1338 lines
48 KiB
C++
1338 lines
48 KiB
C++
// 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 "SynthPrivate.h"
|
|
#include "StringViewHelpers.h"
|
|
#include <absl/strings/ascii.h>
|
|
#include <cstring>
|
|
|
|
// TODO: `ccModDepth` and `ccModParameters` are O(N), need better implementation
|
|
|
|
namespace sfz {
|
|
static constexpr unsigned maxIndices = 8;
|
|
|
|
static bool extractMessage(const char* pattern, const char* path, unsigned* indices);
|
|
static uint64_t hashMessagePath(const char* path, const char* sig);
|
|
|
|
void sfz::Synth::dispatchMessage(Client& client, int delay, const char* path, const char* sig, const sfizz_arg_t* args)
|
|
{
|
|
UNUSED(args);
|
|
Impl& impl = *impl_;
|
|
unsigned indices[maxIndices];
|
|
|
|
switch (hashMessagePath(path, sig)) {
|
|
#define MATCH(p, s) case hash(p "," s): \
|
|
if (extractMessage(p, path, indices) && !strcmp(sig, s))
|
|
|
|
#define GET_REGION_OR_BREAK(idx) \
|
|
if (idx >= impl.regions_.size()) \
|
|
break; \
|
|
const auto& region = *impl.regions_[idx];
|
|
|
|
MATCH("/hello", "") {
|
|
client.receive(delay, "/hello", "", nullptr);
|
|
} break;
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
MATCH("/key/slots", "") {
|
|
const BitArray<128>& keys = impl.keySlots_;
|
|
sfizz_blob_t blob { keys.data(), static_cast<uint32_t>(keys.byte_size()) };
|
|
client.receive<'b'>(delay, path, &blob);
|
|
} break;
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
MATCH("/sw/last/slots", "") {
|
|
const BitArray<128>& switches = impl.swLastSlots_;
|
|
sfizz_blob_t blob { switches.data(), static_cast<uint32_t>(switches.byte_size()) };
|
|
client.receive<'b'>(delay, path, &blob);
|
|
} 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", "") {
|
|
const BitArray<config::numCCs>& ccs = impl.currentUsedCCs_;
|
|
sfizz_blob_t blob { ccs.data(), static_cast<uint32_t>(ccs.byte_size()) };
|
|
client.receive<'b'>(delay, path, &blob);
|
|
} break;
|
|
|
|
MATCH("/cc&/default", "") {
|
|
if (indices[0] >= config::numCCs)
|
|
break;
|
|
client.receive<'f'>(delay, path, impl.defaultCCValues_[indices[0]]);
|
|
} break;
|
|
|
|
MATCH("/cc&/value", "") {
|
|
if (indices[0] >= config::numCCs)
|
|
break;
|
|
// Note: result value is not frame-exact
|
|
client.receive<'f'>(delay, path, impl.resources_.midiState.getCCValue(indices[0]));
|
|
} break;
|
|
|
|
MATCH("/cc&/value", "f") {
|
|
if (indices[0] >= config::numCCs)
|
|
break;
|
|
impl.resources_.midiState.ccEvent(delay, indices[0], args[0].f);
|
|
} break;
|
|
|
|
MATCH("/cc&/label", "") {
|
|
if (indices[0] >= config::numCCs)
|
|
break;
|
|
const std::string* label = impl.getCCLabel(indices[0]);
|
|
client.receive<'s'>(delay, path, label ? label->c_str() : "");
|
|
} break;
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
MATCH("/mem/buffers", "") {
|
|
uint64_t total = BufferCounter::counter().getTotalBytes();
|
|
client.receive<'h'>(delay, path, total);
|
|
} break;
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
MATCH("/region&/delay", "") {
|
|
GET_REGION_OR_BREAK(indices[0])
|
|
client.receive<'f'>(delay, path, region.delay);
|
|
} break;
|
|
|
|
MATCH("/region&/sample", "") {
|
|
GET_REGION_OR_BREAK(indices[0])
|
|
client.receive<'s'>(delay, path, region.sampleId->filename().c_str());
|
|
} break;
|
|
|
|
MATCH("/region&/direction", "") {
|
|
GET_REGION_OR_BREAK(indices[0])
|
|
if (region.sampleId->isReverse())
|
|
client.receive<'s'>(delay, path, "reverse");
|
|
else
|
|
client.receive<'s'>(delay, path, "forward");
|
|
} break;
|
|
|
|
MATCH("/region&/delay_random", "") {
|
|
GET_REGION_OR_BREAK(indices[0])
|
|
client.receive<'f'>(delay, path, region.delayRandom);
|
|
} break;
|
|
|
|
MATCH("/region&/delay_cc&", "") {
|
|
GET_REGION_OR_BREAK(indices[0])
|
|
client.receive<'f'>(delay, path, region.delayCC.getWithDefault(indices[1]));
|
|
} break;
|
|
|
|
MATCH("/region&/offset", "") {
|
|
GET_REGION_OR_BREAK(indices[0])
|
|
client.receive<'h'>(delay, path, region.offset);
|
|
} break;
|
|
|
|
MATCH("/region&/offset_random", "") {
|
|
GET_REGION_OR_BREAK(indices[0])
|
|
client.receive<'h'>(delay, path, region.offsetRandom);
|
|
} break;
|
|
|
|
MATCH("/region&/offset_cc&", "") {
|
|
GET_REGION_OR_BREAK(indices[0])
|
|
client.receive<'h'>(delay, path, region.offsetCC.getWithDefault(indices[1]));
|
|
} break;
|
|
|
|
MATCH("/region&/end", "") {
|
|
GET_REGION_OR_BREAK(indices[0])
|
|
client.receive<'h'>(delay, path, region.sampleEnd);
|
|
} break;
|
|
|
|
MATCH("/region&/enabled", "") {
|
|
GET_REGION_OR_BREAK(indices[0])
|
|
if (region.disabled()) {
|
|
client.receive<'F'>(delay, path, {});
|
|
} else {
|
|
client.receive<'T'>(delay, path, {});
|
|
}
|
|
} break;
|
|
|
|
MATCH("/region&/trigger_on_note", "") {
|
|
GET_REGION_OR_BREAK(indices[0])
|
|
if (region.triggerOnNote) {
|
|
client.receive<'T'>(delay, path, {});
|
|
} else {
|
|
client.receive<'F'>(delay, path, {});
|
|
}
|
|
} break;
|
|
|
|
MATCH("/region&/trigger_on_cc", "") {
|
|
GET_REGION_OR_BREAK(indices[0])
|
|
if (region.triggerOnCC) {
|
|
client.receive<'T'>(delay, path, {});
|
|
} else {
|
|
client.receive<'F'>(delay, path, {});
|
|
}
|
|
} break;
|
|
|
|
MATCH("/region&/count", "") {
|
|
GET_REGION_OR_BREAK(indices[0])
|
|
if (region.sampleCount)
|
|
client.receive<'h'>(delay, path, *region.sampleCount);
|
|
} break;
|
|
|
|
MATCH("/region&/loop_range", "") {
|
|
GET_REGION_OR_BREAK(indices[0])
|
|
sfizz_arg_t args[2];
|
|
args[0].h = region.loopRange.getStart();
|
|
args[1].h = region.loopRange.getEnd();
|
|
client.receive(delay, path, "hh", args);
|
|
} break;
|
|
|
|
MATCH("/region&/loop_mode", "") {
|
|
GET_REGION_OR_BREAK(indices[0])
|
|
if (!region.loopMode) {
|
|
client.receive<'s'>(delay, path, "no_loop");
|
|
break;
|
|
}
|
|
|
|
switch (*region.loopMode) {
|
|
case LoopMode::no_loop:
|
|
client.receive<'s'>(delay, path, "no_loop");
|
|
break;
|
|
case LoopMode::loop_continuous:
|
|
client.receive<'s'>(delay, path, "loop_continuous");
|
|
break;
|
|
case LoopMode::loop_sustain:
|
|
client.receive<'s'>(delay, path, "loop_sustain");
|
|
break;
|
|
case LoopMode::one_shot:
|
|
client.receive<'s'>(delay, path, "one_shot");
|
|
break;
|
|
}
|
|
} break;
|
|
|
|
MATCH("/region&/loop_crossfade", "") {
|
|
GET_REGION_OR_BREAK(indices[0])
|
|
client.receive<'f'>(delay, path, region.loopCrossfade);
|
|
} break;
|
|
|
|
MATCH("/region&/group", "") {
|
|
GET_REGION_OR_BREAK(indices[0])
|
|
client.receive<'h'>(delay, path, region.group);
|
|
} break;
|
|
|
|
MATCH("/region&/off_by", "") {
|
|
GET_REGION_OR_BREAK(indices[0])
|
|
if (!region.offBy) {
|
|
client.receive<'N'>(delay, path, {});
|
|
} else {
|
|
client.receive<'h'>(delay, path, *region.offBy);
|
|
}
|
|
} break;
|
|
|
|
MATCH("/region&/off_mode", "") {
|
|
GET_REGION_OR_BREAK(indices[0])
|
|
switch (region.offMode) {
|
|
case OffMode::time:
|
|
client.receive<'s'>(delay, path, "time");
|
|
break;
|
|
case OffMode::normal:
|
|
client.receive<'s'>(delay, path, "normal");
|
|
break;
|
|
case OffMode::fast:
|
|
client.receive<'s'>(delay, path, "fast");
|
|
break;
|
|
}
|
|
} break;
|
|
|
|
MATCH("/region&/key_range", "") {
|
|
GET_REGION_OR_BREAK(indices[0])
|
|
sfizz_arg_t args[2];
|
|
args[0].i = region.keyRange.getStart();
|
|
args[1].i = region.keyRange.getEnd();
|
|
client.receive(delay, path, "ii", args);
|
|
} break;
|
|
|
|
MATCH("/region&/off_time", "") {
|
|
GET_REGION_OR_BREAK(indices[0])
|
|
client.receive<'f'>(delay, path, region.offTime);
|
|
} break;
|
|
|
|
MATCH("/region&/pitch_keycenter", "") {
|
|
GET_REGION_OR_BREAK(indices[0])
|
|
client.receive<'i'>(delay, path, region.pitchKeycenter);
|
|
} break;
|
|
|
|
MATCH("/region&/vel_range", "") {
|
|
GET_REGION_OR_BREAK(indices[0])
|
|
sfizz_arg_t args[2];
|
|
args[0].f = region.velocityRange.getStart();
|
|
args[1].f = region.velocityRange.getEnd();
|
|
client.receive(delay, path, "ff", args);
|
|
} break;
|
|
|
|
MATCH("/region&/bend_range", "") {
|
|
GET_REGION_OR_BREAK(indices[0])
|
|
sfizz_arg_t args[2];
|
|
args[0].f = region.bendRange.getStart();
|
|
args[1].f = region.bendRange.getEnd();
|
|
client.receive(delay, path, "ff", args);
|
|
} break;
|
|
|
|
MATCH("/region&/cc_range&", "") {
|
|
GET_REGION_OR_BREAK(indices[0])
|
|
sfizz_arg_t args[2];
|
|
const auto& conditions = region.ccConditions.getWithDefault(indices[1]);
|
|
args[0].f = conditions.getStart();
|
|
args[1].f = conditions.getEnd();
|
|
client.receive(delay, path, "ff", args);
|
|
} break;
|
|
|
|
MATCH("/region&/sw_last", "") {
|
|
GET_REGION_OR_BREAK(indices[0])
|
|
if (region.lastKeyswitch) {
|
|
client.receive<'i'>(delay, path, *region.lastKeyswitch);
|
|
} else if (region.lastKeyswitchRange) {
|
|
sfizz_arg_t args[2];
|
|
args[0].i = region.lastKeyswitchRange->getStart();
|
|
args[1].i = region.lastKeyswitchRange->getEnd();
|
|
client.receive(delay, path, "ii", args);
|
|
} else {
|
|
client.receive<'N'>(delay, path, {});
|
|
}
|
|
|
|
} break;
|
|
|
|
MATCH("/region&/sw_label", "") {
|
|
GET_REGION_OR_BREAK(indices[0])
|
|
if (region.keyswitchLabel) {
|
|
client.receive<'s'>(delay, path, region.keyswitchLabel->c_str());
|
|
} else {
|
|
client.receive<'N'>(delay, path, {});
|
|
}
|
|
} break;
|
|
|
|
MATCH("/region&/sw_up", "") {
|
|
GET_REGION_OR_BREAK(indices[0])
|
|
if (region.upKeyswitch) {
|
|
client.receive<'i'>(delay, path, *region.upKeyswitch);
|
|
} else {
|
|
client.receive<'N'>(delay, path, {});
|
|
}
|
|
} break;
|
|
|
|
MATCH("/region&/sw_down", "") {
|
|
GET_REGION_OR_BREAK(indices[0])
|
|
if (region.downKeyswitch) {
|
|
client.receive<'i'>(delay, path, *region.downKeyswitch);
|
|
} else {
|
|
client.receive<'N'>(delay, path, {});
|
|
}
|
|
} break;
|
|
|
|
MATCH("/region&/sw_previous", "") {
|
|
GET_REGION_OR_BREAK(indices[0])
|
|
if (region.previousKeyswitch) {
|
|
client.receive<'i'>(delay, path, *region.previousKeyswitch);
|
|
} else {
|
|
client.receive<'N'>(delay, path, {});
|
|
}
|
|
} break;
|
|
|
|
MATCH("/region&/sw_vel", "") {
|
|
GET_REGION_OR_BREAK(indices[0])
|
|
switch (region.velocityOverride) {
|
|
case VelocityOverride::current:
|
|
client.receive<'s'>(delay, path, "current");
|
|
break;
|
|
case VelocityOverride::previous:
|
|
client.receive<'s'>(delay, path, "previous");
|
|
break;
|
|
}
|
|
} break;
|
|
|
|
MATCH("/region&/chanaft_range", "") {
|
|
GET_REGION_OR_BREAK(indices[0])
|
|
sfizz_arg_t args[2];
|
|
args[0].i = region.aftertouchRange.getStart();
|
|
args[1].i = region.aftertouchRange.getEnd();
|
|
client.receive(delay, path, "ii", args);
|
|
} break;
|
|
|
|
MATCH("/region&/bpm_range", "") {
|
|
GET_REGION_OR_BREAK(indices[0])
|
|
sfizz_arg_t args[2];
|
|
args[0].f = region.bpmRange.getStart();
|
|
args[1].f = region.bpmRange.getEnd();
|
|
client.receive(delay, path, "ff", args);
|
|
} break;
|
|
|
|
MATCH("/region&/rand_range", "") {
|
|
GET_REGION_OR_BREAK(indices[0])
|
|
sfizz_arg_t args[2];
|
|
args[0].f = region.randRange.getStart();
|
|
args[1].f = region.randRange.getEnd();
|
|
client.receive(delay, path, "ff", args);
|
|
} break;
|
|
|
|
MATCH("/region&/seq_length", "") {
|
|
GET_REGION_OR_BREAK(indices[0])
|
|
client.receive<'h'>(delay, path, region.sequenceLength);
|
|
} break;
|
|
|
|
MATCH("/region&/seq_position", "") {
|
|
GET_REGION_OR_BREAK(indices[0])
|
|
client.receive<'h'>(delay, path, region.sequencePosition);
|
|
} break;
|
|
|
|
MATCH("/region&/trigger", "") {
|
|
GET_REGION_OR_BREAK(indices[0])
|
|
switch (region.trigger) {
|
|
case Trigger::attack:
|
|
client.receive<'s'>(delay, path, "attack");
|
|
break;
|
|
case Trigger::first:
|
|
client.receive<'s'>(delay, path, "first");
|
|
break;
|
|
case Trigger::release:
|
|
client.receive<'s'>(delay, path, "release");
|
|
break;
|
|
case Trigger::release_key:
|
|
client.receive<'s'>(delay, path, "release_key");
|
|
break;
|
|
case Trigger::legato:
|
|
client.receive<'s'>(delay, path, "legato");
|
|
break;
|
|
}
|
|
} break;
|
|
|
|
MATCH("/region&/start_cc_range&", "") {
|
|
GET_REGION_OR_BREAK(indices[0])
|
|
auto trigger = region.ccTriggers.get(indices[1]);
|
|
if (trigger) {
|
|
sfizz_arg_t args[2];
|
|
args[0].f = trigger->getStart();
|
|
args[1].f = trigger->getEnd();
|
|
client.receive(delay, path, "ff", args);
|
|
} else {
|
|
client.receive<'N'>(delay, path, {});
|
|
}
|
|
} break;
|
|
|
|
MATCH("/region&/volume", "") {
|
|
GET_REGION_OR_BREAK(indices[0])
|
|
client.receive<'f'>(delay, path, region.volume);
|
|
} break;
|
|
|
|
MATCH("/region&/volume_cc&", "") {
|
|
GET_REGION_OR_BREAK(indices[0])
|
|
auto value = region.ccModDepth(indices[1], ModId::Volume);
|
|
if (value) {
|
|
client.receive<'f'>(delay, path, *value);
|
|
} else {
|
|
client.receive<'N'>(delay, path, {});
|
|
}
|
|
} break;
|
|
|
|
MATCH("/region&/volume_stepcc&", "") {
|
|
GET_REGION_OR_BREAK(indices[0])
|
|
auto params = region.ccModParameters(indices[1], ModId::Volume);
|
|
if (params) {
|
|
client.receive<'f'>(delay, path, params->step);
|
|
} else {
|
|
client.receive<'N'>(delay, path, {});
|
|
}
|
|
} break;
|
|
|
|
MATCH("/region&/volume_smoothcc&", "") {
|
|
GET_REGION_OR_BREAK(indices[0])
|
|
auto params = region.ccModParameters(indices[1], ModId::Volume);
|
|
if (params) {
|
|
client.receive<'i'>(delay, path, params->smooth);
|
|
} else {
|
|
client.receive<'N'>(delay, path, {});
|
|
}
|
|
} break;
|
|
|
|
MATCH("/region&/volume_curvecc&", "") {
|
|
GET_REGION_OR_BREAK(indices[0])
|
|
auto params = region.ccModParameters(indices[1], ModId::Volume);
|
|
if (params) {
|
|
client.receive<'i'>(delay, path, params->curve);
|
|
} else {
|
|
client.receive<'N'>(delay, path, {});
|
|
}
|
|
} break;
|
|
|
|
MATCH("/region&/pan", "") {
|
|
GET_REGION_OR_BREAK(indices[0])
|
|
client.receive<'f'>(delay, path, region.pan * 100.0f);
|
|
} break;
|
|
|
|
MATCH("/region&/pan_cc&", "") {
|
|
GET_REGION_OR_BREAK(indices[0])
|
|
auto value = region.ccModDepth(indices[1], ModId::Pan);
|
|
if (value) {
|
|
client.receive<'f'>(delay, path, *value);
|
|
} else {
|
|
client.receive<'N'>(delay, path, {});
|
|
}
|
|
} break;
|
|
|
|
MATCH("/region&/pan_stepcc&", "") {
|
|
GET_REGION_OR_BREAK(indices[0])
|
|
auto params = region.ccModParameters(indices[1], ModId::Pan);
|
|
if (params) {
|
|
client.receive<'f'>(delay, path, params->step);
|
|
} else {
|
|
client.receive<'N'>(delay, path, {});
|
|
}
|
|
} break;
|
|
|
|
MATCH("/region&/pan_smoothcc&", "") {
|
|
GET_REGION_OR_BREAK(indices[0])
|
|
auto params = region.ccModParameters(indices[1], ModId::Pan);
|
|
if (params) {
|
|
client.receive<'i'>(delay, path, params->smooth);
|
|
} else {
|
|
client.receive<'N'>(delay, path, {});
|
|
}
|
|
} break;
|
|
|
|
MATCH("/region&/pan_curvecc&", "") {
|
|
GET_REGION_OR_BREAK(indices[0])
|
|
auto params = region.ccModParameters(indices[1], ModId::Pan);
|
|
if (params) {
|
|
client.receive<'i'>(delay, path, params->curve);
|
|
} else {
|
|
client.receive<'N'>(delay, path, {});
|
|
}
|
|
} break;
|
|
|
|
MATCH("/region&/width", "") {
|
|
GET_REGION_OR_BREAK(indices[0])
|
|
client.receive<'f'>(delay, path, region.width * 100.0f);
|
|
} break;
|
|
|
|
MATCH("/region&/width_cc&", "") {
|
|
GET_REGION_OR_BREAK(indices[0])
|
|
auto value = region.ccModDepth(indices[1], ModId::Width);
|
|
if (value) {
|
|
client.receive<'f'>(delay, path, *value);
|
|
} else {
|
|
client.receive<'N'>(delay, path, {});
|
|
}
|
|
} break;
|
|
|
|
MATCH("/region&/width_stepcc&", "") {
|
|
GET_REGION_OR_BREAK(indices[0])
|
|
auto params = region.ccModParameters(indices[1], ModId::Width);
|
|
if (params) {
|
|
client.receive<'f'>(delay, path, params->step);
|
|
} else {
|
|
client.receive<'N'>(delay, path, {});
|
|
}
|
|
} break;
|
|
|
|
MATCH("/region&/width_smoothcc&", "") {
|
|
GET_REGION_OR_BREAK(indices[0])
|
|
auto params = region.ccModParameters(indices[1], ModId::Width);
|
|
if (params) {
|
|
client.receive<'i'>(delay, path, params->smooth);
|
|
} else {
|
|
client.receive<'N'>(delay, path, {});
|
|
}
|
|
} break;
|
|
|
|
MATCH("/region&/width_curvecc&", "") {
|
|
GET_REGION_OR_BREAK(indices[0])
|
|
auto params = region.ccModParameters(indices[1], ModId::Width);
|
|
if (params) {
|
|
client.receive<'i'>(delay, path, params->curve);
|
|
} else {
|
|
client.receive<'N'>(delay, path, {});
|
|
}
|
|
} break;
|
|
|
|
MATCH("/region&/position", "") {
|
|
GET_REGION_OR_BREAK(indices[0])
|
|
client.receive<'f'>(delay, path, region.position * 100.0f);
|
|
} break;
|
|
|
|
MATCH("/region&/position_cc&", "") {
|
|
GET_REGION_OR_BREAK(indices[0])
|
|
auto value = region.ccModDepth(indices[1], ModId::Position);
|
|
if (value) {
|
|
client.receive<'f'>(delay, path, *value);
|
|
} else {
|
|
client.receive<'N'>(delay, path, {});
|
|
}
|
|
} break;
|
|
|
|
MATCH("/region&/position_stepcc&", "") {
|
|
GET_REGION_OR_BREAK(indices[0])
|
|
auto params = region.ccModParameters(indices[1], ModId::Position);
|
|
if (params) {
|
|
client.receive<'f'>(delay, path, params->step);
|
|
} else {
|
|
client.receive<'N'>(delay, path, {});
|
|
}
|
|
} break;
|
|
|
|
MATCH("/region&/position_smoothcc&", "") {
|
|
GET_REGION_OR_BREAK(indices[0])
|
|
auto params = region.ccModParameters(indices[1], ModId::Position);
|
|
if (params) {
|
|
client.receive<'i'>(delay, path, params->smooth);
|
|
} else {
|
|
client.receive<'N'>(delay, path, {});
|
|
}
|
|
} break;
|
|
|
|
MATCH("/region&/position_curvecc&", "") {
|
|
GET_REGION_OR_BREAK(indices[0])
|
|
auto params = region.ccModParameters(indices[1], ModId::Position);
|
|
if (params) {
|
|
client.receive<'i'>(delay, path, params->curve);
|
|
} else {
|
|
client.receive<'N'>(delay, path, {});
|
|
}
|
|
} break;
|
|
|
|
MATCH("/region&/amplitude", "") {
|
|
GET_REGION_OR_BREAK(indices[0])
|
|
client.receive<'f'>(delay, path, region.amplitude * 100.0f);
|
|
} break;
|
|
|
|
MATCH("/region&/amplitude_cc&", "") {
|
|
GET_REGION_OR_BREAK(indices[0])
|
|
auto value = region.ccModDepth(indices[1], ModId::Amplitude);
|
|
if (value) {
|
|
client.receive<'f'>(delay, path, *value);
|
|
} else {
|
|
client.receive<'N'>(delay, path, {});
|
|
}
|
|
} break;
|
|
|
|
MATCH("/region&/amplitude_stepcc&", "") {
|
|
GET_REGION_OR_BREAK(indices[0])
|
|
auto params = region.ccModParameters(indices[1], ModId::Amplitude);
|
|
if (params) {
|
|
client.receive<'f'>(delay, path, params->step);
|
|
} else {
|
|
client.receive<'N'>(delay, path, {});
|
|
}
|
|
} break;
|
|
|
|
MATCH("/region&/amplitude_smoothcc&", "") {
|
|
GET_REGION_OR_BREAK(indices[0])
|
|
auto params = region.ccModParameters(indices[1], ModId::Amplitude);
|
|
if (params) {
|
|
client.receive<'i'>(delay, path, params->smooth);
|
|
} else {
|
|
client.receive<'N'>(delay, path, {});
|
|
}
|
|
} break;
|
|
|
|
MATCH("/region&/amplitude_curvecc&", "") {
|
|
GET_REGION_OR_BREAK(indices[0])
|
|
auto params = region.ccModParameters(indices[1], ModId::Amplitude);
|
|
if (params) {
|
|
client.receive<'i'>(delay, path, params->curve);
|
|
} else {
|
|
client.receive<'N'>(delay, path, {});
|
|
}
|
|
} break;
|
|
|
|
MATCH("/region&/amp_keycenter", "") {
|
|
GET_REGION_OR_BREAK(indices[0])
|
|
client.receive<'i'>(delay, path, region.ampKeycenter);
|
|
} break;
|
|
|
|
MATCH("/region&/amp_keytrack", "") {
|
|
GET_REGION_OR_BREAK(indices[0])
|
|
client.receive<'f'>(delay, path, region.ampKeytrack);
|
|
} break;
|
|
|
|
MATCH("/region&/amp_veltrack", "") {
|
|
GET_REGION_OR_BREAK(indices[0])
|
|
client.receive<'f'>(delay, path, region.ampVeltrack * 100.0f);
|
|
} break;
|
|
|
|
MATCH("/region&/amp_random", "") {
|
|
GET_REGION_OR_BREAK(indices[0])
|
|
client.receive<'f'>(delay, path, region.ampRandom);
|
|
} break;
|
|
|
|
MATCH("/region&/xfin_key_range", "") {
|
|
GET_REGION_OR_BREAK(indices[0])
|
|
sfizz_arg_t args[2];
|
|
args[0].i = region.crossfadeKeyInRange.getStart();
|
|
args[1].i = region.crossfadeKeyInRange.getEnd();
|
|
client.receive(delay, path, "ii", args);
|
|
} break;
|
|
|
|
MATCH("/region&/xfout_key_range", "") {
|
|
GET_REGION_OR_BREAK(indices[0])
|
|
sfizz_arg_t args[2];
|
|
args[0].i = region.crossfadeKeyOutRange.getStart();
|
|
args[1].i = region.crossfadeKeyOutRange.getEnd();
|
|
client.receive(delay, path, "ii", args);
|
|
} break;
|
|
|
|
MATCH("/region&/xfin_vel_range", "") {
|
|
GET_REGION_OR_BREAK(indices[0])
|
|
sfizz_arg_t args[2];
|
|
args[0].f = region.crossfadeVelInRange.getStart();
|
|
args[1].f = region.crossfadeVelInRange.getEnd();
|
|
client.receive(delay, path, "ff", args);
|
|
} break;
|
|
|
|
MATCH("/region&/xfout_vel_range", "") {
|
|
GET_REGION_OR_BREAK(indices[0])
|
|
sfizz_arg_t args[2];
|
|
args[0].f = region.crossfadeVelOutRange.getStart();
|
|
args[1].f = region.crossfadeVelOutRange.getEnd();
|
|
client.receive(delay, path, "ff", args);
|
|
} break;
|
|
|
|
MATCH("/region&/xfin_cc_range&", "") {
|
|
GET_REGION_OR_BREAK(indices[0])
|
|
auto range = region.crossfadeCCInRange.get(indices[1]);
|
|
if (range) {
|
|
sfizz_arg_t args[2];
|
|
args[0].f = range->getStart();
|
|
args[1].f = range->getEnd();
|
|
client.receive(delay, path, "ff", args);
|
|
} else {
|
|
client.receive<'N'>(delay, path, {});
|
|
}
|
|
} break;
|
|
|
|
MATCH("/region&/xfout_cc_range&", "") {
|
|
GET_REGION_OR_BREAK(indices[0])
|
|
auto range = region.crossfadeCCOutRange.get(indices[1]);
|
|
if (range) {
|
|
sfizz_arg_t args[2];
|
|
args[0].f = range->getStart();
|
|
args[1].f = range->getEnd();
|
|
client.receive(delay, path, "ff", args);
|
|
} else {
|
|
client.receive<'N'>(delay, path, {});
|
|
}
|
|
} break;
|
|
|
|
MATCH("/region&/xf_keycurve", "") {
|
|
GET_REGION_OR_BREAK(indices[0])
|
|
switch (region.crossfadeKeyCurve) {
|
|
case CrossfadeCurve::gain:
|
|
client.receive<'s'>(delay, path, "gain");
|
|
break;
|
|
case CrossfadeCurve::power:
|
|
client.receive<'s'>(delay, path, "power");
|
|
break;
|
|
}
|
|
} break;
|
|
|
|
MATCH("/region&/xf_velcurve", "") {
|
|
GET_REGION_OR_BREAK(indices[0])
|
|
switch (region.crossfadeVelCurve) {
|
|
case CrossfadeCurve::gain:
|
|
client.receive<'s'>(delay, path, "gain");
|
|
break;
|
|
case CrossfadeCurve::power:
|
|
client.receive<'s'>(delay, path, "power");
|
|
break;
|
|
}
|
|
} break;
|
|
|
|
MATCH("/region&/xf_cccurve", "") {
|
|
GET_REGION_OR_BREAK(indices[0])
|
|
switch (region.crossfadeCCCurve) {
|
|
case CrossfadeCurve::gain:
|
|
client.receive<'s'>(delay, path, "gain");
|
|
break;
|
|
case CrossfadeCurve::power:
|
|
client.receive<'s'>(delay, path, "power");
|
|
break;
|
|
}
|
|
} break;
|
|
|
|
MATCH("/region&/global_volume", "") {
|
|
GET_REGION_OR_BREAK(indices[0])
|
|
client.receive<'f'>(delay, path, region.globalVolume);
|
|
} break;
|
|
|
|
MATCH("/region&/master_volume", "") {
|
|
GET_REGION_OR_BREAK(indices[0])
|
|
client.receive<'f'>(delay, path, region.masterVolume);
|
|
} break;
|
|
|
|
MATCH("/region&/group_volume", "") {
|
|
GET_REGION_OR_BREAK(indices[0])
|
|
client.receive<'f'>(delay, path, region.groupVolume);
|
|
} break;
|
|
|
|
MATCH("/region&/global_amplitude", "") {
|
|
GET_REGION_OR_BREAK(indices[0])
|
|
client.receive<'f'>(delay, path, region.globalAmplitude * 100.0f);
|
|
} break;
|
|
|
|
MATCH("/region&/master_amplitude", "") {
|
|
GET_REGION_OR_BREAK(indices[0])
|
|
client.receive<'f'>(delay, path, region.masterAmplitude * 100.0f);
|
|
} break;
|
|
|
|
MATCH("/region&/group_amplitude", "") {
|
|
GET_REGION_OR_BREAK(indices[0])
|
|
client.receive<'f'>(delay, path, region.groupAmplitude * 100.0f);
|
|
} break;
|
|
|
|
MATCH("/region&/pitch_keytrack", "") {
|
|
GET_REGION_OR_BREAK(indices[0])
|
|
client.receive<'i'>(delay, path, region.pitchKeytrack);
|
|
} break;
|
|
|
|
MATCH("/region&/pitch_veltrack", "") {
|
|
GET_REGION_OR_BREAK(indices[0])
|
|
client.receive<'i'>(delay, path, region.pitchVeltrack);
|
|
} break;
|
|
|
|
MATCH("/region&/pitch_random", "") {
|
|
GET_REGION_OR_BREAK(indices[0])
|
|
client.receive<'f'>(delay, path, region.pitchRandom);
|
|
} break;
|
|
|
|
MATCH("/region&/transpose", "") {
|
|
GET_REGION_OR_BREAK(indices[0])
|
|
client.receive<'i'>(delay, path, region.transpose);
|
|
} break;
|
|
|
|
MATCH("/region&/pitch", "") {
|
|
GET_REGION_OR_BREAK(indices[0])
|
|
client.receive<'f'>(delay, path, region.pitch);
|
|
} break;
|
|
|
|
MATCH("/region&/pitch_cc&", "") {
|
|
GET_REGION_OR_BREAK(indices[0])
|
|
auto value = region.ccModDepth(indices[1], ModId::Pitch);
|
|
if (value) {
|
|
client.receive<'f'>(delay, path, *value);
|
|
} else {
|
|
client.receive<'N'>(delay, path, {});
|
|
}
|
|
} break;
|
|
|
|
MATCH("/region&/pitch_stepcc&", "") {
|
|
GET_REGION_OR_BREAK(indices[0])
|
|
auto params = region.ccModParameters(indices[1], ModId::Pitch);
|
|
if (params) {
|
|
client.receive<'f'>(delay, path, params->step);
|
|
} else {
|
|
client.receive<'N'>(delay, path, {});
|
|
}
|
|
} break;
|
|
|
|
MATCH("/region&/pitch_smoothcc&", "") {
|
|
GET_REGION_OR_BREAK(indices[0])
|
|
auto params = region.ccModParameters(indices[1], ModId::Pitch);
|
|
if (params) {
|
|
client.receive<'i'>(delay, path, params->smooth);
|
|
} else {
|
|
client.receive<'N'>(delay, path, {});
|
|
}
|
|
} break;
|
|
|
|
MATCH("/region&/pitch_curvecc&", "") {
|
|
GET_REGION_OR_BREAK(indices[0])
|
|
auto params = region.ccModParameters(indices[1], ModId::Pitch);
|
|
if (params) {
|
|
client.receive<'i'>(delay, path, params->curve);
|
|
} else {
|
|
client.receive<'N'>(delay, path, {});
|
|
}
|
|
} break;
|
|
|
|
MATCH("/region&/bend_up", "") {
|
|
GET_REGION_OR_BREAK(indices[0])
|
|
client.receive<'f'>(delay, path, region.bendUp);
|
|
} break;
|
|
|
|
MATCH("/region&/bend_down", "") {
|
|
GET_REGION_OR_BREAK(indices[0])
|
|
client.receive<'f'>(delay, path, region.bendDown);
|
|
} break;
|
|
|
|
MATCH("/region&/bend_step", "") {
|
|
GET_REGION_OR_BREAK(indices[0])
|
|
client.receive<'f'>(delay, path, region.bendStep);
|
|
} break;
|
|
|
|
MATCH("/region&/bend_smooth", "") {
|
|
GET_REGION_OR_BREAK(indices[0])
|
|
client.receive<'i'>(delay, path, region.bendSmooth);
|
|
} break;
|
|
|
|
MATCH("/region&/ampeg_attack", "") {
|
|
GET_REGION_OR_BREAK(indices[0])
|
|
client.receive<'f'>(delay, path, region.amplitudeEG.attack);
|
|
} break;
|
|
|
|
MATCH("/region&/ampeg_delay", "") {
|
|
GET_REGION_OR_BREAK(indices[0])
|
|
client.receive<'f'>(delay, path, region.amplitudeEG.delay);
|
|
} break;
|
|
|
|
MATCH("/region&/ampeg_decay", "") {
|
|
GET_REGION_OR_BREAK(indices[0])
|
|
client.receive<'f'>(delay, path, region.amplitudeEG.decay);
|
|
} break;
|
|
|
|
MATCH("/region&/ampeg_hold", "") {
|
|
GET_REGION_OR_BREAK(indices[0])
|
|
client.receive<'f'>(delay, path, region.amplitudeEG.hold);
|
|
} break;
|
|
|
|
MATCH("/region&/ampeg_release", "") {
|
|
GET_REGION_OR_BREAK(indices[0])
|
|
client.receive<'f'>(delay, path, region.amplitudeEG.release);
|
|
} break;
|
|
|
|
MATCH("/region&/ampeg_start", "") {
|
|
GET_REGION_OR_BREAK(indices[0])
|
|
client.receive<'f'>(delay, path, region.amplitudeEG.start);
|
|
} break;
|
|
|
|
MATCH("/region&/ampeg_sustain", "") {
|
|
GET_REGION_OR_BREAK(indices[0])
|
|
client.receive<'f'>(delay, path, region.amplitudeEG.sustain);
|
|
} break;
|
|
|
|
MATCH("/region&/ampeg_depth", "") {
|
|
GET_REGION_OR_BREAK(indices[0])
|
|
client.receive<'f'>(delay, path, region.amplitudeEG.depth);
|
|
} break;
|
|
|
|
MATCH("/region&/ampeg_vel&attack", "") {
|
|
GET_REGION_OR_BREAK(indices[0])
|
|
if (indices[1] != 2)
|
|
break;
|
|
client.receive<'f'>(delay, path, region.amplitudeEG.vel2attack);
|
|
} break;
|
|
|
|
MATCH("/region&/ampeg_vel&delay", "") {
|
|
GET_REGION_OR_BREAK(indices[0])
|
|
if (indices[1] != 2)
|
|
break;
|
|
client.receive<'f'>(delay, path, region.amplitudeEG.vel2delay);
|
|
} break;
|
|
|
|
MATCH("/region&/ampeg_vel&decay", "") {
|
|
GET_REGION_OR_BREAK(indices[0])
|
|
if (indices[1] != 2)
|
|
break;
|
|
client.receive<'f'>(delay, path, region.amplitudeEG.vel2decay);
|
|
} break;
|
|
|
|
MATCH("/region&/ampeg_vel&hold", "") {
|
|
GET_REGION_OR_BREAK(indices[0])
|
|
if (indices[1] != 2)
|
|
break;
|
|
client.receive<'f'>(delay, path, region.amplitudeEG.vel2hold);
|
|
} break;
|
|
|
|
MATCH("/region&/ampeg_vel&release", "") {
|
|
GET_REGION_OR_BREAK(indices[0])
|
|
if (indices[1] != 2)
|
|
break;
|
|
client.receive<'f'>(delay, path, region.amplitudeEG.vel2release);
|
|
} break;
|
|
|
|
MATCH("/region&/ampeg_vel&sustain", "") {
|
|
GET_REGION_OR_BREAK(indices[0])
|
|
if (indices[1] != 2)
|
|
break;
|
|
client.receive<'f'>(delay, path, region.amplitudeEG.vel2sustain);
|
|
} break;
|
|
|
|
MATCH("/region&/ampeg_vel&depth", "") {
|
|
GET_REGION_OR_BREAK(indices[0])
|
|
if (indices[1] != 2)
|
|
break;
|
|
client.receive<'f'>(delay, path, region.amplitudeEG.vel2depth);
|
|
} break;
|
|
|
|
MATCH("/region&/note_polyphony", "") {
|
|
GET_REGION_OR_BREAK(indices[0])
|
|
if (region.notePolyphony) {
|
|
client.receive<'i'>(delay, path, *region.notePolyphony);
|
|
} else {
|
|
client.receive<'N'>(delay, path, {});
|
|
}
|
|
} break;
|
|
|
|
MATCH("/region&/note_selfmask", "") {
|
|
GET_REGION_OR_BREAK(indices[0])
|
|
switch(region.selfMask) {
|
|
case SelfMask::mask:
|
|
client.receive(delay, path, "T", nullptr);
|
|
break;
|
|
case SelfMask::dontMask:
|
|
client.receive(delay, path, "F", nullptr);
|
|
break;
|
|
}
|
|
} break;
|
|
|
|
MATCH("/region&/rt_dead", "") {
|
|
GET_REGION_OR_BREAK(indices[0])
|
|
if (region.rtDead) {
|
|
client.receive(delay, path, "T", nullptr);
|
|
} else {
|
|
client.receive(delay, path, "F", nullptr);
|
|
}
|
|
} break;
|
|
|
|
MATCH("/region&/sustain_sw", "") {
|
|
GET_REGION_OR_BREAK(indices[0])
|
|
if (region.checkSustain) {
|
|
client.receive(delay, path, "T", nullptr);
|
|
} else {
|
|
client.receive(delay, path, "F", nullptr);
|
|
}
|
|
} break;
|
|
|
|
MATCH("/region&/sostenuto_sw", "") {
|
|
GET_REGION_OR_BREAK(indices[0])
|
|
if (region.checkSostenuto) {
|
|
client.receive(delay, path, "T", nullptr);
|
|
} else {
|
|
client.receive(delay, path, "F", nullptr);
|
|
}
|
|
} break;
|
|
|
|
MATCH("/region&/sustain_cc", "") {
|
|
GET_REGION_OR_BREAK(indices[0])
|
|
client.receive<'i'>(delay, path, region.sustainCC);
|
|
} break;
|
|
|
|
MATCH("/region&/sustain_lo", "") {
|
|
GET_REGION_OR_BREAK(indices[0])
|
|
client.receive<'f'>(delay, path, region.sustainThreshold);
|
|
} break;
|
|
|
|
MATCH("/region&/oscillator_phase", "") {
|
|
GET_REGION_OR_BREAK(indices[0])
|
|
client.receive<'f'>(delay, path, region.oscillatorPhase);
|
|
} break;
|
|
|
|
MATCH("/region&/oscillator_quality", "") {
|
|
GET_REGION_OR_BREAK(indices[0])
|
|
if (region.oscillatorQuality) {
|
|
client.receive<'i'>(delay, path, *region.oscillatorQuality);
|
|
} else {
|
|
client.receive<'N'>(delay, path, {});
|
|
}
|
|
} break;
|
|
|
|
MATCH("/region&/oscillator_mode", "") {
|
|
GET_REGION_OR_BREAK(indices[0])
|
|
client.receive<'i'>(delay, path, region.oscillatorMode);
|
|
} break;
|
|
|
|
MATCH("/region&/oscillator_multi", "") {
|
|
GET_REGION_OR_BREAK(indices[0])
|
|
client.receive<'i'>(delay, path, region.oscillatorMulti);
|
|
} break;
|
|
|
|
MATCH("/region&/oscillator_detune", "") {
|
|
GET_REGION_OR_BREAK(indices[0])
|
|
client.receive<'f'>(delay, path, region.oscillatorDetune);
|
|
} break;
|
|
|
|
MATCH("/region&/oscillator_mod_depth", "") {
|
|
GET_REGION_OR_BREAK(indices[0])
|
|
client.receive<'f'>(delay, path, region.oscillatorModDepth * 100.0f);
|
|
} break;
|
|
|
|
// TODO: detune cc, mod depth cc
|
|
|
|
MATCH("/region&/effect&", "") {
|
|
GET_REGION_OR_BREAK(indices[0])
|
|
auto effectIdx = indices[1];
|
|
if (indices[1] == 0)
|
|
break;
|
|
|
|
if (effectIdx < region.gainToEffect.size())
|
|
client.receive<'f'>(delay, path, region.gainToEffect[effectIdx] * 100.0f);
|
|
} break;
|
|
|
|
MATCH("/region&/ampeg_attack_cc&", "") {
|
|
GET_REGION_OR_BREAK(indices[0])
|
|
float value = region.amplitudeEG.ccAttack.getWithDefault(indices[1]);
|
|
client.receive<'f'>(delay, path, value);
|
|
} break;
|
|
|
|
MATCH("/region&/ampeg_decay_cc&", "") {
|
|
GET_REGION_OR_BREAK(indices[0])
|
|
float value = region.amplitudeEG.ccDecay.getWithDefault(indices[1]);
|
|
client.receive<'f'>(delay, path, value);
|
|
} break;
|
|
|
|
MATCH("/region&/ampeg_delay_cc&", "") {
|
|
GET_REGION_OR_BREAK(indices[0])
|
|
float value = region.amplitudeEG.ccDelay.getWithDefault(indices[1]);
|
|
client.receive<'f'>(delay, path, value);
|
|
} break;
|
|
|
|
MATCH("/region&/ampeg_hold_cc&", "") {
|
|
GET_REGION_OR_BREAK(indices[0])
|
|
float value = region.amplitudeEG.ccHold.getWithDefault(indices[1]);
|
|
client.receive<'f'>(delay, path, value);
|
|
} break;
|
|
|
|
MATCH("/region&/ampeg_release_cc&", "") {
|
|
GET_REGION_OR_BREAK(indices[0])
|
|
float value = region.amplitudeEG.ccRelease.getWithDefault(indices[1]);
|
|
client.receive<'f'>(delay, path, value);
|
|
} break;
|
|
|
|
MATCH("/region&/ampeg_start_cc&", "") {
|
|
GET_REGION_OR_BREAK(indices[0])
|
|
float value = region.amplitudeEG.ccStart.getWithDefault(indices[1]);
|
|
client.receive<'f'>(delay, path, value);
|
|
} break;
|
|
|
|
MATCH("/region&/ampeg_sustain_cc&", "") {
|
|
GET_REGION_OR_BREAK(indices[0])
|
|
float value = region.amplitudeEG.ccSustain.getWithDefault(indices[1]);
|
|
client.receive<'f'>(delay, path, value);
|
|
} break;
|
|
|
|
#define GET_FILTER_OR_BREAK(idx) \
|
|
if (idx >= region.filters.size()) \
|
|
break; \
|
|
const auto& filter = region.filters[idx];
|
|
|
|
MATCH("/region&/filter&/cutoff", "") {
|
|
GET_REGION_OR_BREAK(indices[0])
|
|
GET_FILTER_OR_BREAK(indices[1])
|
|
client.receive<'f'>(delay, path, filter.cutoff);
|
|
} break;
|
|
|
|
MATCH("/region&/filter&/resonance", "") {
|
|
GET_REGION_OR_BREAK(indices[0])
|
|
GET_FILTER_OR_BREAK(indices[1])
|
|
client.receive<'f'>(delay, path, filter.resonance);
|
|
} break;
|
|
|
|
MATCH("/region&/filter&/gain", "") {
|
|
GET_REGION_OR_BREAK(indices[0])
|
|
GET_FILTER_OR_BREAK(indices[1])
|
|
client.receive<'f'>(delay, path, filter.gain);
|
|
} break;
|
|
|
|
MATCH("/region&/filter&/keycenter", "") {
|
|
GET_REGION_OR_BREAK(indices[0])
|
|
GET_FILTER_OR_BREAK(indices[1])
|
|
client.receive<'i'>(delay, path, filter.keycenter);
|
|
} break;
|
|
|
|
MATCH("/region&/filter&/keytrack", "") {
|
|
GET_REGION_OR_BREAK(indices[0])
|
|
GET_FILTER_OR_BREAK(indices[1])
|
|
client.receive<'i'>(delay, path, filter.keytrack);
|
|
} break;
|
|
|
|
MATCH("/region&/filter&/veltrack", "") {
|
|
GET_REGION_OR_BREAK(indices[0])
|
|
GET_FILTER_OR_BREAK(indices[1])
|
|
client.receive<'i'>(delay, path, filter.veltrack);
|
|
} break;
|
|
|
|
MATCH("/region&/filter&/type", "") {
|
|
GET_REGION_OR_BREAK(indices[0])
|
|
GET_FILTER_OR_BREAK(indices[1])
|
|
switch (filter.type) {
|
|
case FilterType::kFilterLpf1p: client.receive<'s'>(delay, path, "lpf_1p"); break;
|
|
case FilterType::kFilterHpf1p: client.receive<'s'>(delay, path, "hpf_1p"); break;
|
|
case FilterType::kFilterLpf2p: client.receive<'s'>(delay, path, "lpf_2p"); break;
|
|
case FilterType::kFilterHpf2p: client.receive<'s'>(delay, path, "hpf_2p"); break;
|
|
case FilterType::kFilterBpf2p: client.receive<'s'>(delay, path, "bpf_2p"); break;
|
|
case FilterType::kFilterBrf2p: client.receive<'s'>(delay, path, "brf_2p"); break;
|
|
case FilterType::kFilterBpf1p: client.receive<'s'>(delay, path, "bpf_1p"); break;
|
|
case FilterType::kFilterBrf1p: client.receive<'s'>(delay, path, "brf_1p"); break;
|
|
case FilterType::kFilterApf1p: client.receive<'s'>(delay, path, "apf_1p"); break;
|
|
case FilterType::kFilterLpf2pSv: client.receive<'s'>(delay, path, "lpf_2p_sv"); break;
|
|
case FilterType::kFilterHpf2pSv: client.receive<'s'>(delay, path, "hpf_2p_sv"); break;
|
|
case FilterType::kFilterBpf2pSv: client.receive<'s'>(delay, path, "bpf_2p_sv"); break;
|
|
case FilterType::kFilterBrf2pSv: client.receive<'s'>(delay, path, "brf_2p_sv"); break;
|
|
case FilterType::kFilterLpf4p: client.receive<'s'>(delay, path, "lpf_4p"); break;
|
|
case FilterType::kFilterHpf4p: client.receive<'s'>(delay, path, "hpf_4p"); break;
|
|
case FilterType::kFilterLpf6p: client.receive<'s'>(delay, path, "lpf_6p"); break;
|
|
case FilterType::kFilterHpf6p: client.receive<'s'>(delay, path, "hpf_6p"); break;
|
|
case FilterType::kFilterPink: client.receive<'s'>(delay, path, "pink"); break;
|
|
case FilterType::kFilterLsh: client.receive<'s'>(delay, path, "lsh"); break;
|
|
case FilterType::kFilterHsh: client.receive<'s'>(delay, path, "hsh"); break;
|
|
case FilterType::kFilterPeq: client.receive<'s'>(delay, path, "peq"); break;
|
|
case FilterType::kFilterBpf4p: client.receive<'s'>(delay, path, "bpf_4p"); break;
|
|
case FilterType::kFilterBpf6p: client.receive<'s'>(delay, path, "bpf_6p"); break;
|
|
case FilterType::kFilterNone: client.receive<'s'>(delay, path, "none"); break;
|
|
}
|
|
} break;
|
|
|
|
#undef GET_FILTER_OR_BREAK
|
|
|
|
#define GET_EQ_OR_BREAK(idx) \
|
|
if (idx >= region.equalizers.size()) \
|
|
break; \
|
|
const auto& eq = region.equalizers[idx];
|
|
|
|
MATCH("/region&/eq&/gain", "") {
|
|
GET_REGION_OR_BREAK(indices[0])
|
|
GET_EQ_OR_BREAK(indices[1])
|
|
client.receive<'f'>(delay, path, eq.gain);
|
|
} break;
|
|
|
|
MATCH("/region&/eq&/bandwidth", "") {
|
|
GET_REGION_OR_BREAK(indices[0])
|
|
GET_EQ_OR_BREAK(indices[1])
|
|
client.receive<'f'>(delay, path, eq.bandwidth);
|
|
} break;
|
|
|
|
MATCH("/region&/eq&/frequency", "") {
|
|
GET_REGION_OR_BREAK(indices[0])
|
|
GET_EQ_OR_BREAK(indices[1])
|
|
client.receive<'f'>(delay, path, eq.frequency);
|
|
} break;
|
|
|
|
MATCH("/region&/eq&/vel&freq", "") {
|
|
GET_REGION_OR_BREAK(indices[0])
|
|
GET_EQ_OR_BREAK(indices[1])
|
|
if (indices[2] != 2)
|
|
break;
|
|
client.receive<'f'>(delay, path, eq.vel2frequency);
|
|
} break;
|
|
|
|
MATCH("/region&/eq&/vel&gain", "") {
|
|
GET_REGION_OR_BREAK(indices[0])
|
|
GET_EQ_OR_BREAK(indices[1])
|
|
if (indices[2] != 2)
|
|
break;
|
|
client.receive<'f'>(delay, path, eq.vel2gain);
|
|
} break;
|
|
|
|
MATCH("/region&/eq&/type", "") {
|
|
GET_REGION_OR_BREAK(indices[0])
|
|
GET_EQ_OR_BREAK(indices[1])
|
|
switch (eq.type) {
|
|
case EqType::kEqNone: client.receive<'s'>(delay, path, "none"); break;
|
|
case EqType::kEqPeak: client.receive<'s'>(delay, path, "peak"); break;
|
|
case EqType::kEqLowShelf: client.receive<'s'>(delay, path, "lshelf"); break;
|
|
case EqType::kEqHighShelf: client.receive<'s'>(delay, path, "hshelf"); break;
|
|
}
|
|
} break;
|
|
|
|
#undef GET_EQ_OR_BREAK
|
|
|
|
#undef GET_REGION_OR_BREAK
|
|
|
|
MATCH("/num_active_voices", "") {
|
|
client.receive<'i'>(delay, path, impl.voiceManager_.getNumActiveVoices());
|
|
} break;
|
|
|
|
#define GET_VOICE_OR_BREAK(idx) \
|
|
if (static_cast<int>(idx) >= impl.numVoices_) \
|
|
break; \
|
|
const auto& voice = impl.voiceManager_[idx]; \
|
|
if (voice.isFree()) \
|
|
break;
|
|
|
|
MATCH("/voice&/trigger_value", "") {
|
|
GET_VOICE_OR_BREAK(indices[0])
|
|
client.receive<'f'>(delay, path, voice.getTriggerEvent().value);
|
|
} break;
|
|
|
|
MATCH("/voice&/trigger_number", "") {
|
|
GET_VOICE_OR_BREAK(indices[0])
|
|
client.receive<'i'>(delay, path, voice.getTriggerEvent().number);
|
|
} break;
|
|
|
|
MATCH("/voice&/trigger_type", "") {
|
|
GET_VOICE_OR_BREAK(indices[0])
|
|
const auto& event = voice.getTriggerEvent();
|
|
switch (event.type) {
|
|
case TriggerEventType::CC:
|
|
client.receive<'s'>(delay, path, "cc");
|
|
break;
|
|
case TriggerEventType::NoteOn:
|
|
client.receive<'s'>(delay, path, "note_on");
|
|
break;
|
|
case TriggerEventType::NoteOff:
|
|
client.receive<'s'>(delay, path, "note_on");
|
|
break;
|
|
}
|
|
|
|
} break;
|
|
|
|
#undef MATCH
|
|
// TODO...
|
|
}
|
|
}
|
|
|
|
static bool extractMessage(const char* pattern, const char* path, unsigned* indices)
|
|
{
|
|
unsigned nthIndex = 0;
|
|
|
|
while (const char *endp = strchr(pattern, '&')) {
|
|
if (nthIndex == maxIndices)
|
|
return false;
|
|
|
|
size_t length = endp - pattern;
|
|
if (strncmp(pattern, path, length))
|
|
return false;
|
|
pattern += length;
|
|
path += length;
|
|
|
|
length = 0;
|
|
while (absl::ascii_isdigit(path[length]))
|
|
++length;
|
|
|
|
if (!absl::SimpleAtoi(absl::string_view(path, length), &indices[nthIndex++]))
|
|
return false;
|
|
|
|
pattern += 1;
|
|
path += length;
|
|
}
|
|
|
|
return !strcmp(path, pattern);
|
|
}
|
|
|
|
static uint64_t hashMessagePath(const char* path, const char* sig)
|
|
{
|
|
uint64_t h = Fnv1aBasis;
|
|
while (unsigned char c = *path++) {
|
|
if (!absl::ascii_isdigit(c))
|
|
h = hashByte(c, h);
|
|
else {
|
|
h = hashByte('&', h);
|
|
while (absl::ascii_isdigit(*path))
|
|
++path;
|
|
}
|
|
}
|
|
h = hashByte(',', h);
|
|
while (unsigned char c = *sig++)
|
|
h = hashByte(c, h);
|
|
return h;
|
|
}
|
|
|
|
} // namespace sfz
|