Merge pull request #371 from jpcima/amp-veltrack

Fix amp_veltrack
This commit is contained in:
JP Cimalando 2020-08-18 00:44:51 +02:00 committed by GitHub
commit da23ab281a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 101 additions and 31 deletions

View file

@ -432,7 +432,8 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode)
setValueFromOpcode(opcode, ampKeytrack, Default::ampKeytrackRange);
break;
case hash("amp_veltrack"):
setValueFromOpcode(opcode, ampVeltrack, Default::ampVeltrackRange);
if (auto value = readOpcode(opcode.value, Default::ampVeltrackRange))
ampVeltrack = normalizePercents(*value);
break;
case hash("amp_random"):
setValueFromOpcode(opcode, ampRandom, Default::ampRandomRange);
@ -1517,19 +1518,14 @@ float sfz::Region::velocityCurve(float velocity) const noexcept
{
ASSERT(velocity >= 0.0f && velocity <= 1.0f);
float gain { 1.0f };
if (velCurve) { // Custom velocity curve
return velCurve->evalNormalized(velocity);
} else { // Standard velocity curve
// FIXME: Maybe there's a prettier way to check the boundaries?
const float gaindB = [&]() {
if (ampVeltrack >= 0)
return velocity == 0.0f ? -90.0f : 40 * std::log(velocity) / std::log(10.0f);
else
return velocity == 1.0f ? -90.0f : 40 * std::log(1 - velocity) / std::log(10.0f);
}();
gain *= db2mag( gaindB * std::abs(ampVeltrack) / sfz::Default::ampVeltrackRange.getEnd());
}
float gain;
if (velCurve)
gain = velCurve->evalNormalized(velocity);
else
gain = velocity * velocity;
gain = std::fabs(ampVeltrack) * (1.0f - gain);
gain = (ampVeltrack < 0) ? gain : (1.0f - gain);
return gain;
}

View file

@ -331,7 +331,7 @@ struct Region {
float position { normalizePercents(Default::position) }; // position
uint8_t ampKeycenter { Default::ampKeycenter }; // amp_keycenter
float ampKeytrack { Default::ampKeytrack }; // amp_keytrack
float ampVeltrack { Default::ampVeltrack }; // amp_keytrack
float ampVeltrack { normalizePercents(Default::ampVeltrack) }; // amp_keytrack
std::vector<std::pair<uint8_t, float>> velocityPoints; // amp_velcurve_N
absl::optional<Curve> velCurve {};
float ampRandom { Default::ampRandom }; // amp_random

View file

@ -568,7 +568,8 @@ void sfz::Synth::finalizeSfzLoad()
if (!region->velocityPoints.empty())
region->velCurve = Curve::buildFromVelcurvePoints(
region->velocityPoints, Curve::Interpolator::Linear, region->ampVeltrack < 0.0f);
region->velocityPoints, Curve::Interpolator::Linear);
region->registerPitchWheel(0);
region->registerAftertouch(0);
region->registerTempo(2.0f);

View file

@ -692,15 +692,15 @@ TEST_CASE("[Region] Parsing opcodes")
SECTION("amp_veltrack")
{
REQUIRE(region.ampVeltrack == 100.0f);
REQUIRE(region.ampVeltrack == 1.0f);
region.parseOpcode({ "amp_veltrack", "4.2" });
REQUIRE(region.ampVeltrack == 4.2f);
REQUIRE(region.ampVeltrack == Approx(0.042f));
region.parseOpcode({ "amp_veltrack", "-4.2" });
REQUIRE(region.ampVeltrack == -4.2f);
REQUIRE(region.ampVeltrack == Approx(-0.042f));
region.parseOpcode({ "amp_veltrack", "-123" });
REQUIRE(region.ampVeltrack == -100.0f);
REQUIRE(region.ampVeltrack == -1.0f);
region.parseOpcode({ "amp_veltrack", "132" });
REQUIRE(region.ampVeltrack == 100.0f);
REQUIRE(region.ampVeltrack == 1.0f);
}
SECTION("amp_random")

View file

