Merge pull request #497 from jpcima/editor-improvement

Update the piano
This commit is contained in:
JP Cimalando 2020-10-14 21:06:21 +02:00 committed by GitHub
commit cc9832507f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 410 additions and 239 deletions

View file

@ -34,6 +34,8 @@ add_library(sfizz_editor STATIC EXCLUDE_FROM_ALL
src/editor/EditorController.h
src/editor/GUIComponents.h
src/editor/GUIComponents.cpp
src/editor/GUIPiano.h
src/editor/GUIPiano.cpp
src/editor/NativeHelpers.h
src/editor/NativeHelpers.cpp
src/editor/layout/main.hpp

View file

@ -56,7 +56,7 @@ widget_class mainView {open
}
Fl_Box sfzFileLabel_ {
label {DefaultInstrument.sfz}
comment {tag=kTagLoadSfzFile} selected
comment {tag=kTagLoadSfzFile}
xywh {195 11 250 31} labelsize 20 align 20
class ClickableLabel
}
@ -138,7 +138,7 @@ widget_class mainView {open
}
}
Fl_Group {subPanels_[kPanelGeneral]} {
xywh {5 110 791 285} hide
xywh {5 110 791 285}
class LogicalGroup
} {
Fl_Group {} {open
@ -212,8 +212,8 @@ widget_class mainView {open
}
}
}
Fl_Group {subPanels_[kPanelSettings]} {
xywh {5 109 790 286}
Fl_Group {subPanels_[kPanelSettings]} {open
xywh {5 109 790 286} hide
class LogicalGroup
} {
Fl_Group {} {
@ -305,8 +305,8 @@ widget_class mainView {open
}
}
}
Fl_Box {} {
xywh {5 400 790 70}
Fl_Box piano_ {selected
xywh {5 400 790 70} labelsize 12
class Piano
}
}

View file

@ -8,6 +8,7 @@
#include "EditorController.h"
#include "EditIds.h"
#include "GUIComponents.h"
#include "GUIPiano.h"
#include "NativeHelpers.h"
#include <absl/strings/string_view.h>
#include <absl/strings/match.h>
@ -96,6 +97,8 @@ struct Editor::Impl : EditorController::Receiver, IControlListener {
SActionMenu* fileOperationsMenu_ = nullptr;
SPiano* piano_ = nullptr;
void uiReceiveValue(EditId id, const EditValue& v) override;
void createFrameContents();
@ -554,8 +557,10 @@ void Editor::Impl::createFrameContents()
auto createNextFileButton = [&createGlyphButton](const CRect& bounds, int tag, const char*, CHoriTxtAlign, int fontsize) {
return createGlyphButton(u8"\ue0da", bounds, tag, fontsize);
};
auto createPiano = [](const CRect& bounds, int, const char*, CHoriTxtAlign, int) {
auto createPiano = [](const CRect& bounds, int, const char*, CHoriTxtAlign, int fontsize) {
SPiano* piano = new SPiano(bounds);
auto font = owned(new CFontDesc("Roboto", fontsize));
piano->setFont(font);
return piano;
};
auto createChevronDropDown = [this, &theme](const CRect& bounds, int, const char*, CHoriTxtAlign, int fontsize) {
@ -693,6 +698,23 @@ void Editor::Impl::createFrameContents()
menu->addEntry("Edit file", kTagEditSfzFile);
}
if (SPiano* piano = piano_) {
piano->onKeyPressed = [this](unsigned key, float vel) {
uint8_t msg[3];
msg[0] = 0x90;
msg[1] = static_cast<uint8_t>(key);
msg[2] = static_cast<uint8_t>(std::max(1, static_cast<int>(vel * 127)));
ctrl_->uiSendMIDI(msg, sizeof(msg));
};
piano->onKeyReleased = [this](unsigned key, float vel) {
uint8_t msg[3];
msg[0] = 0x80;
msg[1] = static_cast<uint8_t>(key);
msg[2] = static_cast<uint8_t>(vel * 127);
ctrl_->uiSendMIDI(msg, sizeof(msg));
};
}
///
CViewContainer* panel;
activePanel_ = 0;

View file

@ -154,201 +154,6 @@ bool SFileDropTarget::isFileDrop(IDataPackage* package)
package->getDataType(0) == IDataPackage::kFilePath;
}
///
SPiano::SPiano(const CRect& bounds)
: CView(bounds), font_(kNormalFont)
{
}
void SPiano::setFont(CFontRef font)
{
font_ = font;
invalid();
}
void SPiano::clearKeyRanges()
{
keyInRange_.reset();
}
void SPiano::addKeyRange(int start, int end)
{
start = std::min(127, std::max(0, start));
end = std::min(127, std::max(0, end));
for (int x = start; x <= end; ++x)
keyInRange_.set(x);
}
CCoord SPiano::getKeyWidth()
{
return 6.0;
}
CCoord SPiano::getKeySwitchesHeight()
{
return 20.0;
}
CCoord SPiano::getKeyRangesHeight()
{
return 11.0;
}
CCoord SPiano::getKeysHeight() const
{
return getHeight() -
(getKeySwitchesHeight() + getKeyRangesHeight() + getOctavesHeight());
}
CCoord SPiano::getOctavesHeight() const
{
return font_->getSize();
}
void SPiano::getZoneDimensions(
CRect* pKeySwitches,
CRect* pKeyboard,
CRect* pKeyRanges,
CRect* pOctaves)
{
CRect bounds = getViewSize();
CRect keySwitches(bounds);
keySwitches.setHeight(getKeySwitchesHeight());
CRect keyboard(bounds);
keyboard.top = keySwitches.bottom;
keyboard.setHeight(getKeysHeight());
CRect keyRanges(bounds);
keyRanges.top = keyboard.bottom;
keyRanges.setHeight(getKeyRangesHeight());
CRect octaves(bounds);
octaves.top = keyRanges.bottom;
octaves.setHeight(getOctavesHeight());
// apply some paddings
keySwitches.extend(-2.0, -2.0);
keyboard.extend(-2.0, -2.0);
keyRanges.extend(-2.0, -4.0);
octaves.extend(-2.0, -2.0);
// offsets for centered keyboard
CCoord keyWidth = getKeyWidth();
CCoord offset = std::round((keyboard.getWidth() - (128.0 * keyWidth)) * 0.5);
if (offset > 0) {
keySwitches.extend(-offset, 0.0);
keyboard.extend(-offset, 0.0);
keyRanges.extend(-offset, 0.0);
octaves.extend(-offset, 0.0);
}
//
if (pKeySwitches)
*pKeySwitches = keySwitches;
if (pKeyboard)
*pKeyboard = keyboard;
if (pKeyRanges)
*pKeyRanges = keyRanges;
if (pOctaves)
*pOctaves = octaves;
}
void SPiano::draw(CDrawContext* dc)
{
CRect bounds = getViewSize();
dc->setDrawMode(kAntiAliasing);
SharedPointer<CGraphicsPath> path;
path = owned(dc->createGraphicsPath());
path->addRoundRect(bounds, 5.0);
dc->setFillColor(CColor(0xca, 0xca, 0xca));
dc->drawGraphicsPath(path, CDrawContext::kPathFilled);
//
CRect rectKeySwitches;
CRect rectKeyboard;
CRect rectKeyRanges;
CRect rectOctaves;
getZoneDimensions(&rectKeySwitches, &rectKeyboard, &rectKeyRanges, &rectOctaves);
//
path = owned(dc->createGraphicsPath());
path->addRoundRect(rectKeyboard, 1.0);
dc->setFillColor(CColor(0xff, 0xff, 0xff));
dc->drawGraphicsPath(path, CDrawContext::kPathFilled);
CCoord keyWidth = getKeyWidth();
for (int key = 0; key < 128; ++key) {
CCoord keyX = rectKeyboard.left + key * keyWidth;
int key12 = key % 12;
if (key12 == 1 || key12 == 3 ||
key12 == 6 || key12 == 8 || key12 == 10)
{
CRect blackRect(keyX, rectKeyboard.top + 2, keyX + keyWidth, rectKeyboard.bottom - 2);
path = owned(dc->createGraphicsPath());
path->addRoundRect(blackRect, 1.0);
dc->setFillColor(CColor(0x02, 0x02, 0x02));
dc->drawGraphicsPath(path, CDrawContext::kPathFilled);
}
if (key != 0 && key12 == 0) {
dc->setLineWidth(1.5);
dc->setFrameColor(CColor(0x63, 0x63, 0x63));
dc->drawLine(CPoint(keyX, rectKeyboard.top), CPoint(keyX, rectKeyboard.bottom));
}
if (key12 == 5) {
CCoord pad = rectKeyboard.getHeight() * 0.4;
dc->setLineWidth(1.0);
dc->setFrameColor(CColor(0x63, 0x63, 0x63));
dc->drawLine(CPoint(keyX, rectKeyboard.top + pad), CPoint(keyX, rectKeyboard.bottom - pad));
}
}
//
for (int rangeStart = 0; rangeStart < 128;)
{
if (!keyInRange_[rangeStart]) {
++rangeStart;
}
else {
int rangeEnd = rangeStart;
while (rangeEnd + 1 < 128 && keyInRange_[rangeEnd + 1])
++rangeEnd;
CCoord rangeStartX = rectKeyRanges.left + rangeStart * keyWidth;
CCoord rangeEndX = rectKeyRanges.left + (rangeEnd + 1.0) * keyWidth;
CRect rectRange(rangeStartX, rectKeyRanges.top, rangeEndX, rectKeyRanges.bottom);
path = owned(dc->createGraphicsPath());
path->addRoundRect(rectRange, 2.0);
dc->setFillColor(CColor(0x0f, 0x0f, 0x0f));
dc->drawGraphicsPath(path, CDrawContext::kPathFilled);
rangeStart = rangeEnd + 1;
}
}
//
for (int key = 0; key < 128; ++key) {
CCoord keyX = rectOctaves.left + key * keyWidth;
int key12 = key % 12;
if (key12 == 0) {
CRect textRect(keyX, rectOctaves.top, keyX + 12 * keyWidth, rectOctaves.bottom);
dc->setFont(font_);
dc->setFontColor(CColor(0x63, 0x63, 0x63));
dc->drawString(std::to_string(key / 12 - 1).c_str(), textRect, kLeftText);
}
}
//
}
///
SValueMenu::SValueMenu(const CRect& bounds, IControlListener* listener, int32_t tag)
: CParamDisplay(bounds), menuListener_(owned(new MenuListener(*this)))

View file

@ -82,36 +82,6 @@ private:
FileDropFunction dropFunction_;
};
///
class SPiano : public CView {
public:
explicit SPiano(const CRect& bounds);
CFontRef getFont() const { return font_; }
void setFont(CFontRef font);
void clearKeyRanges();
void addKeyRange(int start, int end);
protected:
static CCoord getKeyWidth();
static CCoord getKeySwitchesHeight();
static CCoord getKeyRangesHeight();
CCoord getKeysHeight() const;
CCoord getOctavesHeight() const;
void getZoneDimensions(
CRect* pKeySwitches,
CRect* pKeyboard,
CRect* pKeyRanges,
CRect* pOctaves);
void draw(CDrawContext* dc) override;
private:
SharedPointer<CFontDesc> font_;
std::bitset<128> keyInRange_;
};
///
class SValueMenu : public CParamDisplay {
public:

View file

@ -0,0 +1,238 @@
// 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 "GUIPiano.h"
#include "utility/vstgui_before.h"
#include "vstgui/lib/cdrawcontext.h"
#include "vstgui/lib/cgraphicspath.h"
#include "utility/vstgui_after.h"
#include <algorithm>
#include <cmath>
static constexpr CCoord keyoffs[12] = {0, 0.6, 1, 1.8, 2, 3,
3.55, 4, 4.7, 5, 5.85, 6};
static constexpr bool black[12] = {0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0};
SPiano::SPiano(CRect bounds)
: CView(bounds)
{
setNumOctaves(10);
}
void SPiano::setFont(CFontRef font)
{
font_ = font;
getDimensions(true);
invalid();
}
void SPiano::setNumOctaves(unsigned octs)
{
keyval_.resize(octs * 12);
octs_ = std::max(1u, octs);
getDimensions(true);
invalid();
}
void SPiano::draw(CDrawContext* dc)
{
const Dimensions dim = getDimensions(false);
const unsigned octs = octs_;
const unsigned keyCount = octs * 12;
dc->setDrawMode(kAntiAliasing);
if (backgroundFill_.alpha > 0) {
SharedPointer<CGraphicsPath> path;
path = owned(dc->createGraphicsPath());
path->addRoundRect(dim.bounds, backgroundRadius_);
dc->setFillColor(CColor(0xca, 0xca, 0xca));
dc->drawGraphicsPath(path, CDrawContext::kPathFilled);
}
for (unsigned key = 0; key < keyCount; ++key) {
if (!black[key % 12]) {
CRect rect = keyRect(key);
CColor keycolor = whiteFill_;
if (keyval_[key])
keycolor = pressedFill_;
dc->setFillColor(keycolor);
dc->drawRect(rect, kDrawFilled);
}
}
dc->setFrameColor(outline_);
dc->drawLine(dim.keyBounds.getTopLeft(), dim.keyBounds.getBottomLeft());
for (unsigned key = 0; key < keyCount; ++key) {
if (!black[key % 12]) {
CRect rect = keyRect(key);
dc->drawLine(rect.getTopRight(), rect.getBottomRight());
}
}
for (unsigned key = 0; key < keyCount; ++key) {
if (black[key % 12]) {
CRect rect = keyRect(key);
CColor keycolor = blackFill_;
if (keyval_[key])
keycolor = pressedFill_;
dc->setFillColor(keycolor);
dc->drawRect(rect, kDrawFilled);
dc->setFrameColor(outline_);
dc->drawRect(rect);
}
}
if (const CFontRef& font = font_) {
for (unsigned o = 0; o < octs; ++o) {
CRect rect = keyRect(o * 12);
CRect textRect(
rect.left, dim.labelBounds.top,
rect.right, dim.labelBounds.bottom);
dc->setFont(font_);
dc->setFontColor(labelStroke_);
std::string text = std::to_string(static_cast<int>(o) - 1);
dc->drawString(text.c_str(), textRect, kCenterText);
}
}
{
dc->setFrameColor(outline_);
dc->drawLine(dim.keyBounds.getTopLeft(), dim.keyBounds.getTopRight());
dc->setFrameColor(shadeOutline_);
dc->drawLine(dim.keyBounds.getBottomLeft(), dim.keyBounds.getBottomRight());
}
dc->setFrameColor(outline_);
}
CMouseEventResult SPiano::onMouseDown(CPoint& where, const CButtonState& buttons)
{
unsigned key = keyAtPos(where);
if (key != ~0u) {
keyval_[key] = 1;
mousePressedKey_ = key;
if (onKeyPressed)
onKeyPressed(key, mousePressVelocity(key, where.y));
invalid();
return kMouseEventHandled;
}
return CView::onMouseDown(where, buttons);
}
CMouseEventResult SPiano::onMouseUp(CPoint& where, const CButtonState& buttons)
{
unsigned key = mousePressedKey_;
if (key != ~0u) {
keyval_[key] = 0;
if (onKeyReleased)
onKeyReleased(key, mousePressVelocity(key, where.y));
mousePressedKey_ = ~0u;
invalid();
return kMouseEventHandled;
}
return CView::onMouseUp(where, buttons);
}
CMouseEventResult SPiano::onMouseMoved(CPoint& where, const CButtonState& buttons)
{
if (mousePressedKey_ != ~0u) {
unsigned key = keyAtPos(where);
if (mousePressedKey_ != key) {
keyval_[mousePressedKey_] = 0;
if (onKeyReleased)
onKeyReleased(mousePressedKey_, mousePressVelocity(key, where.y));
// mousePressedKey_ = ~0u;
if (key != ~0u) {
keyval_[key] = 1;
mousePressedKey_ = key;
if (onKeyPressed)
onKeyPressed(key, mousePressVelocity(key, where.y));
}
invalid();
}
return kMouseEventHandled;
}
return CView::onMouseMoved(where, buttons);
}
const SPiano::Dimensions& SPiano::getDimensions(bool forceUpdate) const
{
if (!forceUpdate && dim_.bounds == getViewSize())
return dim_;
Dimensions dim;
dim.bounds = getViewSize();
dim.paddedBounds = CRect(dim.bounds)
.extend(-2 * innerPaddingX_, -2 * innerPaddingY_);
CCoord keyHeight = std::floor(dim.paddedBounds.getHeight());
CCoord fontHeight = font_ ? font_->getSize() : 0.0;
keyHeight -= spacingY_ + fontHeight;
dim.keyBounds = CRect(dim.paddedBounds)
.setHeight(keyHeight);
dim.keyWidth = static_cast<unsigned>(
dim.paddedBounds.getWidth() / octs_ / 7.0);
dim.keyBounds.setWidth(dim.keyWidth * octs_ * 7.0);
dim.keyBounds.offset(
std::floor(0.5 * (dim.paddedBounds.getWidth() - dim.keyBounds.getWidth())), 0.0);
if (!font_)
dim.labelBounds = CRect();
else
dim.labelBounds = CRect(
dim.keyBounds.left, dim.keyBounds.bottom + spacingY_,
dim.keyBounds.right, dim.keyBounds.bottom + spacingY_ + fontHeight);
dim_ = dim;
return dim_;
}
CRect SPiano::keyRect(const Dimensions& dim, unsigned key)
{
unsigned oct = key / 12;
unsigned note = key % 12;
unsigned keyw = dim.keyWidth;
unsigned keyh = static_cast<unsigned>(dim.keyBounds.getHeight());
CCoord octwidth = (keyoffs[11] + 1.0) * keyw;
CCoord octx = octwidth * oct;
CCoord notex = octx + keyoffs[note] * keyw;
CCoord notew = black[note] ? (0.6 * keyw) : keyw;
CCoord noteh = black[note] ? (0.6 * keyh) : keyh;
return CRect(notex, 0.0, notex + notew, noteh).offset(dim.keyBounds.getTopLeft());
}
CRect SPiano::keyRect(unsigned key) const
{
return keyRect(getDimensions(false), key);
}
unsigned SPiano::keyAtPos(CPoint pos) const
{
const unsigned octs = octs_;
for (unsigned key = 0; key < octs * 12; ++key) {
if (black[key % 12]) {
if (keyRect(key).pointInside(pos))
return key;
}
}
for (unsigned key = 0; key < octs * 12; ++key) {
if (!black[key % 12]) {
if (keyRect(key).pointInside(pos))
return key;
}
}
return ~0u;
}
float SPiano::mousePressVelocity(unsigned key, CCoord posY)
{
const CRect rect = keyRect(key);
CCoord value = (posY - rect.top) / rect.getHeight();
return std::max(0.0f, std::min(1.0f, static_cast<float>(value)));
}

View file

@ -0,0 +1,72 @@
// 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
#pragma once
#include "utility/vstgui_before.h"
#include "vstgui/lib/cview.h"
#include "vstgui/lib/ccolor.h"
#include "utility/vstgui_after.h"
#include <functional>
#include <vector>
using namespace VSTGUI;
class SPiano : public CView {
public:
explicit SPiano(CRect bounds);
CFontRef getFont() const { return font_; }
void setFont(CFontRef font);
unsigned getNumOctaves() const { return octs_; }
void setNumOctaves(unsigned octs);
std::function<void(unsigned, float)> onKeyPressed;
std::function<void(unsigned, float)> onKeyReleased;
protected:
void draw(CDrawContext* dc) override;
CMouseEventResult onMouseDown(CPoint& where, const CButtonState& buttons) override;
CMouseEventResult onMouseUp(CPoint& where, const CButtonState& buttons) override;
CMouseEventResult onMouseMoved(CPoint& where, const CButtonState& buttons) override;
private:
struct Dimensions {
CRect bounds {};
CRect paddedBounds {};
CRect keyBounds {};
unsigned keyWidth {};
CRect labelBounds {};
};
const Dimensions& getDimensions(bool forceUpdate) const;
static CRect keyRect(const Dimensions& dim, unsigned key);
CRect keyRect(unsigned key) const;
unsigned keyAtPos(CPoint pos) const;
float mousePressVelocity(unsigned key, CCoord posY);
private:
unsigned octs_ {};
std::vector<unsigned> keyval_;
unsigned mousePressedKey_ = ~0u;
CCoord innerPaddingX_ = 4.0;
CCoord innerPaddingY_ = 4.0;
CCoord spacingY_ = 4.0;
CColor backgroundFill_ { 0xca, 0xca, 0xca, 0xff };
float backgroundRadius_ = 5.0;
CColor whiteFill_ { 0xee, 0xee, 0xec, 0xff };
CColor blackFill_ { 0x2e, 0x34, 0x36, 0xff };
CColor pressedFill_ { 0xa0, 0xa0, 0xa0, 0xff };
CColor outline_ { 0x00, 0x00, 0x00, 0xff };
CColor shadeOutline_ { 0x80, 0x80, 0x80, 0xff };
CColor labelStroke_ { 0x63, 0x63, 0x63, 0xff };
mutable Dimensions dim_;
SharedPointer<CFontDesc> font_;
};

View file

@ -69,7 +69,6 @@ enterTheme(defaultTheme);
LogicalGroup* const view__28 = createLogicalGroup(CRect(5, 110, 796, 395), -1, "", kCenterText, 14);
subPanels_[kPanelGeneral] = view__28;
view__0->addView(view__28);
view__28->setVisible(false);
RoundedGroup* const view__29 = createRoundedGroup(CRect(0, 0, 175, 280), -1, "", kCenterText, 14);
view__28->addView(view__29);
Label* const view__30 = createLabel(CRect(15, 10, 75, 35), -1, "Curves:", kLeftText, 14);
@ -108,6 +107,7 @@ view__41->addView(view__42);
LogicalGroup* const view__43 = createLogicalGroup(CRect(5, 109, 795, 395), -1, "", kCenterText, 14);
subPanels_[kPanelSettings] = view__43;
view__0->addView(view__43);
view__43->setVisible(false);
TitleGroup* const view__44 = createTitleGroup(CRect(255, 26, 535, 126), -1, "Engine", kCenterText, 12);
view__43->addView(view__44);
ValueMenu* const view__45 = createValueMenu(CRect(25, 60, 85, 85), kTagSetNumVoices, "", kCenterText, 12);
@ -150,5 +150,6 @@ view__51->addView(view__59);
ValueMenu* const view__60 = createValueMenu(CRect(170, 60, 200, 85), kTagSetScalaRootKey, "", kCenterText, 12);
scalaRootOctaveSlider_ = view__60;
view__51->addView(view__60);
Piano* const view__61 = createPiano(CRect(5, 400, 795, 470), -1, "", kCenterText, 14);
Piano* const view__61 = createPiano(CRect(5, 400, 795, 470), -1, "", kCenterText, 12);
piano_ = view__61;
view__0->addView(view__61);

View file

@ -176,10 +176,20 @@ void SfizzVstEditor::uiEndSend(EditId id)
getController()->endEdit(pid);
}
void SfizzVstEditor::uiSendMIDI(const uint8_t* msg, uint32_t len)
void SfizzVstEditor::uiSendMIDI(const uint8_t* data, uint32_t len)
{
// TODO send MIDI...
SfizzVstController* ctl = getController();
Steinberg::OPtr<Vst::IMessage> msg { ctl->allocateMessage() };
if (!msg) {
fprintf(stderr, "[Sfizz] UI could not allocate message\n");
return;
}
msg->setMessageID("MidiMessage");
Vst::IAttributeList* attr = msg->getAttributes();
attr->setBinary("Data", data, len);
ctl->sendMessage(msg);
}
///

View file

@ -40,7 +40,7 @@ protected:
void uiSendValue(EditId id, const EditValue& v) override;
void uiBeginSend(EditId id) override;
void uiEndSend(EditId id) override;
void uiSendMIDI(const uint8_t* msg, uint32_t len) override;
void uiSendMIDI(const uint8_t* data, uint32_t len) override;
private:
void loadSfzFile(const std::string& filePath);

View file

@ -22,8 +22,10 @@ static const char defaultSfzText[] =
"<region>sample=*sine" "\n"
"ampeg_attack=0.02 ampeg_release=0.1" "\n";
enum { kMidiEventMaximumSize = 4 };
SfizzVstProcessor::SfizzVstProcessor()
: _fifoToWorker(64 * 1024)
: _fifoToWorker(64 * 1024), _fifoMidiFromUi(64 * 1024)
{
setControllerClass(SfizzVstController::cid);
}
@ -181,6 +183,8 @@ tresult PLUGIN_API SfizzVstProcessor::process(Vst::ProcessData& data)
else
synth.disableFreeWheeling();
processMidiFromUi();
if (Vst::IParameterChanges* pc = data.inputParameterChanges)
processControllerChanges(*pc);
@ -373,6 +377,40 @@ void SfizzVstProcessor::processEvents(Vst::IEventList& events)
}
}
void SfizzVstProcessor::processMidiFromUi()
{
sfz::Sfizz& synth = *_synth;
for (uint32 size = 0; _fifoMidiFromUi.peek(size) &&
_fifoMidiFromUi.size_used() >= sizeof(size) + size; ) {
_fifoMidiFromUi.discard(sizeof(size));
if (size > kMidiEventMaximumSize) {
_fifoMidiFromUi.discard(size);
continue;
}
uint8_t data[kMidiEventMaximumSize] = {};
_fifoMidiFromUi.get(data, size);
// interpret the MIDI message
switch (data[0] & 0xf0) {
case 0x80:
synth.noteOff(0, data[1] & 0x7f, data[2] & 0x7f);
break;
case 0x90:
synth.noteOn(0, data[1] & 0x7f, data[2] & 0x7f);
break;
case 0xb0:
synth.cc(0, data[1] & 0x7f, data[2] & 0x7f);
break;
case 0xe0:
synth.pitchWheel(0, (data[2] << 7) + data[1] - 8192);
break;
}
}
}
int SfizzVstProcessor::convertVelocityFromFloat(float x)
{
return std::min(127, std::max(0, (int)(x * 127.0f)));
@ -425,6 +463,17 @@ tresult PLUGIN_API SfizzVstProcessor::notify(Vst::IMessage* message)
reply->getAttributes()->setBinary("File", _state.scalaFile.data(), _state.scalaFile.size());
sendMessage(reply);
}
else if (!std::strcmp(id, "MidiMessage")) {
const void* data = nullptr;
uint32 size = 0;
result = attr->getBinary("Data", data, size);
if (size < kMidiEventMaximumSize) {
if (_fifoMidiFromUi.size_free() >= sizeof(size) + size) {
_fifoMidiFromUi.put(size);
_fifoMidiFromUi.put(reinterpret_cast<const uint8_t*>(data), size);
}
}
}
return result;
}

View file

@ -35,6 +35,7 @@ public:
void processParameterChanges(Vst::IParameterChanges& pc);
void processControllerChanges(Vst::IParameterChanges& pc);
void processEvents(Vst::IEventList& events);
void processMidiFromUi();
static int convertVelocityFromFloat(float x);
tresult PLUGIN_API notify(Vst::IMessage* message) override;
@ -58,6 +59,7 @@ private:
volatile bool _workRunning = false;
Ring_Buffer _fifoToWorker;
RTSemaphore _semaToWorker;
Ring_Buffer _fifoMidiFromUi;
std::mutex _processMutex;
// file modification periodic checker