Update the piano
This commit is contained in:
parent
5cd6a514ae
commit
39a4df017e
8 changed files with 343 additions and 234 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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)))
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
237
editor/src/editor/GUIPiano.cpp
Normal file
237
editor/src/editor/GUIPiano.cpp
Normal file
|
|
@ -0,0 +1,237 @@
|
|||
// 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>
|
||||
|
||||
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(-innerPaddingX_, -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(
|
||||
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,
|
||||
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)));
|
||||
}
|
||||
72
editor/src/editor/GUIPiano.h
Normal file
72
editor/src/editor/GUIPiano.h
Normal 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_;
|
||||
};
|
||||
|
|
@ -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);
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue