Parse the relevant inputs

This commit is contained in:
Paul Fd 2021-06-29 10:48:53 +02:00
parent 6b1a7cd259
commit 5527282159
8 changed files with 215 additions and 28 deletions

View file

@ -90,6 +90,7 @@ FloatSpec width { 100.0f, {-100.0f, 100.0f}, kNormalizePercent|kPermissiveBounds
FloatSpec widthMod { 0.0f, {-200.0f, 200.0f}, kNormalizePercent|kPermissiveBounds };
FloatSpec ampKeytrack { 0.0f, {-96.0f, 12.0f}, kPermissiveBounds };
FloatSpec ampVeltrack { 100.0f, {-100.0f, 100.0f}, kNormalizePercent|kPermissiveBounds };
FloatSpec ampVeltrackMod { 0.0f, {-100.0f, 100.0f}, kNormalizePercent|kPermissiveBounds };
FloatSpec ampVelcurve { 0.0f, {0.0f, 1.0f}, kPermissiveBounds };
FloatSpec ampRandom { 0.0f, {-24.0f, 24.0f}, kPermissiveBounds };
BoolSpec rtDead { false, {false, true}, kEnforceBounds };
@ -103,6 +104,7 @@ FloatSpec filterGainMod { 0.0f, {-96.0f, 96.0f}, kPermissiveBounds };
FloatSpec filterRandom { 0.0f, {-12000.0f, 12000.0f}, kPermissiveBounds };
FloatSpec filterKeytrack { 0, {0, 1200}, kPermissiveBounds };
FloatSpec filterVeltrack { 0, {-12000, 12000}, kPermissiveBounds };
FloatSpec filterVeltrackMod { 0.0f, {-100.0f, 100.0f}, kNormalizePercent|kPermissiveBounds };
FloatSpec eqBandwidth { 1.0f, {0.001f, 4.0f}, kPermissiveBounds };
FloatSpec eqBandwidthMod { 0.0f, {-4.0f, 4.0f}, kPermissiveBounds };
FloatSpec eqFrequency { 0.0f, {0.0f, 20000.0f}, kPermissiveBounds };
@ -114,6 +116,7 @@ FloatSpec eqVel2Gain { 0.0f, {-96.0f, 96.0f}, kPermissiveBounds };
FloatSpec pitchKeytrack { 100, {-1200, 1200}, kPermissiveBounds };
FloatSpec pitchRandom { 0.0f, {-12000.0f, 12000.0f}, kPermissiveBounds };
FloatSpec pitchVeltrack { 0, {-12000, 12000}, kPermissiveBounds };
FloatSpec pitchVeltrackMod { 0.0f, {-100.0f, 100.0f}, kNormalizePercent|kPermissiveBounds };
FloatSpec transpose { 0, {-127, 127}, kPermissiveBounds };
FloatSpec pitch { 0.0f, {-2400.0f, 2400.0f}, kPermissiveBounds };
FloatSpec pitchMod { 0.0f, {-2400.0f, 2400.0f}, kPermissiveBounds };

View file

@ -202,6 +202,7 @@ namespace Default
extern const OpcodeSpec<float> widthMod;
extern const OpcodeSpec<float> ampKeytrack;
extern const OpcodeSpec<float> ampVeltrack;
extern const OpcodeSpec<float> ampVeltrackMod;
extern const OpcodeSpec<float> ampVelcurve;
extern const OpcodeSpec<float> ampRandom;
extern const OpcodeSpec<bool> rtDead;
@ -215,6 +216,7 @@ namespace Default
extern const OpcodeSpec<float> filterRandom;
extern const OpcodeSpec<float> filterKeytrack;
extern const OpcodeSpec<float> filterVeltrack;
extern const OpcodeSpec<float> filterVeltrackMod;
extern const OpcodeSpec<float> eqBandwidth;
extern const OpcodeSpec<float> eqBandwidthMod;
extern const OpcodeSpec<float> eqFrequency;
@ -226,6 +228,7 @@ namespace Default
extern const OpcodeSpec<float> pitchKeytrack;
extern const OpcodeSpec<float> pitchRandom;
extern const OpcodeSpec<float> pitchVeltrack;
extern const OpcodeSpec<float> pitchVeltrackMod;
extern const OpcodeSpec<float> transpose;
extern const OpcodeSpec<float> pitch;
extern const OpcodeSpec<float> pitchMod;

View file

@ -20,6 +20,7 @@ struct FilterDescription
float keytrack { Default::filterKeytrack };
uint8_t keycenter { Default::key };
float veltrack { Default::filterVeltrack };
CCMap<ModifierCurvePair<float>> veltrackCC { ModifierCurvePair<float>{ Default::filterVeltrackMod, Default::curveCC } };
float random { Default::filterRandom };
FilterType type { FilterType::kFilterLpf2p };
};

View file

@ -449,6 +449,18 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode, bool cleanOpcode)
case hash("amp_veltrack"):
ampVeltrack = opcode.read(Default::ampVeltrack);
break;
case hash("amp_veltrack_oncc&"):
if (opcode.parameters.back() >= config::numCCs)
return false;
ampVeltrackCC[opcode.parameters.back()].modifier = opcode.read(Default::ampVeltrackMod);
break;
case hash("amp_veltrack_curvecc&"):
if (opcode.parameters.back() >= config::numCCs)
return false;
ampVeltrackCC[opcode.parameters.back()].curve = opcode.read(Default::curveCC);
break;
case hash("amp_random"):
ampRandom = opcode.read(Default::ampRandom);
break;
@ -625,6 +637,32 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode, bool cleanOpcode)
filters[filterIndex].veltrack = opcode.read(Default::filterVeltrack);
}
break;
case hash("fil&_veltrack_oncc&"):
{
const auto filterIndex = opcode.parameters.front() - 1;
if (!extendIfNecessary(filters, filterIndex + 1, Default::numFilters))
return false;
const auto cc = opcode.parameters.back();
if (cc >= config::numCCs)
return false;
filters[filterIndex].veltrackCC[cc].modifier = opcode.read(Default::ampVeltrackMod);
}
break;
case hash("fil&_veltrack_curvecc&"):
{
const auto filterIndex = opcode.parameters.front() - 1;
if (!extendIfNecessary(filters, filterIndex + 1, Default::numFilters))
return false;
const auto cc = opcode.parameters.back();
if (cc >= config::numCCs)
return false;
filters[filterIndex].veltrackCC[cc].curve = opcode.read(Default::curveCC);
}
break;
case hash("fil&_random"): // also fil_random, cutoff_random, cutoff&_random
{
const auto filterIndex = opcode.parameters.front() - 1;
@ -755,6 +793,18 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode, bool cleanOpcode)
case hash("pitch_veltrack"):
pitchVeltrack = opcode.read(Default::pitchVeltrack);
break;
case hash("pitch_veltrack_oncc&"):
if (opcode.parameters.back() >= config::numCCs)
return false;
pitchVeltrackCC[opcode.parameters.back()].modifier = opcode.read(Default::pitchVeltrackMod);
break;
case hash("pitch_veltrack_curvecc&"):
if (opcode.parameters.back() >= config::numCCs)
return false;
pitchVeltrackCC[opcode.parameters.back()].curve = opcode.read(Default::curveCC);
break;
case hash("pitch_random"):
pitchRandom = opcode.read(Default::pitchRandom);
break;

View file

