Merge pull request #475 from jpcima/fix-cc

Fix CC modulations, having their source depth to 0
This commit is contained in:
JP Cimalando 2020-10-06 04:34:35 +02:00 committed by GitHub
commit 2351f18bfd
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 69 additions and 47 deletions

View file

@ -1550,7 +1550,7 @@ bool sfz::Region::processGenericCc(const Opcode& opcode, Range<float> range, con
else {
connections.emplace_back();
conn = &connections.back();
conn->source = ModKey::createCC(ccNumber, 0, 0, 0, 0);
conn->source = ModKey::createCC(ccNumber, 0, 0, 0);
conn->target = target;
}
@ -1558,7 +1558,7 @@ bool sfz::Region::processGenericCc(const Opcode& opcode, Range<float> range, con
ModKey::Parameters p = conn->source.parameters();
switch (opcode.category) {
case kOpcodeOnCcN:
setValueFromOpcode(opcode, p.value, range);
setValueFromOpcode(opcode, conn->sourceDepth, range);
break;
case kOpcodeCurveCcN:
setValueFromOpcode(opcode, p.curve, Default::curveCCRange);

View file

@ -145,11 +145,11 @@ void sfz::Synth::buildRegion(const std::vector<Opcode>& regionOpcodes)
// Create default connections
constexpr unsigned defaultSmoothness = 10;
lastRegion->getOrCreateConnection(
ModKey::createCC(7, 4, defaultSmoothness, 100, 0),
ModKey::createNXYZ(ModId::Amplitude, lastRegion->id)).sourceDepth = 1.0f;
ModKey::createCC(7, 4, defaultSmoothness, 0),
ModKey::createNXYZ(ModId::Amplitude, lastRegion->id)).sourceDepth = 100.0f;
lastRegion->getOrCreateConnection(
ModKey::createCC(10, 1, defaultSmoothness, 100, 0),
ModKey::createNXYZ(ModId::Pan, lastRegion->id)).sourceDepth = 1.0f;
ModKey::createCC(10, 1, defaultSmoothness, 0),
ModKey::createNXYZ(ModId::Pan, lastRegion->id)).sourceDepth = 100.0f;
//
auto parseOpcodes = [&](const std::vector<Opcode>& opcodes) {
@ -1522,7 +1522,18 @@ void sfz::Synth::setupModMatrix()
for (const Region::Connection& conn : region->connections) {
ModGenerator* gen = nullptr;
switch (conn.source.id()) {
ModKey sourceKey = conn.source;
ModKey targetKey = conn.target;
// normalize the stepcc to 0-1
if (sourceKey.id() == ModId::Controller) {
ModKey::Parameters p = sourceKey.parameters();
p.step = (conn.sourceDepth == 0.0f) ? 0.0f :
(p.step / conn.sourceDepth);
sourceKey = ModKey::createCC(p.cc, p.curve, p.smooth, p.step);
}
switch (sourceKey.id()) {
case ModId::Controller:
gen = genController.get();
break;
@ -1546,8 +1557,8 @@ void sfz::Synth::setupModMatrix()
if (!gen)
continue;
ModMatrix::SourceId source = mm.registerSource(conn.source, *gen);
ModMatrix::TargetId target = mm.registerTarget(conn.target);
ModMatrix::SourceId source = mm.registerSource(sourceKey, *gen);
ModMatrix::TargetId target = mm.registerTarget(targetKey);
ASSERT(source);
if (!source) {

View file

@ -30,13 +30,12 @@ ModKey::Parameters& ModKey::Parameters::operator=(const Parameters& other) noexc
return *this;
}
ModKey ModKey::createCC(uint16_t cc, uint8_t curve, uint8_t smooth, float value, float step)
ModKey ModKey::createCC(uint16_t cc, uint8_t curve, uint8_t smooth, float step)
{
ModKey::Parameters p;
p.cc = cc;
p.curve = curve;
p.smooth = smooth;
p.value = value;
p.step = step;
return ModKey(ModId::Controller, {}, p);
}
@ -69,7 +68,7 @@ std::string ModKey::toString() const
case ModId::Controller:
return absl::StrCat("Controller ", params_.cc,
" {curve=", params_.curve, ", smooth=", params_.smooth,
", value=", params_.value, ", step=", params_.step, "}");
", step=", params_.step, "}");
case ModId::Envelope:
return absl::StrCat("EG ", 1 + params_.N, " {", region_.number(), "}");
case ModId::LFO:

View file

@ -28,7 +28,7 @@ public:
explicit ModKey(ModId id, NumericId<Region> region = {}, Parameters params = {})
: id_(id), region_(region), params_(params), flags_(ModIds::flags(id_)) {}
static ModKey createCC(uint16_t cc, uint8_t curve, uint8_t smooth, float value, float step);
static ModKey createCC(uint16_t cc, uint8_t curve, uint8_t smooth, float step);
static ModKey createNXYZ(ModId id, NumericId<Region> region, uint8_t N = 0, uint8_t X = 0, uint8_t Y = 0, uint8_t Z = 0);
explicit operator bool() const noexcept { return id_ != ModId(); }
@ -62,7 +62,7 @@ public:
union {
//! Parameters if this key identifies a CC source
struct { uint16_t cc; uint8_t curve, smooth; float value, step; };
struct { uint16_t cc; uint8_t curve, smooth; float step; };
//! Parameters otherwise, based on the related opcode
// eg. `N` in `lfoN`, `N, X` in `lfoN_eqX`
struct { uint8_t N, X, Y, Z; };

View file

@ -20,7 +20,6 @@ size_t std::hash<sfz::ModKey>::operator()(const sfz::ModKey &key) const
k = hashNumber(p.cc, k);
k = hashNumber(p.curve, k);
k = hashNumber(p.smooth, k);
k = hashNumber(p.value, k);
k = hashNumber(p.step, k);
break;
default:

View file

@ -76,7 +76,7 @@ void ControllerSource::generate(const ModKey& sourceKey, NumericId<Voice> voiceI
const EventVector& events = ms.getCCEvents(p.cc);
auto transformValue = [p, &curve](float x) {
return curve.evalNormalized(x) * p.value;
return curve.evalNormalized(x);
};
if (p.step > 0.0f)

View file

@ -416,7 +416,7 @@ TEST_CASE("[Files] wrong (overlapping) replacement for defines")
const ModKey target = ModKey::createNXYZ(ModId::Amplitude, synth.getRegionView(2)->getId());
const RegionCCView view(*synth.getRegionView(2), target);
REQUIRE(!view.empty());
REQUIRE(view.at(10).value == 34.0f);
REQUIRE(view.valueAt(10) == 34.0f);
}
TEST_CASE("[Files] Specific bug: relative path with backslashes")

View file

@ -87,16 +87,16 @@ TEST_CASE("[Modulations] Connection graph from SFZ")
sample=*sine
amplitude_oncc20=59 amplitude_curvecc20=3
pitch_oncc42=71 pitch_smoothcc42=32
pan_oncc36=14.5 pan_stepcc36=1.5
pan_oncc36=12.5 pan_stepcc36=0.5
width_oncc425=29
)");
const std::string graph = synth.getResources().modMatrix.toDotGraph();
REQUIRE(graph == createDefaultGraph({
R"("Controller 20 {curve=3, smooth=0, value=59, step=0}" -> "Amplitude {0}")",
R"("Controller 42 {curve=0, smooth=32, value=71, step=0}" -> "Pitch {0}")",
R"("Controller 36 {curve=0, smooth=0, value=14.5, step=1.5}" -> "Pan {0}")",
R"("Controller 425 {curve=0, smooth=0, value=29, step=0}" -> "Width {0}")",
R"("Controller 20 {curve=3, smooth=0, step=0}" -> "Amplitude {0}")",
R"("Controller 42 {curve=0, smooth=32, step=0}" -> "Pitch {0}")",
R"("Controller 36 {curve=0, smooth=0, step=0.04}" -> "Pan {0}")",
R"("Controller 425 {curve=0, smooth=0, step=0}" -> "Width {0}")",
}));
}
@ -112,9 +112,9 @@ TEST_CASE("[Modulations] Filter CC connections")
const std::string graph = synth.getResources().modMatrix.toDotGraph();
REQUIRE(graph == createDefaultGraph({
R"("Controller 1 {curve=0, smooth=10, value=2, step=0}" -> "FilterResonance {0, N=3}")",
R"("Controller 2 {curve=2, smooth=0, value=100, step=0}" -> "FilterCutoff {0, N=2}")",
R"("Controller 3 {curve=0, smooth=0, value=5, step=0.5}" -> "FilterGain {0, N=1}")",
R"("Controller 1 {curve=0, smooth=10, step=0}" -> "FilterResonance {0, N=3}")",
R"("Controller 2 {curve=2, smooth=0, step=0}" -> "FilterCutoff {0, N=2}")",
R"("Controller 3 {curve=0, smooth=0, step=0.1}" -> "FilterGain {0, N=1}")",
}));
}
@ -130,9 +130,9 @@ TEST_CASE("[Modulations] EQ CC connections")
const std::string graph = synth.getResources().modMatrix.toDotGraph();
REQUIRE(graph == createDefaultGraph({
R"("Controller 1 {curve=0, smooth=10, value=2, step=0}" -> "EqBandwidth {0, N=3}")",
R"("Controller 2 {curve=0, smooth=0, value=5, step=0.5}" -> "EqGain {0, N=1}")",
R"("Controller 3 {curve=3, smooth=0, value=300, step=0}" -> "EqFrequency {0, N=2}")",
R"("Controller 1 {curve=0, smooth=10, step=0}" -> "EqBandwidth {0, N=3}")",
R"("Controller 2 {curve=0, smooth=0, step=0.1}" -> "EqGain {0, N=1}")",
R"("Controller 3 {curve=3, smooth=0, step=0}" -> "EqFrequency {0, N=2}")",
}));
}
@ -248,8 +248,8 @@ TEST_CASE("[Modulations] FlexEG Ampeg target")
const std::string graph = synth.getResources().modMatrix.toDotGraph();
REQUIRE(graph == createModulationDotGraph({
R"("Controller 10 {curve=1, smooth=10, value=100, step=0}" -> "Pan {0}")",
R"("Controller 7 {curve=4, smooth=10, value=100, step=0}" -> "Amplitude {0}")",
R"("Controller 10 {curve=1, smooth=10, step=0}" -> "Pan {0}")",
R"("Controller 7 {curve=4, smooth=10, step=0}" -> "Amplitude {0}")",
R"("EG 1 {0}" -> "MasterAmplitude {0}")",
}));
}
@ -272,8 +272,8 @@ TEST_CASE("[Modulations] FlexEG Ampeg target with 2 FlexEGs")
const std::string graph = synth.getResources().modMatrix.toDotGraph();
REQUIRE(graph == createModulationDotGraph({
R"("Controller 10 {curve=1, smooth=10, value=100, step=0}" -> "Pan {0}")",
R"("Controller 7 {curve=4, smooth=10, value=100, step=0}" -> "Amplitude {0}")",
R"("Controller 10 {curve=1, smooth=10, step=0}" -> "Pan {0}")",
R"("Controller 7 {curve=4, smooth=10, step=0}" -> "Amplitude {0}")",
R"("EG 2 {0}" -> "MasterAmplitude {0}")",
}));
}
@ -298,8 +298,8 @@ TEST_CASE("[Modulations] FlexEG Ampeg target with multiple EGs targeting ampeg")
const std::string graph = synth.getResources().modMatrix.toDotGraph();
REQUIRE(graph == createModulationDotGraph({
R"("Controller 10 {curve=1, smooth=10, value=100, step=0}" -> "Pan {0}")",
R"("Controller 7 {curve=4, smooth=10, value=100, step=0}" -> "Amplitude {0}")",
R"("Controller 10 {curve=1, smooth=10, step=0}" -> "Pan {0}")",
R"("Controller 7 {curve=4, smooth=10, step=0}" -> "Amplitude {0}")",
R"("EG 1 {0}" -> "MasterAmplitude {0}")",
}));
}

View file

@ -572,7 +572,7 @@ TEST_CASE("[Region] Parsing opcodes")
const RegionCCView view(region, target);
REQUIRE(view.empty());
region.parseOpcode({ "pan_oncc45", "4.2" });
REQUIRE(view.at(45).value == 4.2_a);
REQUIRE(view.valueAt(45) == 4.2_a);
region.parseOpcode({ "pan_curvecc17", "18" });
REQUIRE(view.at(17).curve == 18);
region.parseOpcode({ "pan_curvecc17", "15482" });
@ -612,7 +612,7 @@ TEST_CASE("[Region] Parsing opcodes")
const RegionCCView view(region, target);
REQUIRE(view.empty());
region.parseOpcode({ "width_oncc45", "4.2" });
REQUIRE(view.at(45).value == 4.2_a);
REQUIRE(view.valueAt(45) == 4.2_a);
region.parseOpcode({ "width_curvecc17", "18" });
REQUIRE(view.at(17).curve == 18);
region.parseOpcode({ "width_curvecc17", "15482" });
@ -652,7 +652,7 @@ TEST_CASE("[Region] Parsing opcodes")
const RegionCCView view(region, target);
REQUIRE(view.empty());
region.parseOpcode({ "position_oncc45", "4.2" });
REQUIRE(view.at(45).value == 4.2_a);
REQUIRE(view.valueAt(45) == 4.2_a);
region.parseOpcode({ "position_curvecc17", "18" });
REQUIRE(view.at(17).curve == 18);
region.parseOpcode({ "position_curvecc17", "15482" });
@ -1649,9 +1649,9 @@ TEST_CASE("[Region] Parsing opcodes")
const RegionCCView view(region, target);
REQUIRE(view.empty());
region.parseOpcode({ "amplitude_cc1", "40" });
REQUIRE(view.at(1).value == 40.0_a);
REQUIRE(view.valueAt(1) == 40.0_a);
region.parseOpcode({ "amplitude_oncc2", "30" });
REQUIRE(view.at(2).value == 30.0_a);
REQUIRE(view.valueAt(2) == 30.0_a);
region.parseOpcode({ "amplitude_curvecc17", "18" });
REQUIRE(view.at(17).curve == 18);
region.parseOpcode({ "amplitude_curvecc17", "15482" });
@ -1678,11 +1678,11 @@ TEST_CASE("[Region] Parsing opcodes")
const RegionCCView view(region, target);
REQUIRE(view.empty());
region.parseOpcode({ "gain_cc1", "40" });
REQUIRE(view.at(1).value == 40_a);
REQUIRE(view.valueAt(1) == 40_a);
region.parseOpcode({ "volume_oncc2", "-76" });
REQUIRE(view.at(2).value == -76.0_a);
REQUIRE(view.valueAt(2) == -76.0_a);
region.parseOpcode({ "gain_oncc4", "-1" });
REQUIRE(view.at(4).value == -1.0_a);
REQUIRE(view.valueAt(4) == -1.0_a);
region.parseOpcode({ "volume_curvecc17", "18" });
REQUIRE(view.at(17).curve == 18);
region.parseOpcode({ "volume_curvecc17", "15482" });
@ -1709,11 +1709,11 @@ TEST_CASE("[Region] Parsing opcodes")
const RegionCCView view(region, target);
REQUIRE(view.empty());
region.parseOpcode({ "pitch_cc1", "40" });
REQUIRE(view.at(1).value == 40.0);
REQUIRE(view.valueAt(1) == 40.0);
region.parseOpcode({ "tune_oncc2", "-76" });
REQUIRE(view.at(2).value == -76.0);
REQUIRE(view.valueAt(2) == -76.0);
region.parseOpcode({ "pitch_oncc4", "-1" });
REQUIRE(view.at(4).value == -1.0);
REQUIRE(view.valueAt(4) == -1.0);
region.parseOpcode({ "tune_curvecc17", "18" });
REQUIRE(view.at(17).curve == 18);
region.parseOpcode({ "pitch_curvecc17", "15482" });

