Parse label_noteNN and add getters for the labels in the internal API

This commit is contained in:
Paul Fd 2020-04-08 12:23:17 +02:00 committed by Jean Pierre Cimalando
parent 6eb71b288e
commit 5a0aafa793
5 changed files with 55 additions and 6 deletions

View file

@ -20,7 +20,9 @@
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>
using MidiNoteArray = std::array<T, 128>;
template<class ValueType>

View file

@ -142,7 +142,9 @@ void sfz::Synth::clear()
numMasters = 0;
defaultSwitch = absl::nullopt;
defaultPath = "";
ccNames.clear();
resources.midiState.reset();
ccLabels.clear();
noteLabels.clear();
globalOpcodes.clear();
masterOpcodes.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&"):
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;
case hash("Default_path"):
// fallthrough
@ -871,7 +877,7 @@ std::string sfz::Synth::exportMidnam(absl::string_view model) const
{
pugi::xml_node cns = device.append_child("ControlNameList");
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");
cn.append_attribute("Type").set_value("7bit");
cn.append_attribute("Number").set_value(std::to_string(pair.first).c_str());

View file

@ -388,6 +388,19 @@ public:
*/
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:
/**
* @brief The parser callback; this is called by the parent object each time
@ -494,8 +507,11 @@ private:
* @return Voice*
*/
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
absl::optional<uint8_t> defaultSwitch;
std::vector<std::string> unknownOpcodes;

View file

@ -563,3 +563,21 @@ TEST_CASE("[Files] Empty file")
REQUIRE(!synth.loadSfzFile({}));
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" );
}

View file

@ -0,0 +1,7 @@
<control>
label_cc54=Gain
label_cc2=Other
label_note12=Cymbals
label_note65=Crash
label_note128=Ignored
<region> sample=*sine