Added sustain_sw; sostenuto_sw is parsed but not treated in code
This commit is contained in:
parent
965321166c
commit
ebd2b1906a
7 changed files with 60 additions and 6 deletions
|
|
@ -31,7 +31,8 @@ namespace config {
|
||||||
constexpr int preloadSize { 8192 };
|
constexpr int preloadSize { 8192 };
|
||||||
constexpr int numChannels { 2 };
|
constexpr int numChannels { 2 };
|
||||||
constexpr int numVoices { 64 };
|
constexpr int numVoices { 64 };
|
||||||
constexpr int numLoadingThreads { 4 };
|
constexpr int sustainCC { 64 };
|
||||||
|
constexpr int halfCCThreshold { 64 };
|
||||||
constexpr int centPerSemitone { 100 };
|
constexpr int centPerSemitone { 100 };
|
||||||
constexpr float virtuallyZero { 0.00005f };
|
constexpr float virtuallyZero { 0.00005f };
|
||||||
constexpr float fastReleaseDuration { 0.01 };
|
constexpr float fastReleaseDuration { 0.01 };
|
||||||
|
|
|
||||||
|
|
@ -142,5 +142,9 @@ namespace Default
|
||||||
inline constexpr Range<int> egDepthRange { -12000, 12000 };
|
inline constexpr Range<int> egDepthRange { -12000, 12000 };
|
||||||
inline constexpr Range<float> egOnCCTimeRange { -100.0, 100.0 };
|
inline constexpr Range<float> egOnCCTimeRange { -100.0, 100.0 };
|
||||||
inline constexpr Range<float> egOnCCPercentRange { -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -26,6 +26,7 @@
|
||||||
#include "LeakDetector.h"
|
#include "LeakDetector.h"
|
||||||
#include "Range.h"
|
#include "Range.h"
|
||||||
#include "SfzHelpers.h"
|
#include "SfzHelpers.h"
|
||||||
|
#include "StringViewHelpers.h"
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <string_view>
|
#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) {
|
if constexpr (std::is_integral<ValueType>::value) {
|
||||||
int64_t returnedValue;
|
int64_t returnedValue;
|
||||||
if (!absl::SimpleAtoi(value, &returnedValue))
|
if (!absl::SimpleAtoi(value, &returnedValue)) {
|
||||||
return {};
|
float floatValue;
|
||||||
|
if (!absl::SimpleAtof(value, &floatValue))
|
||||||
|
return {};
|
||||||
|
returnedValue = static_cast<int64_t>(floatValue);
|
||||||
|
}
|
||||||
|
|
||||||
if (returnedValue > std::numeric_limits<ValueType>::max())
|
if (returnedValue > std::numeric_limits<ValueType>::max())
|
||||||
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>
|
template <class ValueType>
|
||||||
inline void setValueFromOpcode(const Opcode& opcode, ValueType& target, const Range<ValueType>& validRange)
|
inline void setValueFromOpcode(const Opcode& opcode, ValueType& target, const Range<ValueType>& validRange)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -22,8 +22,10 @@
|
||||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
#include "Region.h"
|
#include "Region.h"
|
||||||
|
#include "Defaults.h"
|
||||||
#include "MathHelpers.h"
|
#include "MathHelpers.h"
|
||||||
#include "Debug.h"
|
#include "Debug.h"
|
||||||
|
#include "Opcode.h"
|
||||||
#include "StringViewHelpers.h"
|
#include "StringViewHelpers.h"
|
||||||
#include "absl/strings/str_replace.h"
|
#include "absl/strings/str_replace.h"
|
||||||
#include <random>
|
#include <random>
|
||||||
|
|
@ -183,6 +185,13 @@ bool sfz::Region::parseOpcode(const Opcode& opcode)
|
||||||
DBG("Unknown velocity mode: " << std::string(opcode.value));
|
DBG("Unknown velocity mode: " << std::string(opcode.value));
|
||||||
}
|
}
|
||||||
break;
|
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
|
// Region logic: internal conditions
|
||||||
case hash("lochanaft"):
|
case hash("lochanaft"):
|
||||||
setRangeStartFromOpcode(opcode, aftertouchRange, Default::aftertouchRange);
|
setRangeStartFromOpcode(opcode, aftertouchRange, Default::aftertouchRange);
|
||||||
|
|
|
||||||
|
|
@ -96,6 +96,8 @@ struct Region {
|
||||||
std::optional<uint8_t> keyswitchDown {}; // sw_down
|
std::optional<uint8_t> keyswitchDown {}; // sw_down
|
||||||
std::optional<uint8_t> previousNote {}; // sw_previous
|
std::optional<uint8_t> previousNote {}; // sw_previous
|
||||||
SfzVelocityOverride velocityOverride { Default::velocityOverride }; // sw_vel
|
SfzVelocityOverride velocityOverride { Default::velocityOverride }; // sw_vel
|
||||||
|
bool checkSustain { Default::checkSustain }; // sustain_sw
|
||||||
|
bool checkSostenuto { Default::checkSostenuto }; // sostenuto_sw
|
||||||
|
|
||||||
// Region logic: internal conditions
|
// Region logic: internal conditions
|
||||||
Range<uint8_t> aftertouchRange { Default::aftertouchRange }; // hichanaft and lochanaft
|
Range<uint8_t> aftertouchRange { Default::aftertouchRange }; // hichanaft and lochanaft
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,7 @@
|
||||||
|
|
||||||
#include "Voice.h"
|
#include "Voice.h"
|
||||||
#include "AudioSpan.h"
|
#include "AudioSpan.h"
|
||||||
|
#include "Config.h"
|
||||||
#include "Defaults.h"
|
#include "Defaults.h"
|
||||||
#include "MathHelpers.h"
|
#include "MathHelpers.h"
|
||||||
#include "SIMDHelpers.h"
|
#include "SIMDHelpers.h"
|
||||||
|
|
@ -94,6 +95,7 @@ void sfz::Voice::startVoice(Region* region, int delay, int channel, int number,
|
||||||
|
|
||||||
sourcePosition = region->getOffset();
|
sourcePosition = region->getOffset();
|
||||||
floatPosition = static_cast<float>(sourcePosition);
|
floatPosition = static_cast<float>(sourcePosition);
|
||||||
|
DBG("Offset: " << floatPosition);
|
||||||
initialDelay = delay + region->getDelay();
|
initialDelay = delay + region->getDelay();
|
||||||
baseFrequency = midiNoteFrequency(number) * pitchRatio;
|
baseFrequency = midiNoteFrequency(number) * pitchRatio;
|
||||||
prepareEGEnvelope(delay, value);
|
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)
|
if (region->loopMode == SfzLoopMode::one_shot)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (ccState[64] < 63) {
|
if (!region->checkSustain || ccState[config::sustainCC] < config::halfCCThreshold)
|
||||||
release(delay);
|
release(delay);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -162,7 +163,7 @@ void sfz::Voice::registerCC(int delay, int channel [[maybe_unused]], int ccNumbe
|
||||||
if (region == nullptr)
|
if (region == nullptr)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (ccNumber == 64 && noteIsOff && ccValue < 63)
|
if (ccNumber == config::sustainCC && noteIsOff && ccValue < config::halfCCThreshold)
|
||||||
release(delay);
|
release(delay);
|
||||||
|
|
||||||
if (region->amplitudeCC && ccNumber == region->amplitudeCC->first) {
|
if (region->amplitudeCC && ccNumber == region->amplitudeCC->first) {
|
||||||
|
|
|
||||||
|
|
@ -1011,6 +1011,26 @@ TEST_CASE("[Region] Parsing opcodes")
|
||||||
REQUIRE(region.amplitudeEG.ccStart->second == -100.0f);
|
REQUIRE(region.amplitudeEG.ccStart->second == -100.0f);
|
||||||
REQUIRE(region.amplitudeEG.ccSustain->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
|
// Specific region bugs
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue