Normalize percent values everywhere

This commit is contained in:
Jean Pierre Cimalando 2021-03-31 22:36:55 +02:00
parent 731c00d449
commit f4c7efeef5
13 changed files with 45 additions and 59 deletions

View file

@ -44,8 +44,8 @@ void ADSREnvelope::reset(const EGDescription& desc, const Region& region, const
this->decayRate = secondsToExpRate(desc.getDecay(state, velocity));
this->releaseRate = secondsToExpRate(desc.getRelease(state, velocity));
this->hold = secondsToSamples(desc.getHold(state, velocity));
this->sustain = normalizePercents(desc.getSustain(state, velocity));
this->start = normalizePercents(desc.getStart(state, velocity));
this->sustain = desc.getSustain(state, velocity);
this->start = desc.getStart(state, velocity);
releaseDelay = 0;
sustainThreshold = this->sustain + config::virtuallyZero;

View file

@ -74,13 +74,13 @@ UInt8Spec sequence { 1, {1, 100}, 0 };
FloatSpec volume { 0.0f, {-144.0f, 48.0f}, kPermissiveBounds };
FloatSpec volumeMod { 0.0f, {-144.0f, 48.0f}, kPermissiveBounds };
FloatSpec amplitude { 100.0f, {0.0f, 10000.0f}, kNormalizePercent|kPermissiveBounds };
FloatSpec amplitudeMod { 0.0f, {0.0f, 10000.0f}, kPermissiveBounds };
FloatSpec amplitudeMod { 0.0f, {0.0f, 10000.0f}, kNormalizePercent|kPermissiveBounds };
FloatSpec pan { 0.0f, {-100.0f, 100.0f}, kNormalizePercent|kPermissiveBounds };
FloatSpec panMod { 0.0f, {-200.0f, 200.0f}, kPermissiveBounds };
FloatSpec panMod { 0.0f, {-200.0f, 200.0f}, kNormalizePercent|kPermissiveBounds };
FloatSpec position { 0.0f, {-100.0f, 100.0f}, kNormalizePercent|kPermissiveBounds };
FloatSpec positionMod { 0.0f, {-200.0f, 200.0f}, kPermissiveBounds };
FloatSpec positionMod { 0.0f, {-200.0f, 200.0f}, kNormalizePercent|kPermissiveBounds };
FloatSpec width { 100.0f, {-100.0f, 100.0f}, kNormalizePercent|kPermissiveBounds };
FloatSpec widthMod { 0.0f, {-200.0f, 200.0f}, 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 ampVelcurve { 0.0f, {0.0f, 1.0f}, kPermissiveBounds };
@ -136,8 +136,9 @@ FloatSpec lfoScale { 1.0f, {0.0f, 1.0f}, kPermissiveBounds };
FloatSpec egTime { 0.0f, {0.0f, 100.0f}, kPermissiveBounds };
FloatSpec egRelease { 0.001f, {0.0f, 100.0f}, kPermissiveBounds };
FloatSpec egTimeMod { 0.0f, {-100.0f, 100.0f}, kPermissiveBounds };
FloatSpec egPercent { 0.0f, {0.0f, 100.0f}, kPermissiveBounds };
FloatSpec egPercentMod { 0.0f, {-100.0f, 100.0f}, kPermissiveBounds };
FloatSpec egSustain { 100.0f, {0.0f, 100.0f}, kNormalizePercent|kPermissiveBounds };
FloatSpec egPercent { 0.0f, {0.0f, 100.0f}, kNormalizePercent|kPermissiveBounds };
FloatSpec egPercentMod { 0.0f, {-100.0f, 100.0f}, kNormalizePercent|kPermissiveBounds };
FloatSpec egDepth { 0.0f, {-12000.0f, 12000.0f}, kPermissiveBounds };
FloatSpec egVel2Depth { 0.0f, {-12000.0f, 12000.0f}, kPermissiveBounds };
BoolSpec flexEGAmpeg { false, {0, 1}, kEnforceBounds };

View file

@ -240,6 +240,7 @@ namespace Default
extern const OpcodeSpec<float> egTime;
extern const OpcodeSpec<float> egRelease;
extern const OpcodeSpec<float> egTimeMod;
extern const OpcodeSpec<float> egSustain;
extern const OpcodeSpec<float> egPercent;
extern const OpcodeSpec<float> egPercentMod;
extern const OpcodeSpec<float> egDepth;

View file

@ -71,8 +71,8 @@ struct EGDescription {
float delay { Default::egTime };
float hold { Default::egTime };
float release { Default::egTime };
float start { Default::egPercent.bounds.getStart() };
float sustain { Default::egPercent.bounds.getEnd() };
float start { Default::egPercent };
float sustain { Default::egSustain };
float depth { Default::egDepth };
float vel2attack { Default::egTimeMod };
float vel2decay { Default::egTimeMod };

View file

@ -1513,10 +1513,8 @@ bool sfz::Region::processGenericCc(const Opcode& opcode, OpcodeSpec<float> spec,
break;
case kOpcodeStepCcN:
{
const float maxStep =
max(std::abs(spec.bounds.getStart()), std::abs(spec.bounds.getEnd()));
const OpcodeSpec<float> stepCC { 0.0f, Range<float>(0.0f, maxStep), 0 };
p.step = opcode.read(stepCC);
const OpcodeSpec<float> stepCC { 0.0f, {}, kPermissiveBounds };
p.step = spec.normalizeInput(opcode.read(stepCC));
}
break;
case kOpcodeSmoothCcN:

View file

@ -731,17 +731,17 @@ void Synth::Impl::finalizeSfzLoad()
if (!usedCCs.test(7)) {
region.getOrCreateConnection(
ModKey::createCC(7, 4, defaultSmoothness, 0),
ModKey::createNXYZ(ModId::Amplitude, region.id)).sourceDepth = 100.0f;
ModKey::createNXYZ(ModId::Amplitude, region.id)).sourceDepth = 1.0f;
}
if (!usedCCs.test(10)) {
region.getOrCreateConnection(
ModKey::createCC(10, 1, defaultSmoothness, 0),
ModKey::createNXYZ(ModId::Pan, region.id)).sourceDepth = 100.0f;
ModKey::createNXYZ(ModId::Pan, region.id)).sourceDepth = 1.0f;
}
if (!usedCCs.test(11)) {
region.getOrCreateConnection(
ModKey::createCC(11, 4, defaultSmoothness, 0),
ModKey::createNXYZ(ModId::Amplitude, region.id)).sourceDepth = 100.0f;
ModKey::createNXYZ(ModId::Amplitude, region.id)).sourceDepth = 1.0f;
}
}
@ -1699,7 +1699,7 @@ void Synth::Impl::setupModMatrix()
// 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 <= 0.0f) ? 0.0f :
(p.step / conn.sourceDepth);
sourceKey = ModKey::createCC(p.cc, p.curve, p.smooth, p.step);
}