@ -448,16 +448,89 @@ TEST_CASE("[Synth] velcurve")
<region> amp_velcurve_064=1 sample=*sine
<region> amp_velcurve_064=1 amp_veltrack=-100 sample=*sine
)");
REQUIRE( synth.getRegionView(0)->velocityCurve(0_norm) == 0.0_a );
REQUIRE( synth.getRegionView(0)->velocityCurve(32_norm) == Approx(0.5f).margin(1e-2) );
REQUIRE( synth.getRegionView(0)->velocityCurve(64_norm) == 1.0_a );
REQUIRE( synth.getRegionView(0)->velocityCurve(96_norm) == 1.0_a );
REQUIRE( synth.getRegionView(0)->velocityCurve(127_norm) == 1.0_a );
REQUIRE( synth.getRegionView(1)->velocityCurve(0_norm) == 1.0_a );
REQUIRE( synth.getRegionView(1)->velocityCurve(32_norm) == 1.0_a );
REQUIRE( synth.getRegionView(1)->velocityCurve(64_norm) == 1.0_a );
REQUIRE( synth.getRegionView(1)->velocityCurve(96_norm) == Approx(0.5f).margin(1e-2) );
REQUIRE( synth.getRegionView(1)->velocityCurve(127_norm) == 0.0_a );
struct VelocityData { float velocity, gain; bool exact; };
static const VelocityData veldata[] = {
{ 0_norm, 0.0, true },
{ 32_norm, 0.5f, false },
{ 64_norm, 1.0, true },
{ 96_norm, 1.0, true },
{ 127_norm, 1.0, true },
};
REQUIRE(synth.getNumRegions() == 2);
const sfz::Region* r1 = synth.getRegionView(0);
const sfz::Region* r2 = synth.getRegionView(1);
for (const VelocityData& vd : veldata) {
if (vd.exact) {
REQUIRE(r1->velocityCurve(vd.velocity) == vd.gain);
REQUIRE(r2->velocityCurve(vd.velocity) == 1.0f - vd.gain);
}
else {
REQUIRE(r1->velocityCurve(vd.velocity) == Approx(vd.gain).margin(1e-2));
REQUIRE(r2->velocityCurve(vd.velocity) == Approx(1.0f - vd.gain).margin(1e-2));
}
}
}
TEST_CASE("[Synth] veltrack")
{
struct VelocityData { float velocity, dBGain; };
struct VeltrackData { float veltrack; absl::Span<const VelocityData> veldata; };
// measured on ARIA
const VelocityData veldata25[] = {
{ 127_norm, 0.0 },
{ 96_norm, -1 },
{ 64_norm, -1.8 },
{ 32_norm, -2.3 },
{ 1_norm, -2.5 },
};
const VelocityData veldata50[] = {
{ 127_norm, 0.0 },
{ 96_norm, -2.1 },
{ 64_norm, -4.1 },
{ 32_norm, -5.5 },
{ 1_norm, -6.0 },
};
const VelocityData veldata75[] = {
{ 127_norm, 0.0 },
{ 96_norm, -3.4 },
{ 64_norm, -7.2 },
{ 32_norm, -10.5 },
{ 1_norm, -12.0 },
};
const VelocityData veldata100[] = {
{ 127_norm, 0.0 },
{ 96_norm, -4.9 },
{ 64_norm, -12.0 },
{ 32_norm, -24.0 },
{ 1_norm, -84.1 },
};
const VeltrackData veltrackdata[] = {
{ 25, veldata25 },
{ 50, veldata50 },
{ 75, veldata75 },
{ 100, veldata100 },
};
for (const VeltrackData& vt : veltrackdata) {
sfz::Synth synth;
const std::string sfzCode = "<region>sample=*sine amp_veltrack=" +
std::to_string(vt.veltrack);
synth.loadSfzString(fs::current_path() / "tests/TestFiles/veltrack.sfz", sfzCode);
REQUIRE(synth.getNumRegions() == 1);
const sfz::Region* r = synth.getRegionView(0);
for (const VelocityData& vd : vt.veldata) {
float dBGain = 20.0f * std::log10(r->velocityCurve(vd.velocity));
REQUIRE(dBGain == Approx(vd.dBGain).margin(0.1));
}
}
}
TEST_CASE("[Synth] Region by identifier")