Merge pull request #665 from jpcima/show-keyswitch

Display the active keyswitch in the editor
This commit is contained in:
JP Cimalando 2021-02-25 10:20:10 +01:00 committed by GitHub
commit 9123f206fc
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 139 additions and 18 deletions

View file

@ -60,9 +60,9 @@ widget_class mainView {open
xywh {195 11 250 31} labelsize 20 align 20 xywh {195 11 250 31} labelsize 20 align 20
class ClickableLabel class ClickableLabel
} }
Fl_Box {} { Fl_Box keyswitchLabel_ {
label {Key switch:} label {Key switch:} selected
xywh {195 44 250 30} labelsize 20 align 20 xywh {195 44 360 30} labelsize 20 align 20
class Label class Label
} }
Fl_Box {} { Fl_Box {} {
@ -221,7 +221,7 @@ widget_class mainView {open
class LogicalGroup class LogicalGroup
} { } {
Fl_Group {} { Fl_Group {} {
label Engine open selected label Engine open
xywh {305 135 195 100} box ROUNDED_BOX labelsize 12 align 17 xywh {305 135 195 100} box ROUNDED_BOX labelsize 12 align 17
class TitleGroup class TitleGroup
} { } {

View file

@ -20,6 +20,7 @@
#include <ghc/fs_std.hpp> #include <ghc/fs_std.hpp>
#include <array> #include <array>
#include <queue> #include <queue>
#include <unordered_map>
#include <algorithm> #include <algorithm>
#include <functional> #include <functional>
#include <type_traits> #include <type_traits>
@ -49,6 +50,10 @@ struct Editor::Impl : EditorController::Receiver, IControlListener {
std::string userFilesDir_; std::string userFilesDir_;
std::string fallbackFilesDir_; std::string fallbackFilesDir_;
int currentKeyswitch_ = -1;
std::unordered_map<unsigned, std::string> keyswitchNames_;
std::string keyswitchLabelPrefix_;
SharedPointer<CVSTGUITimer> memQueryTimer_; SharedPointer<CVSTGUITimer> memQueryTimer_;
enum { enum {
@ -102,6 +107,7 @@ struct Editor::Impl : EditorController::Receiver, IControlListener {
CTextLabel* tuningFrequencyLabel_ = nullptr; CTextLabel* tuningFrequencyLabel_ = nullptr;
CControl *stretchedTuningSlider_ = nullptr; CControl *stretchedTuningSlider_ = nullptr;
CTextLabel* stretchedTuningLabel_ = nullptr; CTextLabel* stretchedTuningLabel_ = nullptr;
CTextLabel* keyswitchLabel_ = nullptr;
STitleContainer* userFilesGroup_ = nullptr; STitleContainer* userFilesGroup_ = nullptr;
STextButton* userFilesDirButton_ = nullptr; STextButton* userFilesDirButton_ = nullptr;
@ -170,12 +176,17 @@ struct Editor::Impl : EditorController::Receiver, IControlListener {
void updateTuningFrequencyLabel(float tuningFrequency); void updateTuningFrequencyLabel(float tuningFrequency);
void updateStretchedTuningLabel(float stretchedTuning); void updateStretchedTuningLabel(float stretchedTuning);
absl::string_view getCurrentKeyswitchName() const;
void updateKeyswitchNameLabel();
void updateKeyUsed(unsigned key, bool used); void updateKeyUsed(unsigned key, bool used);
void updateKeyswitchUsed(unsigned key, bool used); void updateKeyswitchUsed(unsigned key, bool used);
void updateCCUsed(unsigned cc, bool used); void updateCCUsed(unsigned cc, bool used);
void updateCCValue(unsigned cc, float value); void updateCCValue(unsigned cc, float value);
void updateCCDefaultValue(unsigned cc, float value); void updateCCDefaultValue(unsigned cc, float value);
void updateCCLabel(unsigned cc, const char* label); void updateCCLabel(unsigned cc, const char* label);
void updateSWLastCurrent(int sw);
void updateSWLastLabel(unsigned sw, const char* label);
void updateMemoryUsed(uint64_t mem); void updateMemoryUsed(uint64_t mem);
// edition of CC by UI // edition of CC by UI
@ -237,7 +248,7 @@ void Editor::open(CFrame& frame)
// request the whole Key and CC information // request the whole Key and CC information
impl.sendQueuedOSC("/key/slots", "", nullptr); impl.sendQueuedOSC("/key/slots", "", nullptr);
impl.sendQueuedOSC("/sw/slots", "", nullptr); impl.sendQueuedOSC("/sw/last/slots", "", nullptr);
impl.sendQueuedOSC("/cc/slots", "", nullptr); impl.sendQueuedOSC("/cc/slots", "", nullptr);
} }
@ -268,7 +279,7 @@ void Editor::Impl::uiReceiveValue(EditId id, const EditValue& v)
// request the whole Key and CC information // request the whole Key and CC information
sendQueuedOSC("/key/slots", "", nullptr); sendQueuedOSC("/key/slots", "", nullptr);
sendQueuedOSC("/sw/slots", "", nullptr); sendQueuedOSC("/sw/last/slots", "", nullptr);
sendQueuedOSC("/cc/slots", "", nullptr); sendQueuedOSC("/cc/slots", "", nullptr);
} }
break; break;
@ -430,13 +441,19 @@ void Editor::Impl::uiReceiveMessage(const char* path, const char* sig, const sfi
updateKeyUsed(key, used); updateKeyUsed(key, used);
} }
} }
else if (Messages::matchOSC("/sw/slots", path, indices) && !strcmp(sig, "b")) { else if (Messages::matchOSC("/sw/last/slots", path, indices) && !strcmp(sig, "b")) {
size_t numBits = 8 * args[0].b->size; size_t numBits = 8 * args[0].b->size;
ConstBitSpan bits { args[0].b->data, numBits }; ConstBitSpan bits { args[0].b->data, numBits };
for (unsigned key = 0; key < 128; ++key) { for (unsigned key = 0; key < 128; ++key) {
bool used = key < numBits && bits.test(key); bool used = key < numBits && bits.test(key);
updateKeyswitchUsed(key, used); updateKeyswitchUsed(key, used);
if (used) {
char pathBuf[256];
sprintf(pathBuf, "/sw/last/%u/label", key);
sendQueuedOSC(pathBuf, "", nullptr);
}
} }
sendQueuedOSC("/sw/last/current", "", nullptr);
} }
else if (Messages::matchOSC("/cc/slots", path, indices) && !strcmp(sig, "b")) { else if (Messages::matchOSC("/cc/slots", path, indices) && !strcmp(sig, "b")) {
size_t numBits = 8 * args[0].b->size; size_t numBits = 8 * args[0].b->size;
@ -476,6 +493,12 @@ void Editor::Impl::uiReceiveMessage(const char* path, const char* sig, const sfi
else if (Messages::matchOSC("/cc&/label", path, indices) && !strcmp(sig, "s")) { else if (Messages::matchOSC("/cc&/label", path, indices) && !strcmp(sig, "s")) {
updateCCLabel(indices[0], args[0].s); updateCCLabel(indices[0], args[0].s);
} }
else if (Messages::matchOSC("/sw/last/current", path, indices) && !strcmp(sig, "i")) {
updateSWLastCurrent(args[0].i);
}
else if (Messages::matchOSC("/sw/last/&/label", path, indices) && !strcmp(sig, "s")) {
updateSWLastLabel(indices[0], args[0].s);
}
else if (Messages::matchOSC("/mem/buffers", path, indices) && !strcmp(sig, "h")) { else if (Messages::matchOSC("/mem/buffers", path, indices) && !strcmp(sig, "h")) {
updateMemoryUsed(args[0].h); updateMemoryUsed(args[0].h);
} }
@ -808,6 +831,10 @@ void Editor::Impl::createFrameContents()
mainView_ = owned(mainView); mainView_ = owned(mainView);
} }
///
if (keyswitchLabel_)
keyswitchLabelPrefix_ = std::string(keyswitchLabel_->getText()) + ' ';
/// ///
SharedPointer<SFileDropTarget> fileDropTarget = owned(new SFileDropTarget); SharedPointer<SFileDropTarget> fileDropTarget = owned(new SFileDropTarget);
@ -1033,7 +1060,7 @@ void Editor::Impl::changeSfzFile(const std::string& filePath)
// request the whole Key and CC information // request the whole Key and CC information
sendQueuedOSC("/key/slots", "", nullptr); sendQueuedOSC("/key/slots", "", nullptr);
sendQueuedOSC("/sw/slots", "", nullptr); sendQueuedOSC("/sw/last/slots", "", nullptr);
sendQueuedOSC("/cc/slots", "", nullptr); sendQueuedOSC("/cc/slots", "", nullptr);
} }
@ -1347,6 +1374,27 @@ void Editor::Impl::updateStretchedTuningLabel(float stretchedTuning)
label->setText(text); label->setText(text);
} }
absl::string_view Editor::Impl::getCurrentKeyswitchName() const
{
int sw = currentKeyswitch_;
if (sw == -1)
return {};
auto it = keyswitchNames_.find(static_cast<unsigned>(sw));
if (it == keyswitchNames_.end())
return {};
return it->second;
}
void Editor::Impl::updateKeyswitchNameLabel()
{
if (CTextLabel* label = keyswitchLabel_) {
std::string name { getCurrentKeyswitchName() };
label->setText((keyswitchLabelPrefix_ + name).c_str());
}
}
void Editor::Impl::updateKeyUsed(unsigned key, bool used) void Editor::Impl::updateKeyUsed(unsigned key, bool used)
{ {
if (SPiano* piano = piano_) if (SPiano* piano = piano_)
@ -1383,6 +1431,21 @@ void Editor::Impl::updateCCLabel(unsigned cc, const char* label)
panel->setControlLabelText(cc, label); panel->setControlLabelText(cc, label);
} }
void Editor::Impl::updateSWLastCurrent(int sw)
{
if (currentKeyswitch_ == sw)
return;
currentKeyswitch_ = sw;
updateKeyswitchNameLabel();
}
void Editor::Impl::updateSWLastLabel(unsigned sw, const char* label)
{
keyswitchNames_[sw].assign(label);
if ((unsigned)currentKeyswitch_ == sw)
updateKeyswitchNameLabel();
}
void Editor::Impl::updateMemoryUsed(uint64_t mem) void Editor::Impl::updateMemoryUsed(uint64_t mem)
{ {
if (CTextLabel* label = memoryLabel_) { if (CTextLabel* label = memoryLabel_) {

View file

@ -25,7 +25,8 @@ view__8->addView(view__10);
auto* const view__11 = createClickableLabel(CRect(10, 6, 260, 37), kTagLoadSfzFile, "DefaultInstrument.sfz", kLeftText, 20); auto* const view__11 = createClickableLabel(CRect(10, 6, 260, 37), kTagLoadSfzFile, "DefaultInstrument.sfz", kLeftText, 20);
sfzFileLabel_ = view__11; sfzFileLabel_ = view__11;
view__8->addView(view__11); view__8->addView(view__11);
auto* const view__12 = createLabel(CRect(10, 39, 260, 69), -1, "Key switch:", kLeftText, 20); auto* const view__12 = createLabel(CRect(10, 39, 370, 69), -1, "Key switch:", kLeftText, 20);
keyswitchLabel_ = view__12;
view__8->addView(view__12); view__8->addView(view__12);
auto* const view__13 = createLabel(CRect(10, 71, 70, 96), -1, "Voices:", kRightText, 12); auto* const view__13 = createLabel(CRect(10, 71, 70, 96), -1, "Voices:", kRightText, 12);
view__8->addView(view__13); view__8->addView(view__13);

View file

@ -241,6 +241,7 @@ void Synth::Impl::clear()
numGroups_ = 0; numGroups_ = 0;
numMasters_ = 0; numMasters_ = 0;
currentSwitch_ = absl::nullopt; currentSwitch_ = absl::nullopt;
currentSwitchChanged_ = true;
defaultPath_ = ""; defaultPath_ = "";
resources_.midiState.reset(); resources_.midiState.reset();
resources_.filePool.clear(); resources_.filePool.clear();
@ -250,8 +251,8 @@ void Synth::Impl::clear()
changedCCsThisCycle_.clear(); changedCCsThisCycle_.clear();
keyLabels_.clear(); keyLabels_.clear();
keySlots_.clear(); keySlots_.clear();
swSlots_.clear(); swLastSlots_.clear();
keyswitchLabels_.clear(); clearKeyswitchLabels();
globalOpcodes_.clear(); globalOpcodes_.clear();
masterOpcodes_.clear(); masterOpcodes_.clear();
groupOpcodes_.clear(); groupOpcodes_.clear();
@ -623,7 +624,7 @@ void Synth::Impl::finalizeSfzLoad()
region->keySwitched = (*currentSwitch_ == *region->lastKeyswitch); region->keySwitched = (*currentSwitch_ == *region->lastKeyswitch);
if (region->keyswitchLabel) if (region->keyswitchLabel)
insertPairUniquely(keyswitchLabels_, *region->lastKeyswitch, *region->keyswitchLabel); setKeyswitchLabel(*region->lastKeyswitch, *region->keyswitchLabel);
} }
if (region->lastKeyswitchRange) { if (region->lastKeyswitchRange) {
@ -633,7 +634,7 @@ void Synth::Impl::finalizeSfzLoad()
if (region->keyswitchLabel) { if (region->keyswitchLabel) {
for (uint8_t note = range.getStart(), end = range.getEnd(); note <= end; note++) for (uint8_t note = range.getStart(), end = range.getEnd(); note <= end; note++)
insertPairUniquely(keyswitchLabels_, note, *region->keyswitchLabel); setKeyswitchLabel(note, *region->keyswitchLabel);
} }
} }
@ -749,15 +750,17 @@ void Synth::Impl::finalizeSfzLoad()
// cache the set of keyswitches assigned // cache the set of keyswitches assigned
for (const RegionPtr& regionPtr : regions_) { for (const RegionPtr& regionPtr : regions_) {
if (absl::optional<uint8_t> sw = regionPtr->lastKeyswitch) { if (absl::optional<uint8_t> sw = regionPtr->lastKeyswitch) {
swSlots_.set(*sw); swLastSlots_.set(*sw);
} }
else if (absl::optional<Range<uint8_t>> swRange = regionPtr->lastKeyswitchRange) { else if (absl::optional<Range<uint8_t>> swRange = regionPtr->lastKeyswitchRange) {
unsigned loKey = swRange->getStart(); unsigned loKey = swRange->getStart();
unsigned hiKey = swRange->getEnd(); unsigned hiKey = swRange->getEnd();
for (unsigned key = loKey; key <= hiKey; ++key) for (unsigned key = loKey; key <= hiKey; ++key)
swSlots_.set(key); swLastSlots_.set(key);
} }
} }
// resend current keyswitch
currentSwitchChanged_ = true;
} }
bool Synth::loadScalaFile(const fs::path& path) bool Synth::loadScalaFile(const fs::path& path)
@ -985,6 +988,16 @@ void Synth::renderBlock(AudioSpan<float> buffer) noexcept
broadcaster.receive<'b'>(numFrames - 1, "/cc/changed", &blob); broadcaster.receive<'b'>(numFrames - 1, "/cc/changed", &blob);
} }
impl.changedCCsThisCycle_.clear(); impl.changedCCsThisCycle_.clear();
// Send the changed keyswitch
if (impl.currentSwitchChanged_) {
if (broadcaster.canReceive()) {
int32_t value = -1;
if (impl.currentSwitch_)
value = *impl.currentSwitch_;
broadcaster.receive<'i'>(numFrames - 1, "/sw/last/current", value);
}
impl.currentSwitchChanged_ = false;
}
{ // Clear events and advance midi time { // Clear events and advance midi time
ScopedTiming logger { impl.dispatchDuration_, ScopedTiming::Operation::addToDuration }; ScopedTiming logger { impl.dispatchDuration_, ScopedTiming::Operation::addToDuration };
@ -1081,6 +1094,7 @@ void Synth::Impl::noteOnDispatch(int delay, int noteNumber, float velocity) noex
region->keySwitched = false; region->keySwitched = false;
} }
currentSwitch_ = noteNumber; currentSwitch_ = noteNumber;
currentSwitchChanged_ = true;
} }
for (auto& region : lastKeyswitchLists_[noteNumber]) for (auto& region : lastKeyswitchLists_[noteNumber])
@ -1869,12 +1883,36 @@ void Synth::Impl::setCCLabel(int ccNumber, std::string name)
} }
} }
const std::string* Synth::Impl::getKeyswitchLabel(int swNumber)
{
auto it = keyswitchLabelsMap_.find(swNumber);
return (it == keyswitchLabelsMap_.end()) ? nullptr : &keyswitchLabels_[it->second].second;
}
void Synth::Impl::setKeyswitchLabel(int swNumber, std::string name)
{
auto it = keyswitchLabelsMap_.find(swNumber);
if (it != keyswitchLabelsMap_.end())
keyswitchLabels_[it->second].second = std::move(name);
else {
size_t index = keyswitchLabels_.size();
keyswitchLabels_.emplace_back(swNumber, std::move(name));
keyswitchLabelsMap_[swNumber] = index;
}
}
void Synth::Impl::clearCCLabels() void Synth::Impl::clearCCLabels()
{ {
ccLabels_.clear(); ccLabels_.clear();
ccLabelsMap_.clear(); ccLabelsMap_.clear();
} }
void Synth::Impl::clearKeyswitchLabels()
{
keyswitchLabels_.clear();
keyswitchLabelsMap_.clear();
}
Parser& Synth::getParser() noexcept Parser& Synth::getParser() noexcept
{ {
Impl& impl = *impl_; Impl& impl = *impl_;

View file

@ -46,12 +46,26 @@ void sfz::Synth::dispatchMessage(Client& client, int delay, const char* path, co
//---------------------------------------------------------------------- //----------------------------------------------------------------------
MATCH("/sw/slots", "") { MATCH("/sw/last/slots", "") {
const BitArray<128>& switches = impl.swSlots_; const BitArray<128>& switches = impl.swLastSlots_;
sfizz_blob_t blob { switches.data(), static_cast<uint32_t>(switches.byte_size()) }; sfizz_blob_t blob { switches.data(), static_cast<uint32_t>(switches.byte_size()) };
client.receive<'b'>(delay, path, &blob); client.receive<'b'>(delay, path, &blob);
} break; } break;
MATCH("/sw/last/current", "") {
int32_t value = -1;
if (impl.currentSwitch_)
value = *impl.currentSwitch_;
client.receive<'i'>(delay, path, value);
} break;
MATCH("/sw/last/&/label", "") {
if (indices[0] >= 128)
break;
const std::string* label = impl.getKeyswitchLabel(indices[0]);
client.receive<'s'>(delay, path, label ? label->c_str() : "");
} break;
//---------------------------------------------------------------------- //----------------------------------------------------------------------
MATCH("/cc/slots", "") { MATCH("/cc/slots", "") {

View file

@ -184,6 +184,9 @@ struct Synth::Impl final: public Parser::Listener {
const std::string* getCCLabel(int ccNumber); const std::string* getCCLabel(int ccNumber);
void setCCLabel(int ccNumber, std::string name); void setCCLabel(int ccNumber, std::string name);
void clearCCLabels(); void clearCCLabels();
const std::string* getKeyswitchLabel(int swNumber);
void setKeyswitchLabel(int swNumber, std::string name);
void clearKeyswitchLabels();
/** /**
* @brief Perform a CC event * @brief Perform a CC event
@ -217,11 +220,13 @@ struct Synth::Impl final: public Parser::Listener {
std::map<int, size_t> ccLabelsMap_; std::map<int, size_t> ccLabelsMap_;
std::vector<NoteNamePair> keyLabels_; std::vector<NoteNamePair> keyLabels_;
BitArray<128> keySlots_; BitArray<128> keySlots_;
BitArray<128> swSlots_; BitArray<128> swLastSlots_;
std::vector<NoteNamePair> keyswitchLabels_; std::vector<NoteNamePair> keyswitchLabels_;
std::map<int, size_t> keyswitchLabelsMap_;
// Set as sw_default if present in the file // Set as sw_default if present in the file
absl::optional<uint8_t> currentSwitch_; absl::optional<uint8_t> currentSwitch_;
bool currentSwitchChanged_ = true;
std::vector<std::string> unknownOpcodes_; std::vector<std::string> unknownOpcodes_;
using RegionViewVector = std::vector<Region*>; using RegionViewVector = std::vector<Region*>;
using VoiceViewVector = std::vector<Voice*>; using VoiceViewVector = std::vector<Voice*>;