View file

@ -516,7 +516,7 @@ void sfz::Synth::dispatchMessage(Client& client, int delay, const char* path, co
GET_REGION_OR_BREAK(indices[0])
auto value = region.ccModDepth(indices[1], ModId::Pan);
if (value) {
client.receive<'f'>(delay, path, *value);
client.receive<'f'>(delay, path, *value * 100.0f);
} else {
client.receive<'N'>(delay, path, {});
}
@ -526,7 +526,7 @@ void sfz::Synth::dispatchMessage(Client& client, int delay, const char* path, co
GET_REGION_OR_BREAK(indices[0])
auto params = region.ccModParameters(indices[1], ModId::Pan);
if (params) {
client.receive<'f'>(delay, path, params->step);
client.receive<'f'>(delay, path, params->step * 100.0f);
} else {
client.receive<'N'>(delay, path, {});
}
@ -561,7 +561,7 @@ void sfz::Synth::dispatchMessage(Client& client, int delay, const char* path, co
GET_REGION_OR_BREAK(indices[0])
auto value = region.ccModDepth(indices[1], ModId::Width);
if (value) {
client.receive<'f'>(delay, path, *value);
client.receive<'f'>(delay, path, *value * 100.0f);
} else {
client.receive<'N'>(delay, path, {});
}
@ -571,7 +571,7 @@ void sfz::Synth::dispatchMessage(Client& client, int delay, const char* path, co
GET_REGION_OR_BREAK(indices[0])
auto params = region.ccModParameters(indices[1], ModId::Width);
if (params) {
client.receive<'f'>(delay, path, params->step);
client.receive<'f'>(delay, path, params->step * 100.0f);
} else {
client.receive<'N'>(delay, path, {});
}
@ -606,7 +606,7 @@ void sfz::Synth::dispatchMessage(Client& client, int delay, const char* path, co
GET_REGION_OR_BREAK(indices[0])
auto value = region.ccModDepth(indices[1], ModId::Position);
if (value) {
client.receive<'f'>(delay, path, *value);
client.receive<'f'>(delay, path, *value * 100.0f);
} else {
client.receive<'N'>(delay, path, {});
}
@ -616,7 +616,7 @@ void sfz::Synth::dispatchMessage(Client& client, int delay, const char* path, co
GET_REGION_OR_BREAK(indices[0])
auto params = region.ccModParameters(indices[1], ModId::Position);
if (params) {
client.receive<'f'>(delay, path, params->step);
client.receive<'f'>(delay, path, params->step * 100.0f);
} else {
client.receive<'N'>(delay, path, {});
}
@ -651,7 +651,7 @@ void sfz::Synth::dispatchMessage(Client& client, int delay, const char* path, co
GET_REGION_OR_BREAK(indices[0])
auto value = region.ccModDepth(indices[1], ModId::Amplitude);
if (value) {
client.receive<'f'>(delay, path, *value);
client.receive<'f'>(delay, path, *value * 100.0f);
} else {
client.receive<'N'>(delay, path, {});
}
@ -661,7 +661,7 @@ void sfz::Synth::dispatchMessage(Client& client, int delay, const char* path, co
GET_REGION_OR_BREAK(indices[0])
auto params = region.ccModParameters(indices[1], ModId::Amplitude);
if (params) {
client.receive<'f'>(delay, path, params->step);
client.receive<'f'>(delay, path, params->step * 100.0f);
} else {
client.receive<'N'>(delay, path, {});
}
@ -943,12 +943,12 @@ void sfz::Synth::dispatchMessage(Client& client, int delay, const char* path, co
MATCH("/region&/ampeg_start", "") {
GET_REGION_OR_BREAK(indices[0])
client.receive<'f'>(delay, path, region.amplitudeEG.start);
client.receive<'f'>(delay, path, region.amplitudeEG.start * 100.0f);
} break;
MATCH("/region&/ampeg_sustain", "") {
GET_REGION_OR_BREAK(indices[0])
client.receive<'f'>(delay, path, region.amplitudeEG.sustain);
client.receive<'f'>(delay, path, region.amplitudeEG.sustain * 100.0f);
} break;
MATCH("/region&/ampeg_depth", "") {
@ -995,7 +995,7 @@ void sfz::Synth::dispatchMessage(Client& client, int delay, const char* path, co
GET_REGION_OR_BREAK(indices[0])
if (indices[1] != 2)
break;
client.receive<'f'>(delay, path, region.amplitudeEG.vel2sustain);
client.receive<'f'>(delay, path, region.amplitudeEG.vel2sustain * 100.0f);
} break;
MATCH("/region&/ampeg_vel&depth", "") {
@ -1152,13 +1152,13 @@ void sfz::Synth::dispatchMessage(Client& client, int delay, const char* path, co
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);
client.receive<'f'>(delay, path, value * 100.0f);
} 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);
client.receive<'f'>(delay, path, value * 100.0f);
} break;
#define GET_FILTER_OR_BREAK(idx) \

View file

@ -826,7 +826,7 @@ void Voice::Impl::amplitudeEnvelope(absl::Span<float> modulationSpan) noexcept
applyGain1<float>(baseGain_, modulationSpan);
if (float* mod = mm.getModulation(amplitudeTarget_)) {
for (size_t i = 0; i < numSamples; ++i)
modulationSpan[i] *= normalizePercents(mod[i]);
modulationSpan[i] *= mod[i];
}
// Volume envelope
@ -891,7 +891,7 @@ void Voice::Impl::panStageMono(AudioSpan<float> buffer) noexcept
fill(*modulationSpan, region_->pan);
if (float* mod = mm.getModulation(panTarget_)) {
for (size_t i = 0; i < numSamples; ++i)
(*modulationSpan)[i] += normalizePercents(mod[i]);
(*modulationSpan)[i] += mod[i];
}
pan(*modulationSpan, leftBuffer, rightBuffer);
}
@ -913,7 +913,7 @@ void Voice::Impl::panStageStereo(AudioSpan<float> buffer) noexcept
fill(*modulationSpan, region_->pan);
if (float* mod = mm.getModulation(panTarget_)) {
for (size_t i = 0; i < numSamples; ++i)
(*modulationSpan)[i] += normalizePercents(mod[i]);
(*modulationSpan)[i] += mod[i];
}
pan(*modulationSpan, leftBuffer, rightBuffer);
@ -921,14 +921,14 @@ void Voice::Impl::panStageStereo(AudioSpan<float> buffer) noexcept
fill(*modulationSpan, region_->width);
if (float* mod = mm.getModulation(widthTarget_)) {
for (size_t i = 0; i < numSamples; ++i)
(*modulationSpan)[i] += normalizePercents(mod[i]);
(*modulationSpan)[i] += mod[i];
}
width(*modulationSpan, leftBuffer, rightBuffer);
fill(*modulationSpan, region_->position);
if (float* mod = mm.getModulation(positionTarget_)) {
for (size_t i = 0; i < numSamples; ++i)
(*modulationSpan)[i] += normalizePercents(mod[i]);
(*modulationSpan)[i] += mod[i];
}
pan(*modulationSpan, leftBuffer, rightBuffer);
@ -1511,7 +1511,7 @@ void Voice::Impl::fillWithGenerator(AudioSpan<float> buffer) noexcept
applyGain1(oscillatorModDepth, *modulatorSpan);
const float* modDepthMod = resources_.modMatrix.getModulation(oscillatorModDepthTarget_);
if (modDepthMod)
multiplyMul1(0.01f, absl::MakeConstSpan(modDepthMod, numFrames), *modulatorSpan);
applyGain(absl::MakeConstSpan(modDepthMod, numFrames), *modulatorSpan);
// compute carrier×modulator
switch (region_->oscillatorMode) {

View file

@ -49,9 +49,9 @@ int ModIds::flags(ModId id) noexcept
// targets
case ModId::MasterAmplitude:
return kModIsPerVoice|kModIsPercentMultiplicative;
return kModIsPerVoice|kModIsMultiplicative;
case ModId::Amplitude:
return kModIsPerVoice|kModIsPercentMultiplicative;
return kModIsPerVoice|kModIsMultiplicative;
case ModId::Pan:
return kModIsPerVoice|kModIsAdditive;
case ModId::Width:
@ -77,7 +77,7 @@ int ModIds::flags(ModId id) noexcept
case ModId::OscillatorDetune:
return kModIsPerVoice|kModIsAdditive;
case ModId::OscillatorModDepth:
return kModIsPerVoice|kModIsPercentMultiplicative;
return kModIsPerVoice|kModIsMultiplicative;
case ModId::PitchEGDepth:
return kModIsPerVoice|kModIsAdditive;
case ModId::FilEGDepth:

View file

@ -85,8 +85,6 @@ enum ModFlags : int {
kModIsAdditive = 1 << 3,
//! This target is multiplicative (T)
kModIsMultiplicative = 1 << 4,
//! This target is %-multiplicative (T)
kModIsPercentMultiplicative = 1 << 5,
};
namespace ModIds {

View file

@ -438,14 +438,6 @@ float* ModMatrix::getModulation(TargetId targetId)
buffer[i] *= (sourceDepth + sourceDepthMod[i]) * sourceBuffer[i];
}
}
else if (targetFlags & kModIsPercentMultiplicative) {
if (!sourceDepthMod)
multiplyMul1<float>(0.01f * sourceDepth, sourceBuffer, buffer);
else {
for (uint32_t i = 0; i < numFrames; ++i)
buffer[i] *= 0.01f * (sourceDepth + sourceDepthMod[i]) * sourceBuffer[i];
}
}
else {
ASSERT(targetFlags & kModIsAdditive);
if (!sourceDepthMod)
@ -465,8 +457,6 @@ float* ModMatrix::getModulation(TargetId targetId)
if (isFirstSource) {
if (targetFlags & kModIsMultiplicative)
fill(buffer, 1.0f);
else if (targetFlags & kModIsPercentMultiplicative)
fill(buffer, 100.0f);
else {
ASSERT(targetFlags & kModIsAdditive);
fill(buffer, 0.0f);

View file

@ -378,7 +378,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.valueAt(10) == 34.0f);
REQUIRE(view.valueAt(10) == Approx(0.34f).margin(1e-3));
}
TEST_CASE("[Files] Specific bug: relative path with backslashes")

View file

@ -42,15 +42,13 @@ TEST_CASE("[Modulations] Flags")
{
checkBasicFlags(flags);
REQUIRE((bool(flags & sfz::kModIsAdditive) +
bool(flags & sfz::kModIsMultiplicative) +
bool(flags & sfz::kModIsPercentMultiplicative)) == 0);
bool(flags & sfz::kModIsMultiplicative)) == 0);
};
static auto* checkTargetFlags = +[](int flags)
{
checkBasicFlags(flags);
REQUIRE((bool(flags & sfz::kModIsAdditive) +
bool(flags & sfz::kModIsMultiplicative) +
bool(flags & sfz::kModIsPercentMultiplicative)) == 1);
bool(flags & sfz::kModIsMultiplicative)) == 1);
};
sfz::ModIds::forEachSourceId([](sfz::ModId id)
@ -385,7 +383,7 @@ TEST_CASE("[Modulations] LFO v1 CC connections")
REQUIRE(graph == createDefaultGraph({
R"("Controller 1 {curve=0, smooth=0, step=0}" -> "AmplitudeLFODepth {0}")",
R"("Controller 2 {curve=0, smooth=0, step=0}" -> "PitchLFODepth {1}")",
R"("Controller 3 {curve=0, smooth=0, step=-0}" -> "FilterLFODepth {2}")",
R"("Controller 3 {curve=0, smooth=0, step=0}" -> "FilterLFODepth {2}")",
R"("AmplitudeLFO {0}" -> "Volume {0}")",
R"("PitchLFO {1}" -> "Pitch {1}")",
R"("FilterLFO {2}" -> "FilterCutoff {2, N=1}")",
@ -403,7 +401,7 @@ TEST_CASE("[Modulations] EG v1 CC connections")
const std::string graph = synth.getResources().modMatrix.toDotGraph();
REQUIRE(graph == createDefaultGraph({
R"("Controller 2 {curve=0, smooth=0, step=0}" -> "PitchEGDepth {0}")",
R"("Controller 3 {curve=0, smooth=0, step=-0}" -> "FilterEGDepth {1}")",
R"("Controller 3 {curve=0, smooth=0, step=0}" -> "FilterEGDepth {1}")",
R"("PitchEG {0}" -> "Pitch {0}")",
R"("FilterEG {1}" -> "FilterCutoff {1, N=1}")",
}, 2));