Parse label_noteNN and add getters for the labels in the internal API
This commit is contained in:
parent
6eb71b288e
commit
5a0aafa793
5 changed files with 55 additions and 6 deletions
|
|
@ -20,7 +20,9 @@
|
||||||
namespace sfz
|
namespace sfz
|
||||||
{
|
{
|
||||||
|
|
||||||
using CCNamePair = std::pair<uint16_t, std::string>;
|
using CCNamePair = std::pair<decltype(config::numCCs), std::string>;
|
||||||
|
using NoteNamePair = std::pair<uint8_t, std::string>;
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
using MidiNoteArray = std::array<T, 128>;
|
using MidiNoteArray = std::array<T, 128>;
|
||||||
template<class ValueType>
|
template<class ValueType>
|
||||||
|
|
|
||||||
|
|
@ -142,7 +142,9 @@ void sfz::Synth::clear()
|
||||||
numMasters = 0;
|
numMasters = 0;
|
||||||
defaultSwitch = absl::nullopt;
|
defaultSwitch = absl::nullopt;
|
||||||
defaultPath = "";
|
defaultPath = "";
|
||||||
ccNames.clear();
|
resources.midiState.reset();
|
||||||
|
ccLabels.clear();
|
||||||
|
noteLabels.clear();
|
||||||
globalOpcodes.clear();
|
globalOpcodes.clear();
|
||||||
masterOpcodes.clear();
|
masterOpcodes.clear();
|
||||||
groupOpcodes.clear();
|
groupOpcodes.clear();
|
||||||
|
|
@ -208,7 +210,11 @@ void sfz::Synth::handleControlOpcodes(const std::vector<Opcode>& members)
|
||||||
case hash("Label_cc&"): // fallthrough
|
case hash("Label_cc&"): // fallthrough
|
||||||
case hash("label_cc&"):
|
case hash("label_cc&"):
|
||||||
if (Default::ccNumberRange.containsWithEnd(member.parameters.back()))
|
if (Default::ccNumberRange.containsWithEnd(member.parameters.back()))
|
||||||
ccNames.emplace_back(member.parameters.back(), std::string(member.value));
|
ccLabels.emplace_back(member.parameters.back(), std::string(member.value));
|
||||||
|
break;
|
||||||
|
case hash("label_note&"):
|
||||||
|
if (Default::keyRange.containsWithEnd(member.parameters.back()))
|
||||||
|
noteLabels.emplace_back(member.parameters.back(), std::string(member.value));
|
||||||
break;
|
break;
|
||||||
case hash("Default_path"):
|
case hash("Default_path"):
|
||||||
// fallthrough
|
// fallthrough
|
||||||
|
|
@ -871,7 +877,7 @@ std::string sfz::Synth::exportMidnam(absl::string_view model) const
|
||||||
{
|
{
|
||||||
pugi::xml_node cns = device.append_child("ControlNameList");
|
pugi::xml_node cns = device.append_child("ControlNameList");
|
||||||
cns.append_attribute("Name").set_value("Controls");
|
cns.append_attribute("Name").set_value("Controls");
|
||||||
for (const CCNamePair& pair : ccNames) {
|
for (const CCNamePair& pair : ccLabels) {
|
||||||
pugi::xml_node cn = cns.append_child("Control");
|
pugi::xml_node cn = cns.append_child("Control");
|
||||||
cn.append_attribute("Type").set_value("7bit");
|
cn.append_attribute("Type").set_value("7bit");
|
||||||
cn.append_attribute("Number").set_value(std::to_string(pair.first).c_str());
|
cn.append_attribute("Number").set_value(std::to_string(pair.first).c_str());
|
||||||
|
|
|
||||||
|
|
@ -388,6 +388,19 @@ public:
|
||||||
*/
|
*/
|
||||||
const Parser& getParser() const noexcept { return parser; }
|
const Parser& getParser() const noexcept { return parser; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the note labels, if any
|
||||||
|
*
|
||||||
|
* @return const std::vector<NoteNamePair>&
|
||||||
|
*/
|
||||||
|
const std::vector<NoteNamePair>& getNoteLabels() const noexcept { return noteLabels; }
|
||||||
|
/**
|
||||||
|
* @brief Get the CC labels, if any
|
||||||
|
*
|
||||||
|
* @return const std::vector<NoteNamePair>&
|
||||||
|
*/
|
||||||
|
const std::vector<CCNamePair>& getCCLabels() const noexcept { return ccLabels; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
/**
|
/**
|
||||||
* @brief The parser callback; this is called by the parent object each time
|
* @brief The parser callback; this is called by the parent object each time
|
||||||
|
|
@ -494,8 +507,11 @@ private:
|
||||||
* @return Voice*
|
* @return Voice*
|
||||||
*/
|
*/
|
||||||
Voice* findFreeVoice() noexcept;
|
Voice* findFreeVoice() noexcept;
|
||||||
// Names for the cc as set by the label_cc opcode
|
|
||||||
std::vector<CCNamePair> ccNames;
|
// Names for the CC and notes as set by label_cc and label_note
|
||||||
|
std::vector<CCNamePair> ccLabels;
|
||||||
|
std::vector<NoteNamePair> noteLabels;
|
||||||
|
|
||||||
// Default active switch if multiple keyswitchable regions are present
|
// Default active switch if multiple keyswitchable regions are present
|
||||||
absl::optional<uint8_t> defaultSwitch;
|
absl::optional<uint8_t> defaultSwitch;
|
||||||
std::vector<std::string> unknownOpcodes;
|
std::vector<std::string> unknownOpcodes;
|
||||||
|
|
|
||||||
|
|
@ -563,3 +563,21 @@ TEST_CASE("[Files] Empty file")
|
||||||
REQUIRE(!synth.loadSfzFile({}));
|
REQUIRE(!synth.loadSfzFile({}));
|
||||||
REQUIRE(parser.getIncludedFiles().empty());
|
REQUIRE(parser.getIncludedFiles().empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_CASE("[Files] Labels")
|
||||||
|
{
|
||||||
|
sfz::Synth synth;
|
||||||
|
synth.loadSfzFile(fs::current_path() / "tests/TestFiles/labels.sfz");
|
||||||
|
auto noteLabels = synth.getNoteLabels();
|
||||||
|
auto ccLabels = synth.getCCLabels();
|
||||||
|
REQUIRE( noteLabels.size() == 2);
|
||||||
|
REQUIRE( noteLabels[0].first == 12 );
|
||||||
|
REQUIRE( noteLabels[0].second == "Cymbals" );
|
||||||
|
REQUIRE( noteLabels[1].first == 65 );
|
||||||
|
REQUIRE( noteLabels[1].second == "Crash" );
|
||||||
|
REQUIRE( ccLabels.size() == 2);
|
||||||
|
REQUIRE( ccLabels[0].first == 54 );
|
||||||
|
REQUIRE( ccLabels[0].second == "Gain" );
|
||||||
|
REQUIRE( ccLabels[1].first == 2 );
|
||||||
|
REQUIRE( ccLabels[1].second == "Other" );
|
||||||
|
}
|
||||||
|
|
|
||||||
7
tests/TestFiles/labels.sfz
Normal file
7
tests/TestFiles/labels.sfz
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
<control>
|
||||||
|
label_cc54=Gain
|
||||||
|
label_cc2=Other
|
||||||
|
label_note12=Cymbals
|
||||||
|
label_note65=Crash
|
||||||
|
label_note128=Ignored
|
||||||
|
<region> sample=*sine
|
||||||
Loading…
Add table
Reference in a new issue