diff --git a/src/sfizz/Opcode.h b/src/sfizz/Opcode.h index 65436b2c..962acedd 100644 --- a/src/sfizz/Opcode.h +++ b/src/sfizz/Opcode.h @@ -12,6 +12,7 @@ #include "StringViewHelpers.h" #include "absl/types/optional.h" #include "absl/meta/type_traits.h" +#include "absl/strings/ascii.h" #include #include #include @@ -115,16 +116,18 @@ private: template ::value, int> = 0> inline absl::optional readOpcode(absl::string_view value, const Range& validRange) { - const auto numberEnd = value.find_first_not_of("-1234567890."); + size_t numberEnd = 0; + + if (numberEnd < value.size() && (value[numberEnd] == '+' || value[numberEnd] == '-')) + ++numberEnd; + while (numberEnd < value.size() && absl::ascii_isdigit(value[numberEnd])) + ++numberEnd; + value = value.substr(0, numberEnd); int64_t returnedValue; - if (!absl::SimpleAtoi(value, &returnedValue)) { - float floatValue; - if (!absl::SimpleAtof(value, &floatValue)) + if (!absl::SimpleAtoi(value, &returnedValue)) return absl::nullopt; - returnedValue = static_cast(floatValue); - } if (returnedValue > std::numeric_limits::max()) returnedValue = std::numeric_limits::max(); @@ -147,12 +150,24 @@ inline absl::optional readOpcode(absl::string_view value, const Range template ::value, int> = 0> inline absl::optional readOpcode(absl::string_view value, const Range& validRange) { - const auto numberEnd = value.find_first_not_of("-1234567890."); + size_t numberEnd = 0; + + if (numberEnd < value.size() && (value[numberEnd] == '+' || value[numberEnd] == '-')) + ++numberEnd; + while (numberEnd < value.size() && absl::ascii_isdigit(value[numberEnd])) + ++numberEnd; + + if (numberEnd < value.size() && value[numberEnd] == '.') { + ++numberEnd; + while (numberEnd < value.size() && absl::ascii_isdigit(value[numberEnd])) + ++numberEnd; + } + value = value.substr(0, numberEnd); float returnedValue; if (!absl::SimpleAtof(value, &returnedValue)) - return absl::nullopt; + return absl::nullopt; return validRange.clamp(returnedValue); } diff --git a/tests/OpcodeT.cpp b/tests/OpcodeT.cpp index 53581dd6..bfd0a7f8 100644 --- a/tests/OpcodeT.cpp +++ b/tests/OpcodeT.cpp @@ -250,12 +250,15 @@ TEST_CASE("[Opcode] Normalization") TEST_CASE("[Opcode] readOpcode") { REQUIRE( sfz::readOpcode("16", sfz::Range(0, 100)).value() == 16 ); + REQUIRE( sfz::readOpcode("+16", sfz::Range(0, 100)).value() == 16 ); REQUIRE( sfz::readOpcode("110", sfz::Range(0, 100)).value() == 100 ); REQUIRE( sfz::readOpcode("-1", sfz::Range(0, 100)).value() == 0 ); REQUIRE( sfz::readOpcode("12.5", sfz::Range(-100, 100)).value() == 12 ); + REQUIRE( sfz::readOpcode("+12.5", sfz::Range(-100, 100)).value() == 12 ); REQUIRE( sfz::readOpcode("-40", sfz::Range(-100, 100)).value() == -40 ); REQUIRE( sfz::readOpcode("-140", sfz::Range(-100, 100)).value() == -100 ); REQUIRE( sfz::readOpcode("12.5", sfz::Range(0.0f, 100.0f)).value() == 12.5_a ); + REQUIRE( sfz::readOpcode("+12.5", sfz::Range(0.0f, 100.0f)).value() == 12.5_a ); REQUIRE( sfz::readOpcode("-22.5", sfz::Range(-20.0f, 100.0f)).value() == -20.0_a ); REQUIRE( sfz::readOpcode("150.5", sfz::Range(-20.0f, 100.0f)).value() == 100.0_a ); REQUIRE( sfz::readOpcode("50.25garbage", sfz::Range(-20.0f, 100.0f)).value() == 50.25_a );