2019-07-29 02:13:03 +02:00
|
|
|
#pragma once
|
|
|
|
|
#include "Defaults.h"
|
2019-08-25 14:01:03 +02:00
|
|
|
#include "Helpers.h"
|
2019-07-29 02:13:03 +02:00
|
|
|
#include "Range.h"
|
2019-08-25 14:01:03 +02:00
|
|
|
#include "SfzHelpers.h"
|
2019-07-29 02:13:03 +02:00
|
|
|
#include <optional>
|
2019-08-25 14:01:03 +02:00
|
|
|
#include <string_view>
|
2019-07-29 02:13:03 +02:00
|
|
|
|
|
|
|
|
// charconv support is still sketchy with clang/gcc so we use abseil's numbers
|
|
|
|
|
#include "absl/strings/numbers.h"
|
|
|
|
|
|
2019-08-25 14:01:03 +02:00
|
|
|
namespace sfz {
|
|
|
|
|
struct Opcode {
|
2019-07-29 02:13:03 +02:00
|
|
|
Opcode() = delete;
|
|
|
|
|
Opcode(std::string_view inputOpcode, std::string_view inputValue);
|
2019-08-25 14:01:03 +02:00
|
|
|
std::string_view opcode {};
|
|
|
|
|
std::string_view value {};
|
2019-07-29 02:13:03 +02:00
|
|
|
// This is to handle the integer parameter of some opcodes
|
|
|
|
|
std::optional<uint8_t> parameter;
|
2019-08-25 00:00:50 +02:00
|
|
|
LEAK_DETECTOR(Opcode);
|
2019-07-29 02:13:03 +02:00
|
|
|
};
|
|
|
|
|
|
2019-08-25 14:01:03 +02:00
|
|
|
template <class ValueType>
|
2019-07-29 02:13:03 +02:00
|
|
|
inline std::optional<ValueType> readOpcode(std::string_view value, const Range<ValueType>& validRange)
|
|
|
|
|
{
|
2019-08-25 14:01:03 +02:00
|
|
|
if constexpr (std::is_integral<ValueType>::value) {
|
2019-07-29 02:13:03 +02:00
|
|
|
int64_t returnedValue;
|
|
|
|
|
if (!absl::SimpleAtoi(value, &returnedValue))
|
|
|
|
|
return {};
|
|
|
|
|
|
|
|
|
|
if (returnedValue > std::numeric_limits<ValueType>::max())
|
|
|
|
|
returnedValue = std::numeric_limits<ValueType>::max();
|
|
|
|
|
if (returnedValue < std::numeric_limits<ValueType>::min())
|
|
|
|
|
returnedValue = std::numeric_limits<ValueType>::min();
|
|
|
|
|
|
|
|
|
|
return validRange.clamp(static_cast<ValueType>(returnedValue));
|
2019-08-25 14:01:03 +02:00
|
|
|
} else {
|
2019-07-29 02:13:03 +02:00
|
|
|
float returnedValue;
|
|
|
|
|
if (!absl::SimpleAtof(value, &returnedValue))
|
2019-08-04 01:38:31 +02:00
|
|
|
return std::nullopt;
|
2019-07-29 02:13:03 +02:00
|
|
|
|
|
|
|
|
return validRange.clamp(returnedValue);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-08-25 14:01:03 +02:00
|
|
|
template <class ValueType>
|
2019-07-29 02:13:03 +02:00
|
|
|
inline void setValueFromOpcode(const Opcode& opcode, ValueType& target, const Range<ValueType>& validRange)
|
|
|
|
|
{
|
|
|
|
|
auto value = readOpcode(opcode.value, validRange);
|
|
|
|
|
if (!value) // Try and read a note rather than a number
|
|
|
|
|
value = readNoteValue(opcode.value);
|
|
|
|
|
if (value)
|
|
|
|
|
target = *value;
|
|
|
|
|
}
|
|
|
|
|
|
2019-08-25 14:01:03 +02:00
|
|
|
template <class ValueType>
|
2019-07-29 02:13:03 +02:00
|
|
|
inline void setValueFromOpcode(const Opcode& opcode, std::optional<ValueType>& target, const Range<ValueType>& validRange)
|
|
|
|
|
{
|
|
|
|
|
auto value = readOpcode(opcode.value, validRange);
|
|
|
|
|
if (!value) // Try and read a note rather than a number
|
|
|
|
|
value = readNoteValue(opcode.value);
|
|
|
|
|
if (value)
|
|
|
|
|
target = *value;
|
|
|
|
|
}
|
|
|
|
|
|
2019-08-25 14:01:03 +02:00
|
|
|
template <class ValueType>
|
2019-07-29 02:13:03 +02:00
|
|
|
inline void setRangeEndFromOpcode(const Opcode& opcode, Range<ValueType>& target, const Range<ValueType>& validRange)
|
|
|
|
|
{
|
|
|
|
|
auto value = readOpcode(opcode.value, validRange);
|
|
|
|
|
if (!value) // Try and read a note rather than a number
|
|
|
|
|
value = readNoteValue(opcode.value);
|
|
|
|
|
if (value)
|
|
|
|
|
target.setEnd(*value);
|
|
|
|
|
}
|
|
|
|
|
|
2019-08-25 14:01:03 +02:00
|
|
|
template <class ValueType>
|
2019-07-29 02:13:03 +02:00
|
|
|
inline void setRangeStartFromOpcode(const Opcode& opcode, Range<ValueType>& target, const Range<ValueType>& validRange)
|
|
|
|
|
{
|
|
|
|
|
auto value = readOpcode(opcode.value, validRange);
|
|
|
|
|
if (!value) // Try and read a note rather than a number
|
|
|
|
|
value = readNoteValue(opcode.value);
|
|
|
|
|
if (value)
|
|
|
|
|
target.setStart(*value);
|
|
|
|
|
}
|
|
|
|
|
|
2019-08-25 14:01:03 +02:00
|
|
|
template <class ValueType>
|
2019-07-29 02:13:03 +02:00
|
|
|
inline void setCCPairFromOpcode(const Opcode& opcode, std::optional<CCValuePair>& target, const Range<ValueType>& validRange)
|
|
|
|
|
{
|
|
|
|
|
auto value = readOpcode(opcode.value, validRange);
|
2019-08-25 14:01:03 +02:00
|
|
|
if (value && opcode.parameter && Default::ccRange.containsWithEnd(*opcode.parameter))
|
2019-07-29 02:13:03 +02:00
|
|
|
target = std::make_pair(*opcode.parameter, *value);
|
|
|
|
|
else
|
|
|
|
|
target = {};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|