@ -384,6 +384,7 @@ struct Region {
uint8_t ampKeycenter { Default::key }; // amp_keycenter
float ampKeytrack { Default::ampKeytrack }; // amp_keytrack
float ampVeltrack { Default::ampVeltrack }; // amp_veltrack
CCMap<ModifierCurvePair<float>> ampVeltrackCC { ModifierCurvePair<float>{ Default::ampVeltrackMod, Default::curveCC } };
std::vector<std::pair<uint8_t, float>> velocityPoints; // amp_velcurve_N
absl::optional<Curve> velCurve {};
float ampRandom { Default::ampRandom }; // amp_random
@ -415,6 +416,7 @@ struct Region {
float pitchKeytrack { Default::pitchKeytrack }; // pitch_keytrack
float pitchRandom { Default::pitchRandom }; // pitch_random
float pitchVeltrack { Default::pitchVeltrack }; // pitch_veltrack
CCMap<ModifierCurvePair<float>> pitchVeltrackCC { ModifierCurvePair<float>{ Default::pitchVeltrackMod, Default::curveCC } };
float transpose { Default::transpose }; // transpose
float pitch { Default::pitch }; // tune
float bendUp { Default::bendUp };

View file

@ -22,6 +22,13 @@ namespace sfz {
using CCNamePair = std::pair<uint16_t, std::string>;
using NoteNamePair = std::pair<uint8_t, std::string>;
template<class T>
struct ModifierCurvePair
{
T modifier {};
uint8_t curve {};
};
template <class T>
using MidiNoteArray = std::array<T, 128>;
template <class ValueType>

View file

@ -782,6 +782,26 @@ void sfz::Synth::dispatchMessage(Client& client, int delay, const char* path, co
client.receive<'f'>(delay, path, region.ampVeltrack * 100.0f);
} break;
MATCH("/region&/amp_veltrack_cc&", "") {
GET_REGION_OR_BREAK(indices[0])
if (region.ampVeltrackCC.contains(indices[1])) {
const auto& cc = region.ampVeltrackCC.getWithDefault(indices[1]);
client.receive<'f'>(delay, path, cc.modifier * 100.0f);
} else {
client.receive<'N'>(delay, path, {});
}
} break;
MATCH("/region&/amp_veltrack_curvecc&", "") {
GET_REGION_OR_BREAK(indices[0])
if (region.ampVeltrackCC.contains(indices[1])) {
const auto& cc = region.ampVeltrackCC.getWithDefault(indices[1]);
client.receive<'i'>(delay, path, cc.curve );
} else {
client.receive<'N'>(delay, path, {});
}
} break;
MATCH("/region&/amp_random", "") {
GET_REGION_OR_BREAK(indices[0])
client.receive<'f'>(delay, path, region.ampRandom);
@ -921,6 +941,26 @@ void sfz::Synth::dispatchMessage(Client& client, int delay, const char* path, co
client.receive<'i'>(delay, path, region.pitchVeltrack);
} break;
MATCH("/region&/pitch_veltrack_cc&", "") {
GET_REGION_OR_BREAK(indices[0])
if (region.pitchVeltrackCC.contains(indices[1])) {
const auto& cc = region.pitchVeltrackCC.getWithDefault(indices[1]);
client.receive<'f'>(delay, path, cc.modifier * 100.0f);
} else {
client.receive<'N'>(delay, path, {});
}
} break;
MATCH("/region&/pitch_veltrack_curvecc&", "") {
GET_REGION_OR_BREAK(indices[0])
if (region.pitchVeltrackCC.contains(indices[1])) {
const auto& cc = region.pitchVeltrackCC.getWithDefault(indices[1]);
client.receive<'i'>(delay, path, cc.curve );
} else {
client.receive<'N'>(delay, path, {});
}
} break;
MATCH("/region&/pitch_random", "") {
GET_REGION_OR_BREAK(indices[0])
client.receive<'f'>(delay, path, region.pitchRandom);
@ -1277,6 +1317,28 @@ void sfz::Synth::dispatchMessage(Client& client, int delay, const char* path, co
client.receive<'i'>(delay, path, filter.veltrack);
} break;
MATCH("/region&/filter&/veltrack_cc&", "") {
GET_REGION_OR_BREAK(indices[0])
GET_FILTER_OR_BREAK(indices[1])
if (filter.veltrackCC.contains(indices[2])) {
const auto& cc = filter.veltrackCC.getWithDefault(indices[2]);
client.receive<'f'>(delay, path, cc.modifier * 100.0f);
} else {
client.receive<'N'>(delay, path, {});
}
} break;
MATCH("/region&/filter&/veltrack_curvecc&", "") {
GET_REGION_OR_BREAK(indices[0])
GET_FILTER_OR_BREAK(indices[1])
if (filter.veltrackCC.contains(indices[2])) {
const auto& cc = filter.veltrackCC.getWithDefault(indices[2]);
client.receive<'i'>(delay, path, cc.curve );
} else {
client.receive<'N'>(delay, path, {});
}
} break;
MATCH("/region&/filter&/type", "") {
GET_REGION_OR_BREAK(indices[0])
GET_FILTER_OR_BREAK(indices[1])

View file

@ -1629,20 +1629,47 @@ TEST_CASE("[Values] Amp Veltrack")
Client client(&messageList);
client.setReceiveCallback(&simpleMessageReceiver);
synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"(
<region> sample=kick.wav
<region> sample=kick.wav amp_veltrack=10.1
<region> sample=kick.wav amp_veltrack=-132
)");
synth.dispatchMessage(client, 0, "/region0/amp_veltrack", "", nullptr);
synth.dispatchMessage(client, 0, "/region1/amp_veltrack", "", nullptr);
synth.dispatchMessage(client, 0, "/region2/amp_veltrack", "", nullptr);
std::vector<std::string> expected {
"/region0/amp_veltrack,f : { 100 }",
"/region1/amp_veltrack,f : { 10.1 }",
"/region2/amp_veltrack,f : { -132 }",
};
REQUIRE(messageList == expected);
SECTION("Basic")
{
synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"(
<region> sample=kick.wav
<region> sample=kick.wav amp_veltrack=10.1
<region> sample=kick.wav amp_veltrack=-132
)");
synth.dispatchMessage(client, 0, "/region0/amp_veltrack", "", nullptr);
synth.dispatchMessage(client, 0, "/region1/amp_veltrack", "", nullptr);
synth.dispatchMessage(client, 0, "/region2/amp_veltrack", "", nullptr);
std::vector<std::string> expected {
"/region0/amp_veltrack,f : { 100 }",
"/region1/amp_veltrack,f : { 10.1 }",
"/region2/amp_veltrack,f : { -132 }",
};
REQUIRE(messageList == expected);
}
SECTION("CC")
{
synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"(
<region> sample=kick.wav
<region> sample=kick.wav amp_veltrack_cc1=10.1 amp_veltrack_curvecc1=3
<region> sample=kick.wav amp_veltrack_oncc2=-40 amp_veltrack_curvecc3=4
)");
synth.dispatchMessage(client, 0, "/region0/amp_veltrack_cc1", "", nullptr);
synth.dispatchMessage(client, 0, "/region1/amp_veltrack_cc1", "", nullptr);
synth.dispatchMessage(client, 0, "/region1/amp_veltrack_curvecc1", "", nullptr);
synth.dispatchMessage(client, 0, "/region2/amp_veltrack_cc2", "", nullptr);
synth.dispatchMessage(client, 0, "/region2/amp_veltrack_curvecc3", "", nullptr);
// TODO: activate for the new region parser ; accept oob
// synth.dispatchMessage(client, 0, "/region2/amp_veltrack", "", nullptr);
std::vector<std::string> expected {
"/region0/amp_veltrack_cc1,N : { }",
"/region1/amp_veltrack_cc1,f : { 10.1 }",
"/region1/amp_veltrack_curvecc1,i : { 3 }",
"/region2/amp_veltrack_cc2,f : { -40 }",
"/region2/amp_veltrack_curvecc3,i : { 4 }",
};
REQUIRE(messageList == expected);
}
}
TEST_CASE("[Values] Amp Random")
@ -1987,20 +2014,47 @@ TEST_CASE("[Values] Pitch Veltrack")
Client client(&messageList);
client.setReceiveCallback(&simpleMessageReceiver);
synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"(
<region> sample=kick.wav
<region> sample=kick.wav pitch_veltrack=10
<region> sample=kick.wav pitch_veltrack=-132
)");
synth.dispatchMessage(client, 0, "/region0/pitch_veltrack", "", nullptr);
synth.dispatchMessage(client, 0, "/region1/pitch_veltrack", "", nullptr);
synth.dispatchMessage(client, 0, "/region2/pitch_veltrack", "", nullptr);
std::vector<std::string> expected {
"/region0/pitch_veltrack,i : { 0 }",
"/region1/pitch_veltrack,i : { 10 }",
"/region2/pitch_veltrack,i : { -132 }",
};
REQUIRE(messageList == expected);
SECTION("Basic")
{
synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"(
<region> sample=kick.wav
<region> sample=kick.wav pitch_veltrack=10
<region> sample=kick.wav pitch_veltrack=-132
)");
synth.dispatchMessage(client, 0, "/region0/pitch_veltrack", "", nullptr);
synth.dispatchMessage(client, 0, "/region1/pitch_veltrack", "", nullptr);
synth.dispatchMessage(client, 0, "/region2/pitch_veltrack", "", nullptr);
std::vector<std::string> expected {
"/region0/pitch_veltrack,i : { 0 }",
"/region1/pitch_veltrack,i : { 10 }",
"/region2/pitch_veltrack,i : { -132 }",
};
REQUIRE(messageList == expected);
}
SECTION("CC")
{
synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"(
<region> sample=kick.wav
<region> sample=kick.wav pitch_veltrack_cc1=10.1 pitch_veltrack_curvecc1=3
<region> sample=kick.wav pitch_veltrack_oncc2=-40 pitch_veltrack_curvecc3=4
)");
synth.dispatchMessage(client, 0, "/region0/pitch_veltrack_cc1", "", nullptr);
synth.dispatchMessage(client, 0, "/region1/pitch_veltrack_cc1", "", nullptr);
synth.dispatchMessage(client, 0, "/region1/pitch_veltrack_curvecc1", "", nullptr);
synth.dispatchMessage(client, 0, "/region2/pitch_veltrack_cc2", "", nullptr);
synth.dispatchMessage(client, 0, "/region2/pitch_veltrack_curvecc3", "", nullptr);
// TODO: activate for the new region parser ; accept oob
// synth.dispatchMessage(client, 0, "/region2/pitch_veltrack", "", nullptr);
std::vector<std::string> expected {
"/region0/pitch_veltrack_cc1,N : { }",
"/region1/pitch_veltrack_cc1,f : { 10.1 }",
"/region1/pitch_veltrack_curvecc1,i : { 3 }",
"/region2/pitch_veltrack_cc2,f : { -40 }",
"/region2/pitch_veltrack_curvecc3,i : { 4 }",
};
REQUIRE(messageList == expected);
}
}
TEST_CASE("[Values] Pitch Random")
@ -2992,6 +3046,7 @@ TEST_CASE("[Values] Filter dispatching")
<region> sample=kick.wav
cutoff3=50 resonance2=3 fil2_gain=-5 fil3_keytrack=100
fil_gain=5 fil1_gain=-5 fil2_veltrack=-100
fil4_veltrack_cc7=-100 fil5_veltrack_curvecc2=2
)");
synth.dispatchMessage(client, 0, "/region0/filter2/cutoff", "", nullptr);
@ -3000,6 +3055,8 @@ TEST_CASE("[Values] Filter dispatching")
synth.dispatchMessage(client, 0, "/region0/filter2/keytrack", "", nullptr);
synth.dispatchMessage(client, 0, "/region0/filter0/gain", "", nullptr);
synth.dispatchMessage(client, 0, "/region0/filter1/veltrack", "", nullptr);
synth.dispatchMessage(client, 0, "/region0/filter3/veltrack_cc7", "", nullptr);
synth.dispatchMessage(client, 0, "/region0/filter4/veltrack_curvecc2", "", nullptr);
std::vector<std::string> expected {
"/region0/filter2/cutoff,f : { 50 }",
"/region0/filter1/resonance,f : { 3 }",
@ -3007,6 +3064,8 @@ TEST_CASE("[Values] Filter dispatching")
"/region0/filter2/keytrack,i : { 100 }",
"/region0/filter0/gain,f : { -5 }",
"/region0/filter1/veltrack,i : { -100 }",
"/region0/filter3/veltrack_cc7,f : { -100 }",
"/region0/filter4/veltrack_curvecc2,i : { 2 }",
};
REQUIRE(messageList == expected);
}