View file

@ -35,6 +35,18 @@ sfz::ModKey::Parameters RegionCCView::at(int cc) const
throw std::out_of_range("Region CC");
}
float RegionCCView::valueAt(int cc) const
{
for (const sfz::Region::Connection& conn : region_.connections) {
if (match(conn)) {
const sfz::ModKey::Parameters p = conn.source.parameters();
if (p.cc == cc)
return conn.sourceDepth;
}
}
throw std::out_of_range("Region CC");
}
bool RegionCCView::match(const sfz::Region::Connection& conn) const
{
return conn.source.id() == sfz::ModId::Controller && conn.target == target_;
@ -76,12 +88,12 @@ std::string createDefaultGraph(std::vector<std::string> lines, int numRegions)
R"("AmplitudeEG {)", regionIdx, R"(}" -> "MasterAmplitude {)", regionIdx, R"(}")"
));
lines.push_back(absl::StrCat(
R"("Controller 7 {curve=4, smooth=10, value=100, step=0}" -> "Amplitude {)",
R"("Controller 7 {curve=4, smooth=10, step=0}" -> "Amplitude {)",
regionIdx,
R"(}")"
));
lines.push_back(absl::StrCat(
R"("Controller 10 {curve=1, smooth=10, value=100, step=0}" -> "Pan {)",
R"("Controller 10 {curve=1, smooth=10, step=0}" -> "Pan {)",
regionIdx,
R"(}")"
));

View file

@ -19,6 +19,7 @@ public:
size_t size() const;
bool empty() const;
sfz::ModKey::Parameters at(int cc) const;
float valueAt(int cc) const;
private:
bool match(const sfz::Region::Connection& conn) const;