Added sustain_sw; sostenuto_sw is parsed but not treated in code

This commit is contained in:
paulfd 2019-09-13 20:46:35 +02:00
parent 965321166c
commit ebd2b1906a
7 changed files with 60 additions and 6 deletions

View file

@ -31,7 +31,8 @@ namespace config {
constexpr int preloadSize { 8192 };
constexpr int numChannels { 2 };
constexpr int numVoices { 64 };
constexpr int numLoadingThreads { 4 };
constexpr int sustainCC { 64 };
constexpr int halfCCThreshold { 64 };
constexpr int centPerSemitone { 100 };
constexpr float virtuallyZero { 0.00005f };
constexpr float fastReleaseDuration { 0.01 };

View file

@ -142,5 +142,9 @@ namespace Default
inline constexpr Range<int> egDepthRange { -12000, 12000 };
inline constexpr Range<float> egOnCCTimeRange { -100.0, 100.0 };
inline constexpr Range<float> egOnCCPercentRange { -100.0, 100.0 };
// ***** SFZ v2 ********
inline constexpr bool checkSustain { true }; // sustain_sw
inline constexpr bool checkSostenuto { true }; // sostenuto_sw
}
}

View file

@ -26,6 +26,7 @@
#include "LeakDetector.h"
#include "Range.h"
#include "SfzHelpers.h"
#include "StringViewHelpers.h"
#include <optional>
#include <string_view>
@ -48,8 +49,12 @@ inline std::optional<ValueType> readOpcode(std::string_view value, const Range<V
{
if constexpr (std::is_integral<ValueType>::value) {
int64_t returnedValue;
if (!absl::SimpleAtoi(value, &returnedValue))
return {};
if (!absl::SimpleAtoi(value, &returnedValue)) {
float floatValue;
if (!absl::SimpleAtof(value, &floatValue))
return {};
returnedValue = static_cast<int64_t>(floatValue);
}
if (returnedValue > std::numeric_limits<ValueType>::max())
returnedValue = std::numeric_limits<ValueType>::max();
@ -66,6 +71,18 @@ inline std::optional<ValueType> readOpcode(std::string_view value, const Range<V
}
}
inline std::optional<bool> readBooleanFromOpcode(const Opcode& opcode)
{
switch (hash(opcode.value)) {
case hash("off"):
return false;
case hash("on"):
return true;
default:
return {};
}
}
template <class ValueType>
inline void setValueFromOpcode(const Opcode& opcode, ValueType& target, const Range<ValueType>& validRange)
{

View file

@ -22,8 +22,10 @@
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "Region.h"
#include "Defaults.h"
#include "MathHelpers.h"
#include "Debug.h"
#include "Opcode.h"
#include "StringViewHelpers.h"
#include "absl/strings/str_replace.h"
#include <random>
@ -183,6 +185,13 @@ bool sfz::Region::parseOpcode(const Opcode& opcode)
DBG("Unknown velocity mode: " << std::string(opcode.value));
}
break;
case hash("sustain_sw"):
checkSustain = readBooleanFromOpcode(opcode).value_or(Default::checkSustain);
break;
case hash("sostenuto_sw"):
checkSostenuto = readBooleanFromOpcode(opcode).value_or(Default::checkSostenuto);
break;
// Region logic: internal conditions
case hash("lochanaft"):
setRangeStartFromOpcode(opcode, aftertouchRange, Default::aftertouchRange);

View file

@ -96,6 +96,8 @@ struct Region {
std::optional<uint8_t> keyswitchDown {}; // sw_down
std::optional<uint8_t> previousNote {}; // sw_previous
SfzVelocityOverride velocityOverride { Default::velocityOverride }; // sw_vel
bool checkSustain { Default::checkSustain }; // sustain_sw
bool checkSostenuto { Default::checkSostenuto }; // sostenuto_sw
// Region logic: internal conditions
Range<uint8_t> aftertouchRange { Default::aftertouchRange }; // hichanaft and lochanaft

View file

@ -23,6 +23,7 @@
#include "Voice.h"
#include "AudioSpan.h"
#include "Config.h"
#include "Defaults.h"
#include "MathHelpers.h"
#include "SIMDHelpers.h"
@ -94,6 +95,7 @@ void sfz::Voice::startVoice(Region* region, int delay, int channel, int number,
sourcePosition = region->getOffset();
floatPosition = static_cast<float>(sourcePosition);
DBG("Offset: " << floatPosition);
initialDelay = delay + region->getDelay();
baseFrequency = midiNoteFrequency(number) * pitchRatio;
prepareEGEnvelope(delay, value);
@ -151,9 +153,8 @@ void sfz::Voice::registerNoteOff(int delay, int channel, int noteNumber, uint8_t
if (region->loopMode == SfzLoopMode::one_shot)
return;
if (ccState[64] < 63) {
if (!region->checkSustain || ccState[config::sustainCC] < config::halfCCThreshold)
release(delay);
}
}
}
@ -162,7 +163,7 @@ void sfz::Voice::registerCC(int delay, int channel [[maybe_unused]], int ccNumbe
if (region == nullptr)
return;
if (ccNumber == 64 && noteIsOff && ccValue < 63)
if (ccNumber == config::sustainCC && noteIsOff && ccValue < config::halfCCThreshold)
release(delay);
if (region->amplitudeCC && ccNumber == region->amplitudeCC->first) {

View file

@ -1011,6 +1011,26 @@ TEST_CASE("[Region] Parsing opcodes")
REQUIRE(region.amplitudeEG.ccStart->second == -100.0f);
REQUIRE(region.amplitudeEG.ccSustain->second == -100.0f);
}
SECTION("sustain_sw and sostenuto_sw")
{
REQUIRE(region.checkSustain);
REQUIRE(region.checkSostenuto);
region.parseOpcode({ "sustain_sw", "off" });
REQUIRE(!region.checkSustain);
region.parseOpcode({ "sustain_sw", "on" });
REQUIRE(region.checkSustain);
region.parseOpcode({ "sustain_sw", "off" });
region.parseOpcode({ "sustain_sw", "obladi" });
REQUIRE(region.checkSustain);
region.parseOpcode({ "sostenuto_sw", "off" });
REQUIRE(!region.checkSostenuto);
region.parseOpcode({ "sostenuto_sw", "on" });
REQUIRE(region.checkSostenuto);
region.parseOpcode({ "sostenuto_sw", "off" });
region.parseOpcode({ "sostenuto_sw", "obladi" });
REQUIRE(region.checkSostenuto);
}
}
// Specific region bugs