Merge pull request #652 from jpcima/color-conversions
Color the key ranges
This commit is contained in:
commit
5d657e60e8
9 changed files with 293 additions and 9 deletions
|
|
@ -56,6 +56,7 @@ The sfizz library also uses in some subprojects:
|
|||
- [cxxopts] by Jarryd Beck, licensed under the MIT license
|
||||
- [fmidi] by Jean Pierre Cimalando, licensed under the Boost Software License 1.0
|
||||
- [libsamplerate], licensed under the BSD 2-Clause license
|
||||
- [GLSL-Color-Spaces] by tobspr, licensed under the MIT license
|
||||
|
||||
[Abseil]: https://abseil.io/
|
||||
[atomic_queue]: https://github.com/max0x7ba/atomic_queue
|
||||
|
|
@ -74,6 +75,7 @@ The sfizz library also uses in some subprojects:
|
|||
[libsamplerate]: http://www.mega-nerd.com/SRC/
|
||||
[libsndfile]: http://www.mega-nerd.com/libsndfile/
|
||||
[LV2]: https://lv2plug.in/
|
||||
[GLSL-Color-Spaces]: https://github.com/tobspr/GLSL-Color-Spaces
|
||||
[our website]: https://sfz.tools/sfizz
|
||||
[releases]: https://github.com/sfztools/sfizz/releases
|
||||
[Carla]: https://kx.studio/Applications:Carla
|
||||
|
|
|
|||
|
|
@ -36,6 +36,8 @@ add_library(sfizz_editor STATIC EXCLUDE_FROM_ALL
|
|||
src/editor/GUIComponents.cpp
|
||||
src/editor/GUIPiano.h
|
||||
src/editor/GUIPiano.cpp
|
||||
src/editor/ColorHelpers.h
|
||||
src/editor/ColorHelpers.cpp
|
||||
src/editor/NativeHelpers.h
|
||||
src/editor/NativeHelpers.cpp
|
||||
src/editor/layout/main.hpp
|
||||
|
|
@ -59,6 +61,10 @@ if(APPLE)
|
|||
endif()
|
||||
|
||||
# dependencies
|
||||
add_library(sfizz_colorspaces INTERFACE)
|
||||
add_library(sfizz::colorspaces ALIAS sfizz_colorspaces)
|
||||
target_include_directories(sfizz_colorspaces INTERFACE "external/color-spaces")
|
||||
|
||||
if(WIN32)
|
||||
#
|
||||
elseif(APPLE)
|
||||
|
|
@ -69,7 +75,7 @@ else()
|
|||
target_include_directories(sfizz_editor PRIVATE ${sfizz-gio_INCLUDE_DIRS})
|
||||
target_link_libraries(sfizz_editor PRIVATE ${sfizz-gio_LIBRARIES})
|
||||
endif()
|
||||
target_link_libraries(sfizz_editor PRIVATE sfizz::bit_array sfizz::filesystem)
|
||||
target_link_libraries(sfizz_editor PRIVATE sfizz::colorspaces sfizz::bit_array sfizz::filesystem)
|
||||
|
||||
# layout tool
|
||||
if(NOT CMAKE_CROSSCOMPILING)
|
||||
|
|
|
|||
129
plugins/editor/external/color-spaces/ColorSpaces.h
vendored
Normal file
129
plugins/editor/external/color-spaces/ColorSpaces.h
vendored
Normal file
|
|
@ -0,0 +1,129 @@
|
|||
// SPDX-License-Identifier: MIT
|
||||
/*
|
||||
GLSL Color Space Utility Functions
|
||||
(c) 2015 tobspr
|
||||
|
||||
Porting a subset to C++
|
||||
(c) 2020 Jean Pierre Cimalando
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2015
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
Most formulars / matrices are from:
|
||||
https://en.wikipedia.org/wiki/SRGB
|
||||
|
||||
Some are from:
|
||||
http://www.chilliant.com/rgb2hsv.html
|
||||
https://www.fourcc.org/fccyvrgb.php
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include <array>
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
|
||||
namespace ColorSpaces {
|
||||
|
||||
template <std::size_t N> using vec = std::array<float, N>;
|
||||
using vec3 = vec<3>;
|
||||
using vec4 = vec<4>;
|
||||
|
||||
template <class T>
|
||||
T clamp(T x, T lo, T hi)
|
||||
{
|
||||
return std::max(lo, std::min(hi, x));
|
||||
}
|
||||
|
||||
template <std::size_t N>
|
||||
vec<N> saturate(vec<N> x)
|
||||
{
|
||||
for (std::size_t i = 0; i < N; ++i)
|
||||
x[i] = clamp(x[i], 0.0f, 1.0f);
|
||||
return x;
|
||||
}
|
||||
|
||||
float dot(vec3 a, vec3 b)
|
||||
{
|
||||
return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
|
||||
}
|
||||
|
||||
// Constants
|
||||
static constexpr float HCV_EPSILON = 1e-10;
|
||||
static constexpr float HCY_EPSILON = 1e-10;
|
||||
|
||||
// Converts a value from linear RGB to HCV (Hue, Chroma, Value)
|
||||
vec3 rgb_to_hcv(vec3 rgb)
|
||||
{
|
||||
// Based on work by Sam Hocevar and Emil Persson
|
||||
vec4 P = (rgb[1] < rgb[2]) ? vec4{{rgb[2], rgb[1], -1.0, 2.0/3.0}} : vec4{{rgb[1], rgb[2], 0.0, -1.0/3.0}};
|
||||
vec4 Q = (rgb[0] < P[0]) ? vec4{{P[0], P[1], P[3], rgb[0]}} : vec4{{rgb[0], P[1], P[2], P[0]}};
|
||||
float C = Q[0] - std::min(Q[3], Q[1]);
|
||||
float H = std::abs((Q[3] - Q[1]) / (6 * C + HCV_EPSILON) + Q[2]);
|
||||
return vec3{{H, C, Q[0]}};
|
||||
}
|
||||
|
||||
// Converts from pure Hue to linear RGB
|
||||
vec3 hue_to_rgb(float hue)
|
||||
{
|
||||
float R = std::fabs(hue * 6 - 3) - 1;
|
||||
float G = 2 - std::fabs(hue * 6 - 2);
|
||||
float B = 2 - std::fabs(hue * 6 - 4);
|
||||
return saturate(vec3{{R,G,B}});
|
||||
}
|
||||
|
||||
// Converts from HCY to linear RGB
|
||||
vec3 hcy_to_rgb(vec3 hcy)
|
||||
{
|
||||
const vec3 HCYwts{{0.299, 0.587, 0.114}};
|
||||
vec3 RGB = hue_to_rgb(hcy[0]);
|
||||
float Z = dot(RGB, HCYwts);
|
||||
if (hcy[2] < Z) {
|
||||
hcy[1] *= hcy[2] / Z;
|
||||
} else if (Z < 1) {
|
||||
hcy[1] *= (1 - hcy[2]) / (1 - Z);
|
||||
}
|
||||
return vec3{{(RGB[0] - Z) * hcy[1] + hcy[2],
|
||||
(RGB[1] - Z) * hcy[1] + hcy[2],
|
||||
(RGB[2] - Z) * hcy[1] + hcy[2]}};
|
||||
}
|
||||
|
||||
// Converts from rgb to hcy (Hue, Chroma, Luminance)
|
||||
vec3 rgb_to_hcy(vec3 rgb)
|
||||
{
|
||||
const vec3 HCYwts = vec3{{0.299, 0.587, 0.114}};
|
||||
// Corrected by David Schaeffer
|
||||
vec3 HCV = rgb_to_hcv(rgb);
|
||||
float Y = dot(rgb, HCYwts);
|
||||
float Z = dot(hue_to_rgb(HCV[0]), HCYwts);
|
||||
if (Y < Z) {
|
||||
HCV[1] *= Z / (HCY_EPSILON + Y);
|
||||
} else {
|
||||
HCV[1] *= (1 - Z) / (HCY_EPSILON + 1 - Y);
|
||||
}
|
||||
return vec3{{HCV[0], HCV[1], Y}};
|
||||
}
|
||||
|
||||
} // namespace ColorSpaces
|
||||
22
plugins/editor/external/color-spaces/LICENSE
vendored
Normal file
22
plugins/editor/external/color-spaces/LICENSE
vendored
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2015
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
46
plugins/editor/src/editor/ColorHelpers.cpp
Normal file
46
plugins/editor/src/editor/ColorHelpers.cpp
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
// 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 "ColorHelpers.h"
|
||||
#include <ColorSpaces.h>
|
||||
|
||||
SColorRGB::SColorRGB(const CColor &cc)
|
||||
{
|
||||
r = cc.normRed<float>();
|
||||
g = cc.normGreen<float>();
|
||||
b = cc.normBlue<float>();
|
||||
a = cc.normAlpha<float>();
|
||||
}
|
||||
|
||||
SColorRGB::SColorRGB(const SColorHCY &hcy)
|
||||
{
|
||||
ColorSpaces::vec3 vhcy{{hcy.h, hcy.c, hcy.y}};
|
||||
ColorSpaces::vec3 vrgb = ColorSpaces::hcy_to_rgb(vhcy);
|
||||
r = vrgb[0];
|
||||
g = vrgb[1];
|
||||
b = vrgb[2];
|
||||
a = hcy.a;
|
||||
}
|
||||
|
||||
CColor SColorRGB::toColor() const
|
||||
{
|
||||
CColor cc;
|
||||
cc.setNormRed(r);
|
||||
cc.setNormGreen(g);
|
||||
cc.setNormBlue(b);
|
||||
cc.setNormAlpha(a);
|
||||
return cc;
|
||||
}
|
||||
|
||||
SColorHCY::SColorHCY(const SColorRGB &rgb)
|
||||
{
|
||||
ColorSpaces::vec3 vrgb{{rgb.r, rgb.g, rgb.b}};
|
||||
ColorSpaces::vec3 vhcy = ColorSpaces::rgb_to_hcy(vrgb);
|
||||
h = vhcy[0];
|
||||
c = vhcy[1];
|
||||
y = vhcy[2];
|
||||
a = rgb.a;
|
||||
}
|
||||
33
plugins/editor/src/editor/ColorHelpers.h
Normal file
33
plugins/editor/src/editor/ColorHelpers.h
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
// 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 "vstgui/lib/ccolor.h"
|
||||
|
||||
using namespace VSTGUI;
|
||||
|
||||
struct SColorRGB;
|
||||
struct SColorHCY;
|
||||
|
||||
struct SColorRGB {
|
||||
SColorRGB() = default;
|
||||
explicit SColorRGB(const CColor &cc);
|
||||
explicit SColorRGB(const SColorHCY &hcy);
|
||||
SColorRGB(float r, float g, float b, float a = 1.0) : r(r), g(g), b(b), a(a) {}
|
||||
CColor toColor() const;
|
||||
|
||||
float r {}, g {}, b {}, a { 1.0 };
|
||||
};
|
||||
|
||||
struct SColorHCY {
|
||||
SColorHCY() = default;
|
||||
explicit SColorHCY(const CColor &cc) : SColorHCY(SColorRGB(cc)) {}
|
||||
explicit SColorHCY(const SColorRGB &rgb);
|
||||
SColorHCY(float h, float c, float y, float a = 1.0) : h(h), c(c), y(y), a(a) {}
|
||||
CColor toColor() const { return SColorRGB(*this).toColor(); }
|
||||
|
||||
float h {}, c {}, y {}, a { 1.0 };
|
||||
};
|
||||
|
|
@ -164,6 +164,7 @@ struct Editor::Impl : EditorController::Receiver, IControlListener {
|
|||
void updateTuningFrequencyLabel(float tuningFrequency);
|
||||
void updateStretchedTuningLabel(float stretchedTuning);
|
||||
|
||||
void updateKeyUsed(unsigned key, bool used);
|
||||
void updateCCUsed(unsigned cc, bool used);
|
||||
void updateCCValue(unsigned cc, float value);
|
||||
void updateCCDefaultValue(unsigned cc, float value);
|
||||
|
|
@ -394,7 +395,12 @@ void Editor::Impl::uiReceiveMessage(const char* path, const char* sig, const sfi
|
|||
unsigned indices[8];
|
||||
|
||||
if (Messages::matchOSC("/key/slots", path, indices) && !strcmp(sig, "b")) {
|
||||
// TODO(jpc) key ranges
|
||||
size_t numBits = 8 * args[0].b->size;
|
||||
ConstBitSpan bits { args[0].b->data, numBits };
|
||||
for (unsigned key = 0; key < 128; ++key) {
|
||||
bool used = key < numBits && bits.test(key);
|
||||
updateKeyUsed(key, used);
|
||||
}
|
||||
}
|
||||
else if (Messages::matchOSC("/cc/slots", path, indices) && !strcmp(sig, "b")) {
|
||||
size_t numBits = 8 * args[0].b->size;
|
||||
|
|
@ -1274,6 +1280,12 @@ void Editor::Impl::updateStretchedTuningLabel(float stretchedTuning)
|
|||
label->setText(text);
|
||||
}
|
||||
|
||||
void Editor::Impl::updateKeyUsed(unsigned key, bool used)
|
||||
{
|
||||
if (SPiano* piano = piano_)
|
||||
piano->setKeyUsed(key, used);
|
||||
}
|
||||
|
||||
void Editor::Impl::updateCCUsed(unsigned cc, bool used)
|
||||
{
|
||||
if (SControlsPanel* panel = controlsPanel_)
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz
|
||||
|
||||
#include "GUIPiano.h"
|
||||
#include "ColorHelpers.h"
|
||||
#include "utility/vstgui_before.h"
|
||||
#include "vstgui/lib/cdrawcontext.h"
|
||||
#include "vstgui/lib/cgraphicspath.h"
|
||||
|
|
@ -37,11 +38,24 @@ void SPiano::setNumOctaves(unsigned octs)
|
|||
invalid();
|
||||
}
|
||||
|
||||
void SPiano::setKeyUsed(unsigned key, bool used)
|
||||
{
|
||||
if (key >= 128)
|
||||
return;
|
||||
|
||||
if (keyUsed_.test(key) == used)
|
||||
return;
|
||||
|
||||
keyUsed_.set(key, used);
|
||||
invalid();
|
||||
}
|
||||
|
||||
void SPiano::draw(CDrawContext* dc)
|
||||
{
|
||||
const Dimensions dim = getDimensions(false);
|
||||
const unsigned octs = octs_;
|
||||
const unsigned keyCount = octs * 12;
|
||||
const bool allKeysUsed = keyUsed_.all();
|
||||
|
||||
dc->setDrawMode(kAntiAliasing);
|
||||
|
||||
|
|
@ -56,9 +70,17 @@ void SPiano::draw(CDrawContext* dc)
|
|||
for (unsigned key = 0; key < keyCount; ++key) {
|
||||
if (!black[key % 12]) {
|
||||
CRect rect = keyRect(key);
|
||||
CColor keycolor = whiteFill_;
|
||||
|
||||
SColorHCY hcy(keyUsedHue_, 1.0, whiteKeyLuma_);
|
||||
if (!keyUsed_[key] || allKeysUsed) {
|
||||
hcy.y = 1.0;
|
||||
if (keyval_[key])
|
||||
hcy.c = 0.0;
|
||||
}
|
||||
if (keyval_[key])
|
||||
keycolor = pressedFill_;
|
||||
hcy.y = std::max(0.0f, hcy.y - keyLumaPressDelta_);
|
||||
|
||||
CColor keycolor = hcy.toColor();
|
||||
dc->setFillColor(keycolor);
|
||||
dc->drawRect(rect, kDrawFilled);
|
||||
}
|
||||
|
|
@ -76,9 +98,14 @@ void SPiano::draw(CDrawContext* dc)
|
|||
for (unsigned key = 0; key < keyCount; ++key) {
|
||||
if (black[key % 12]) {
|
||||
CRect rect = keyRect(key);
|
||||
CColor keycolor = blackFill_;
|
||||
|
||||
SColorHCY hcy(keyUsedHue_, 1.0, blackKeyLuma_);
|
||||
if (!keyUsed_[key] || allKeysUsed)
|
||||
hcy.c = 0.0;
|
||||
if (keyval_[key])
|
||||
keycolor = pressedFill_;
|
||||
hcy.y = std::max(0.0f, hcy.y - keyLumaPressDelta_);
|
||||
|
||||
CColor keycolor = hcy.toColor();
|
||||
dc->setFillColor(keycolor);
|
||||
dc->drawRect(rect, kDrawFilled);
|
||||
dc->setFrameColor(outline_);
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@
|
|||
#include "utility/vstgui_after.h"
|
||||
#include <functional>
|
||||
#include <vector>
|
||||
#include <bitset>
|
||||
|
||||
using namespace VSTGUI;
|
||||
|
||||
|
|
@ -24,6 +25,8 @@ public:
|
|||
unsigned getNumOctaves() const { return octs_; }
|
||||
void setNumOctaves(unsigned octs);
|
||||
|
||||
void setKeyUsed(unsigned key, bool used);
|
||||
|
||||
std::function<void(unsigned, float)> onKeyPressed;
|
||||
std::function<void(unsigned, float)> onKeyReleased;
|
||||
|
||||
|
|
@ -52,6 +55,7 @@ private:
|
|||
private:
|
||||
unsigned octs_ {};
|
||||
std::vector<unsigned> keyval_;
|
||||
std::bitset<128> keyUsed_;
|
||||
unsigned mousePressedKey_ = ~0u;
|
||||
|
||||
CCoord innerPaddingX_ = 4.0;
|
||||
|
|
@ -60,9 +64,12 @@ private:
|
|||
|
||||
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 };
|
||||
|
||||
float keyUsedHue_ = 0.55;
|
||||
float whiteKeyLuma_ = 0.9;
|
||||
float blackKeyLuma_ = 0.5;
|
||||
float keyLumaPressDelta_ = 0.2;
|
||||
|
||||
CColor outline_ { 0x00, 0x00, 0x00, 0xff };
|
||||
CColor shadeOutline_ { 0x80, 0x80, 0x80, 0xff };
|
||||
CColor labelStroke_ { 0x63, 0x63, 0x63, 0xff };
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue