text: // SPDX-License-Identifier: BSD-2-Clause
  
  // This code is part of the sfizz library and is licensed under a BSD 2-clause
  // license. You should have receive a LICENSE.md file along with the code.
  // If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz
  
  #include "TestHelpers.h"
  #include "sfizz/Synth.h"
  #include "catch2/catch.hpp"
  #include <stdexcept>
  #include <absl/strings/str_cat.h>
  #include <absl/strings/str_format.h>
  using namespace Catch::literals;
  using namespace sfz;
  
  TEST_CASE("[Values] Delay")
  {
      Synth synth;
      std::vector<std::string> messageList;
      Client client(&messageList);
      client.setReceiveCallback(&simpleMessageReceiver);
  
      SECTION("Basic")
      {
          synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"(
              <region> sample=*sine
              <region> sample=*sine delay=1
              <region> sample=*sine delay=-1
              <region> sample=*sine delay=1 delay=-1
          )");
          synth.dispatchMessage(client, 0, "/region0/delay", "", nullptr);
          synth.dispatchMessage(client, 0, "/region1/delay", "", nullptr);
          synth.dispatchMessage(client, 0, "/region2/delay", "", nullptr);
          synth.dispatchMessage(client, 0, "/region3/delay", "", nullptr);
          std::vector<std::string> expected {
              "/region0/delay,f : { 0 }",
              "/region1/delay,f : { 1 }",
              "/region2/delay,f : { -1 }",
              "/region3/delay,f : { -1 }",
          };
          REQUIRE(messageList == expected);
      }
  
      SECTION("Random")
      {
          synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"(
              <region> sample=*sine
              <region> sample=*sine delay_random=1
              <region> sample=*sine delay_random=-1
              <region> sample=*sine delay_random=1 delay_random=-1
          )");
          synth.dispatchMessage(client, 0, "/region0/delay_random", "", nullptr);
          synth.dispatchMessage(client, 0, "/region1/delay_random", "", nullptr);
          synth.dispatchMessage(client, 0, "/region2/delay_random", "", nullptr);
          synth.dispatchMessage(client, 0, "/region3/delay_random", "", nullptr);
          std::vector<std::string> expected {
              "/region0/delay_random,f : { 0 }",
              "/region1/delay_random,f : { 1 }",
              "/region2/delay_random,f : { -1 }",
              "/region3/delay_random,f : { -1 }",
          };
          REQUIRE(messageList == expected);
      }
  
      SECTION("CC")
      {
          synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"(
              <region> sample=kick.wav
              <region> sample=kick.wav delay_cc12=1.5
              <region> sample=kick.wav delay_cc12=-1.5
              <region> sample=kick.wav delay_cc14=3 delay_cc12=2 delay_cc12=-12
          )");
          synth.dispatchMessage(client, 0, "/region0/delay_cc12", "", nullptr);
          synth.dispatchMessage(client, 0, "/region1/delay_cc12", "", nullptr);
          synth.dispatchMessage(client, 0, "/region2/delay_cc12", "", nullptr);
          synth.dispatchMessage(client, 0, "/region3/delay_cc14", "", nullptr);
          synth.dispatchMessage(client, 0, "/region3/delay_cc12", "", nullptr);
          std::vector<std::string> expected {
              "/region0/delay_cc12,f : { 0 }",
              "/region1/delay_cc12,f : { 1.5 }",
              "/region2/delay_cc12,f : { -1.5 }",
              "/region3/delay_cc14,f : { 3 }",
              "/region3/delay_cc12,f : { -12 }",
          };
          REQUIRE(messageList == expected);
      }
  }
  
  TEST_CASE("[Values] Sample and direction")
  {
      Synth synth;
      std::vector<std::string> messageList;
      Client client(&messageList);
      client.setReceiveCallback(&simpleMessageReceiver);
      synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"(
          <region> sample=*sine
          <region> sample=kick.wav
          <region> sample=kick.wav direction=reverse
      )");
      synth.dispatchMessage(client, 0, "/region0/sample", "", nullptr);
      synth.dispatchMessage(client, 0, "/region1/sample", "", nullptr);
      synth.dispatchMessage(client, 0, "/region1/direction", "", nullptr);
      synth.dispatchMessage(client, 0, "/region2/direction", "", nullptr);
      std::vector<std::string> expected {
          "/region0/sample,s : { *sine }",
          "/region1/sample,s : { kick.wav }",
          "/region1/direction,s : { forward }",
          "/region2/direction,s : { reverse }",
      };
      REQUIRE(messageList == expected);
  }
  
  TEST_CASE("[Values] Offset")
  {
      Synth synth;
      std::vector<std::string> messageList;
      Client client(&messageList);
      client.setReceiveCallback(&simpleMessageReceiver);
  
      SECTION("Basic")
      {
          synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"(
              <region> sample=kick.wav
              <region> sample=kick.wav offset=12
              <region> sample=kick.wav offset=-1
              <region> sample=kick.wav offset=12 offset=-1
          )");
          synth.dispatchMessage(client, 0, "/region0/offset", "", nullptr);
          synth.dispatchMessage(client, 0, "/region1/offset", "", nullptr);
          synth.dispatchMessage(client, 0, "/region2/offset", "", nullptr);
          synth.dispatchMessage(client, 0, "/region3/offset", "", nullptr);
          std::vector<std::string> expected {
              "/region0/offset,h : { 0 }",
              "/region1/offset,h : { 12 }",
              "/region2/offset,h : { -1 }",
              "/region3/offset,h : { -1 }",
          };
          REQUIRE(messageList == expected);
      }
  
      SECTION("Random")
      {
          synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"(
              <region> sample=kick.wav
              <region> sample=kick.wav offset_random=1
              <region> sample=kick.wav offset_random=-1
              <region> sample=kick.wav offset_random=1 offset_random=-1
          )");
          synth.dispatchMessage(client, 0, "/region0/offset_random", "", nullptr);
          synth.dispatchMessage(client, 0, "/region1/offset_random", "", nullptr);
          synth.dispatchMessage(client, 0, "/region2/offset_random", "", nullptr);
          synth.dispatchMessage(client, 0, "/region3/offset_random", "", nullptr);
          std::vector<std::string> expected {
              "/region0/offset_random,h : { 0 }",
              "/region1/offset_random,h : { 1 }",
              "/region2/offset_random,h : { -1 }",
              "/region3/offset_random,h : { -1 }",
          };
          REQUIRE(messageList == expected);
      }
  
      SECTION("CC")
      {
          synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"(
              <region> sample=kick.wav
              <region> sample=kick.wav offset_cc12=12
              <region> sample=kick.wav offset_cc12=-12
              <region> sample=kick.wav offset_cc14=14 offset_cc12=12 offset_cc12=-12
          )");
          synth.dispatchMessage(client, 0, "/region0/offset_cc12", "", nullptr);
          synth.dispatchMessage(client, 0, "/region1/offset_cc12", "", nullptr);
          synth.dispatchMessage(client, 0, "/region2/offset_cc12", "", nullptr);
          synth.dispatchMessage(client, 0, "/region3/offset_cc14", "", nullptr);
          synth.dispatchMessage(client, 0, "/region3/offset_cc12", "", nullptr);
          std::vector<std::string> expected {
              "/region0/offset_cc12,h : { 0 }",
              "/region1/offset_cc12,h : { 12 }",
              "/region2/offset_cc12,h : { -12 }",
              "/region3/offset_cc14,h : { 14 }",
              "/region3/offset_cc12,h : { -12 }",
          };
          REQUIRE(messageList == expected);
      }
  }
  
  TEST_CASE("[Values] End")
  {
      Synth synth;
      std::vector<std::string> messageList;
      Client client(&messageList);
      client.setReceiveCallback(&simpleMessageReceiver);
      SECTION("Basic")
      {
          synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"(
              <region> sample=kick.wav end=194
              <region> sample=kick.wav end=-1
              <region> sample=kick.wav end=0
              <region> sample=kick.wav end=194 end=-1
              <region> sample=kick.wav end=0 end=194
          )");
          synth.dispatchMessage(client, 0, "/region0/end", "", nullptr);
          synth.dispatchMessage(client, 0, "/region0/enabled", "", nullptr);
          synth.dispatchMessage(client, 0, "/region1/enabled", "", nullptr);
          synth.dispatchMessage(client, 0, "/region2/enabled", "", nullptr);
          synth.dispatchMessage(client, 0, "/region3/enabled", "", nullptr);
          synth.dispatchMessage(client, 0, "/region4/enabled", "", nullptr);
          synth.dispatchMessage(client, 0, "/region4/end", "", nullptr);
          std::vector<std::string> expected {
              "/region0/end,h : { 194 }",
              "/region0/enabled,T : {  }",
              "/region1/enabled,F : {  }",
              "/region2/enabled,F : {  }",
              "/region3/enabled,F : {  }",
              "/region4/enabled,T : {  }",
              "/region4/end,h : { 194 }",
          };
          REQUIRE(messageList == expected);
      }
      SECTION("CC")
      {
          synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"(
              <region> sample=kick.wav
              <region> sample=kick.wav end_cc12=12
              <region> sample=kick.wav end_oncc12=-12
              <region> sample=kick.wav end_cc14=14 end_cc12=12 end_oncc12=-12
          )");
          synth.dispatchMessage(client, 0, "/region0/end_cc12", "", nullptr);
          synth.dispatchMessage(client, 0, "/region1/end_cc12", "", nullptr);
          synth.dispatchMessage(client, 0, "/region2/end_cc12", "", nullptr);
          synth.dispatchMessage(client, 0, "/region3/end_cc14", "", nullptr);
          synth.dispatchMessage(client, 0, "/region3/end_cc12", "", nullptr);
          std::vector<std::string> expected {
              "/region0/end_cc12,h : { 0 }",
              "/region1/end_cc12,h : { 12 }",
              "/region2/end_cc12,h : { -12 }",
              "/region3/end_cc14,h : { 14 }",
              "/region3/end_cc12,h : { -12 }",
          };
          REQUIRE(messageList == expected);
      }
  }
  
  TEST_CASE("[Values] Count")
  {
      Synth synth;
      std::vector<std::string> messageList;
      Client client(&messageList);
      client.setReceiveCallback(&simpleMessageReceiver);
      synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"(
          <region> sample=kick.wav
          <region> sample=kick.wav count=2
          <region> sample=kick.wav count=-1
      )");
      synth.dispatchMessage(client, 0, "/region0/count", "", nullptr);
      synth.dispatchMessage(client, 0, "/region1/count", "", nullptr);
      synth.dispatchMessage(client, 0, "/region2/count", "", nullptr);
      std::vector<std::string> expected {
          "/region0/count,N : {  }",
          "/region1/count,h : { 2 }",
          "/region2/count,N : {  }",
      };
      REQUIRE(messageList == expected);
  }
  
  TEST_CASE("[Values] Loop mode")
  {
      Synth synth;
      std::vector<std::string> messageList;
      Client client(&messageList);
      client.setReceiveCallback(&simpleMessageReceiver);
      synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"(
          <region> sample=kick.wav
          <region> sample=kick.wav loop_mode=one_shot
          <region> sample=kick.wav loopmode=one_shot
          <region> sample=kick.wav loop_mode=loop_sustain
          <region> sample=kick.wav loop_mode=loop_continuous
          <region> sample=kick.wav loop_mode=loop_continuous loop_mode=no_loop
      )");
      synth.dispatchMessage(client, 0, "/region0/loop_mode", "", nullptr);
      synth.dispatchMessage(client, 0, "/region1/loop_mode", "", nullptr);
      synth.dispatchMessage(client, 0, "/region2/loop_mode", "", nullptr);
      synth.dispatchMessage(client, 0, "/region3/loop_mode", "", nullptr);
      synth.dispatchMessage(client, 0, "/region4/loop_mode", "", nullptr);
      synth.dispatchMessage(client, 0, "/region5/loop_mode", "", nullptr);
      std::vector<std::string> expected {
          "/region0/loop_mode,s : { no_loop }",
          "/region1/loop_mode,s : { one_shot }",
          "/region2/loop_mode,s : { one_shot }",
          "/region3/loop_mode,s : { loop_sustain }",
          "/region4/loop_mode,s : { loop_continuous }",
          "/region5/loop_mode,s : { no_loop }",
      };
      REQUIRE(messageList == expected);
  }
  
  TEST_CASE("[Values] Loops")
  {
      Synth synth;
      std::vector<std::string> messageList;
      Client client(&messageList);
      client.setReceiveCallback(&simpleMessageReceiver);
      synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"(
          <region> sample=kick.wav
          <region> sample=kick.wav loop_mode=one_shot
          <region> sample=kick.wav loopmode=one_shot
          <region> sample=kick.wav loop_mode=loop_sustain
          <region> sample=kick.wav loop_mode=loop_continuous
          <region> sample=kick.wav loop_mode=loop_continuous loop_mode=no_loop
      )");
      synth.dispatchMessage(client, 0, "/region0/loop_mode", "", nullptr);
      synth.dispatchMessage(client, 0, "/region1/loop_mode", "", nullptr);
      synth.dispatchMessage(client, 0, "/region2/loop_mode", "", nullptr);
      synth.dispatchMessage(client, 0, "/region3/loop_mode", "", nullptr);
      synth.dispatchMessage(client, 0, "/region4/loop_mode", "", nullptr);
      synth.dispatchMessage(client, 0, "/region5/loop_mode", "", nullptr);
      std::vector<std::string> expected {
          "/region0/loop_mode,s : { no_loop }",
          "/region1/loop_mode,s : { one_shot }",
          "/region2/loop_mode,s : { one_shot }",
          "/region3/loop_mode,s : { loop_sustain }",
          "/region4/loop_mode,s : { loop_continuous }",
          "/region5/loop_mode,s : { no_loop }",
      };
      REQUIRE(messageList == expected);
  }
  
  TEST_CASE("[Values] Loop range")
  {
      Synth synth;
      std::vector<std::string> messageList;
      Client client(&messageList);
      client.setReceiveCallback(&simpleMessageReceiver);
      SECTION("Basic")
      {
          synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"(
              <region> sample=kick.wav
              <region> sample=kick.wav loop_start=10 loop_end=100
              <region> sample=kick.wav loopstart=10 loopend=100
              <region> sample=kick.wav loop_start=-1 loopend=-100
          )");
          synth.dispatchMessage(client, 0, "/region0/loop_range", "", nullptr);
          synth.dispatchMessage(client, 0, "/region1/loop_range", "", nullptr);
          synth.dispatchMessage(client, 0, "/region2/loop_range", "", nullptr);
          synth.dispatchMessage(client, 0, "/region3/loop_range", "", nullptr);
          std::vector<std::string> expected {
              "/region0/loop_range,hh : { 0, 44011 }", // Default loop points in the file
              "/region1/loop_range,hh : { 10, 100 }",
              "/region2/loop_range,hh : { 10, 100 }",
              "/region3/loop_range,hh : { 0, 44011 }",
          };
          REQUIRE(messageList == expected);
      }
      SECTION("CC")
      {
          synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"(
              <region> sample=kick.wav
              <region> sample=kick.wav loop_start_cc12=10 loop_end_cc14=-100
              <region> sample=kick.wav loop_start_oncc12=-10 loop_end_oncc14=100
              <region> sample=kick.wav loop_startcc12=-10 loop_lengthcc14=100
              <region> sample=kick.wav loop_length_oncc14=100
              <region> sample=kick.wav loop_length_cc14=100
          )");
          synth.dispatchMessage(client, 0, "/region0/loop_start_cc12", "", nullptr);
          synth.dispatchMessage(client, 0, "/region0/loop_end_cc14", "", nullptr);
          synth.dispatchMessage(client, 0, "/region1/loop_start_cc12", "", nullptr);
          synth.dispatchMessage(client, 0, "/region1/loop_end_cc14", "", nullptr);
          synth.dispatchMessage(client, 0, "/region2/loop_start_cc12", "", nullptr);
          synth.dispatchMessage(client, 0, "/region2/loop_end_cc14", "", nullptr);
          synth.dispatchMessage(client, 0, "/region3/loop_start_cc12", "", nullptr);
          synth.dispatchMessage(client, 0, "/region3/loop_end_cc14", "", nullptr);
          synth.dispatchMessage(client, 0, "/region4/loop_end_cc14", "", nullptr);
          synth.dispatchMessage(client, 0, "/region5/loop_end_cc14", "", nullptr);
          std::vector<std::string> expected {
              "/region0/loop_start_cc12,h : { 0 }",
              "/region0/loop_end_cc14,h : { 0 }",
              "/region1/loop_start_cc12,h : { 10 }",
              "/region1/loop_end_cc14,h : { -100 }",
              "/region2/loop_start_cc12,h : { -10 }",
              "/region2/loop_end_cc14,h : { 100 }",
              "/region3/loop_start_cc12,h : { -10 }",
              "/region3/loop_end_cc14,h : { 100 }",
              "/region4/loop_end_cc14,h : { 100 }",
              "/region5/loop_end_cc14,h : { 100 }",
          };
          REQUIRE(messageList == expected);
      }
  }
  
  TEST_CASE("[Values] Loop crossfade")
  {
      Synth synth;
      std::vector<std::string> messageList;
      Client client(&messageList);
      client.setReceiveCallback(&simpleMessageReceiver);
      synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"(
          <region> sample=kick.wav loop_crossfade=0.5
          <region> sample=kick.wav loop_crossfade=-1
      )");
      synth.dispatchMessage(client, 0, "/region0/loop_crossfade", "", nullptr);
      synth.dispatchMessage(client, 0, "/region1/loop_crossfade", "", nullptr);
      std::vector<std::string> expected {
          "/region0/loop_crossfade,f : { 0.5 }",
          "/region1/loop_crossfade,f : { 0.001 }",
      };
      REQUIRE(messageList == expected);
  }
  
  TEST_CASE("[Values] Loop count")
  {
      Synth synth;
      std::vector<std::string> messageList;
      Client client(&messageList);
      client.setReceiveCallback(&simpleMessageReceiver);
      synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"(
          <region> sample=kick.wav
          <region> sample=kick.wav loop_count=2
          <region> sample=kick.wav loop_count=-1
      )");
      synth.dispatchMessage(client, 0, "/region0/loop_count", "", nullptr);
      synth.dispatchMessage(client, 0, "/region1/loop_count", "", nullptr);
      synth.dispatchMessage(client, 0, "/region2/loop_count", "", nullptr);
      std::vector<std::string> expected {
          "/region0/loop_count,N : {  }",
          "/region1/loop_count,h : { 2 }",
          "/region2/loop_count,N : {  }",
      };
      REQUIRE(messageList == expected);
  }
  
  TEST_CASE("[Values] Output")
  {
      Synth synth;
      std::vector<std::string> messageList;
      Client client(&messageList);
      client.setReceiveCallback(&simpleMessageReceiver);
  
      SECTION("No special outputs") {
          synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"(
              <region> sample=kick.wav
          )");
          synth.dispatchMessage(client, 0, "/region0/output", "", nullptr);
          synth.dispatchMessage(client, 0, "/num_outputs", "", nullptr);
          std::vector<std::string> expected {
              "/region0/output,i : { 0 }",
              "/num_outputs,i : { 1 }",
          };
          REQUIRE(messageList == expected);
      }
  
      SECTION("1 output") {
          synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"(
              <region> sample=kick.wav
              <region> sample=kick.wav output=1
              <region> sample=kick.wav output=-1
          )");
          synth.dispatchMessage(client, 0, "/region0/output", "", nullptr);
          synth.dispatchMessage(client, 0, "/region1/output", "", nullptr);
          synth.dispatchMessage(client, 0, "/region2/output", "", nullptr);
          synth.dispatchMessage(client, 0, "/num_outputs", "", nullptr);
          std::vector<std::string> expected {
              "/region0/output,i : { 0 }",
              "/region1/output,i : { 1 }",
              "/region2/output,i : { 0 }",
              "/num_outputs,i : { 2 }",
          };
          REQUIRE(messageList == expected);
      }
  
      SECTION("More than 1 output") {
          synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"(
              <region> sample=kick.wav
              <region> sample=kick.wav output=1
              <region> sample=kick.wav output=3
          )");
          synth.dispatchMessage(client, 0, "/region0/output", "", nullptr);
          synth.dispatchMessage(client, 0, "/region1/output", "", nullptr);
          synth.dispatchMessage(client, 0, "/region2/output", "", nullptr);
          synth.dispatchMessage(client, 0, "/num_outputs", "", nullptr);
          std::vector<std::string> expected {
              "/region0/output,i : { 0 }",
              "/region1/output,i : { 1 }",
              "/region2/output,i : { 3 }",
              "/num_outputs,i : { 4 }",
          };
          REQUIRE(messageList == expected);
      }
  }
  
  TEST_CASE("[Values] Group")
  {
      Synth synth;
      std::vector<std::string> messageList;
      Client client(&messageList);
      client.setReceiveCallback(&simpleMessageReceiver);
      synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"(
          <region> sample=kick.wav
          <region> sample=kick.wav group=5
          <region> sample=kick.wav group=-2
      )");
      synth.dispatchMessage(client, 0, "/region0/group", "", nullptr);
      synth.dispatchMessage(client, 0, "/region1/group", "", nullptr);
      synth.dispatchMessage(client, 0, "/region2/group", "", nullptr);
      std::vector<std::string> expected {
          "/region0/group,h : { 0 }",
          "/region1/group,h : { 5 }",
          "/region2/group,h : { -2 }",
      };
      REQUIRE(messageList == expected);
  }
  
  TEST_CASE("[Values] Off by")
  {
      Synth synth;
      std::vector<std::string> messageList;
      Client client(&messageList);
      client.setReceiveCallback(&simpleMessageReceiver);
      synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"(
          <region> sample=kick.wav
          <region> sample=kick.wav off_by=5
          <region> sample=kick.wav off_by=-2
      )");
      synth.dispatchMessage(client, 0, "/region0/off_by", "", nullptr);
      synth.dispatchMessage(client, 0, "/region1/off_by", "", nullptr);
      synth.dispatchMessage(client, 0, "/region2/off_by", "", nullptr);
      std::vector<std::string> expected {
          "/region0/off_by,N : {  }",
          "/region1/off_by,h : { 5 }",
          "/region2/off_by,h : { -2 }",
      };
      REQUIRE(messageList == expected);
  }
  
  TEST_CASE("[Values] Off mode")
  {
      Synth synth;
      std::vector<std::string> messageList;
      Client client(&messageList);
      client.setReceiveCallback(&simpleMessageReceiver);
      synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"(
          <region> sample=kick.wav
          <region> sample=kick.wav off_mode=fast
          <region> sample=kick.wav off_mode=normal
          <region> sample=kick.wav off_mode=time
          <region> sample=kick.wav off_mode=time off_mode=normal
          <region> sample=kick.wav off_mode=nothing
      )");
      synth.dispatchMessage(client, 0, "/region0/off_mode", "", nullptr);
      synth.dispatchMessage(client, 0, "/region1/off_mode", "", nullptr);
      synth.dispatchMessage(client, 0, "/region2/off_mode", "", nullptr);
      synth.dispatchMessage(client, 0, "/region3/off_mode", "", nullptr);
      synth.dispatchMessage(client, 0, "/region4/off_mode", "", nullptr);
      synth.dispatchMessage(client, 0, "/region5/off_mode", "", nullptr);
      std::vector<std::string> expected {
          "/region0/off_mode,s : { fast }",
          "/region1/off_mode,s : { fast }",
          "/region2/off_mode,s : { normal }",
          "/region3/off_mode,s : { time }",
          "/region4/off_mode,s : { normal }",
          "/region5/off_mode,s : { fast }",
      };
      REQUIRE(messageList == expected);
  }
  
  TEST_CASE("[Values] Off time")
  {
      Synth synth;
      std::vector<std::string> messageList;
      Client client(&messageList);
      client.setReceiveCallback(&simpleMessageReceiver);
      synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"(
          <region> sample=kick.wav
          <region> sample=kick.wav off_time=0.1
          <region> sample=kick.wav off_time=-1
      )");
      synth.dispatchMessage(client, 0, "/region0/off_time", "", nullptr);
      synth.dispatchMessage(client, 0, "/region1/off_time", "", nullptr);
      synth.dispatchMessage(client, 0, "/region2/off_time", "", nullptr);
      std::vector<std::string> expected {
          "/region0/off_time,f : { 0.006 }",
          "/region1/off_time,f : { 0.1 }",
          "/region2/off_time,f : { -1 }",
      };
      REQUIRE(messageList == expected);
  }
  
  TEST_CASE("[Values] Key range")
  {
      Synth synth;
      std::vector<std::string> messageList;
      Client client(&messageList);
      client.setReceiveCallback(&simpleMessageReceiver);
      synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"(
          <region> sample=kick.wav
          <region> sample=kick.wav lokey=34 hikey=60
          <region> sample=kick.wav lokey=c4 hikey=b5
          <region> sample=kick.wav lokey=-3 hikey=60
          <region> sample=kick.wav hikey=-1
          <region> sample=kick.wav pitch_keycenter=32
          <region> sample=kick.wav pitch_keycenter=-1
          <region> sample=kick.wav key=26
      )");
      synth.dispatchMessage(client, 0, "/region0/key_range", "", nullptr);
      synth.dispatchMessage(client, 0, "/region1/key_range", "", nullptr);
      synth.dispatchMessage(client, 0, "/region2/key_range", "", nullptr);
      synth.dispatchMessage(client, 0, "/region3/key_range", "", nullptr);
      synth.dispatchMessage(client, 0, "/region4/key_range", "", nullptr);
      synth.dispatchMessage(client, 0, "/region0/pitch_keycenter", "", nullptr);
      synth.dispatchMessage(client, 0, "/region5/pitch_keycenter", "", nullptr);
      synth.dispatchMessage(client, 0, "/region6/pitch_keycenter", "", nullptr);
      synth.dispatchMessage(client, 0, "/region7/key_range", "", nullptr);
      synth.dispatchMessage(client, 0, "/region7/pitch_keycenter", "", nullptr);
      std::vector<std::string> expected {
          "/region0/key_range,ii : { 0, 127 }",
          "/region1/key_range,ii : { 34, 60 }",
          "/region2/key_range,ii : { 60, 83 }",
          "/region3/key_range,ii : { 0, 60 }",
          "/region4/key_range,ii : { 0, 127 }",
          "/region0/pitch_keycenter,i : { 60 }",
          "/region5/pitch_keycenter,i : { 32 }",
          "/region6/pitch_keycenter,i : { 60 }",
          "/region7/key_range,ii : { 26, 26 }",
          "/region7/pitch_keycenter,i : { 26 }",
      };
      REQUIRE(messageList == expected);
  }
  
  TEST_CASE("[Values] Triggers on note")
  {
      Synth synth;
      std::vector<std::string> messageList;
      Client client(&messageList);
      client.setReceiveCallback(&simpleMessageReceiver);
      synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"(
          <region> sample=kick.wav
          <region> sample=kick.wav hikey=-1
          <region> sample=kick.wav key=-1
          <region> sample=kick.wav hikey=-1 lokey=12
          <region> sample=kick.wav hikey=-1 lokey=-1
          <region> sample=kick.wav hikey=0 lokey=12
      )");
      synth.dispatchMessage(client, 0, "/region0/trigger_on_note", "", nullptr);
      synth.dispatchMessage(client, 0, "/region1/trigger_on_note", "", nullptr);
      synth.dispatchMessage(client, 0, "/region2/trigger_on_note", "", nullptr);
      // TODO: Double check with Sforzando/rgc
      synth.dispatchMessage(client, 0, "/region3/trigger_on_note", "", nullptr);
      synth.dispatchMessage(client, 0, "/region4/trigger_on_note", "", nullptr);
      synth.dispatchMessage(client, 0, "/region5/trigger_on_note", "", nullptr);
      std::vector<std::string> expected {
          "/region0/trigger_on_note,T : {  }",
          "/region1/trigger_on_note,F : {  }",
          "/region2/trigger_on_note,F : {  }",
          "/region3/trigger_on_note,F : {  }",
          "/region4/trigger_on_note,F : {  }",
          "/region5/trigger_on_note,T : {  }",
      };
      REQUIRE(messageList == expected);
  }
  
  TEST_CASE("[Values] Velocity range")
  {
      Synth synth;
      std::vector<std::string> messageList;
      Client client(&messageList);
      client.setReceiveCallback(&simpleMessageReceiver);
      synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"(
          <region> sample=kick.wav
          <region> sample=kick.wav lovel=34 hivel=60
          <region> sample=kick.wav lovel=-3 hivel=60
          <region> sample=kick.wav hivel=-1
      )");
      synth.dispatchMessage(client, 0, "/region0/vel_range", "", nullptr);
      synth.dispatchMessage(client, 0, "/region1/vel_range", "", nullptr);
      synth.dispatchMessage(client, 0, "/region2/vel_range", "", nullptr);
      synth.dispatchMessage(client, 0, "/region3/vel_range", "", nullptr);
      std::vector<std::string> expected {
          "/region0/vel_range,ff : { 0, 1 }",
          "/region1/vel_range,ff : { 0.267717, 0.480315 }",
          "/region2/vel_range,ff : { -0.023622, 0.480315 }",
          "/region3/vel_range,ff : { 0, -0.00787402 }",
      };
      REQUIRE(messageList == expected);
  }
  
  TEST_CASE("[Values] Bend range")
  {
      Synth synth;
      std::vector<std::string> messageList;
      Client client(&messageList);
      client.setReceiveCallback(&simpleMessageReceiver);
      synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"(
          <region> sample=kick.wav
          <region> sample=kick.wav lobend=891 hibend=2000
          <region> sample=kick.wav lobend=-891 hibend=891
          <region> sample=kick.wav hibend=-10000
      )");
      synth.dispatchMessage(client, 0, "/region0/bend_range", "", nullptr);
      synth.dispatchMessage(client, 0, "/region1/bend_range", "", nullptr);
      synth.dispatchMessage(client, 0, "/region2/bend_range", "", nullptr);
      synth.dispatchMessage(client, 0, "/region3/bend_range", "", nullptr);
      std::vector<std::string> expected {
          "/region0/bend_range,ff : { -1, 1 }",
          "/region1/bend_range,ff : { 0.108778, 0.24417 }",
          "/region2/bend_range,ff : { -0.108778, 0.108778 }",
          "/region3/bend_range,ff : { -1, -1.22085 }",
      };
      REQUIRE(messageList == expected);
  }
  
  TEST_CASE("[Values] CC condition range")
  {
      Synth synth;
      std::vector<std::string> messageList;
      Client client(&messageList);
      client.setReceiveCallback(&simpleMessageReceiver);
  
      SECTION("Basic")
      {
          synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"(
              <region> sample=kick.wav
              <region> sample=kick.wav locc1=0 hicc1=54
              <region> sample=kick.wav locc1=0 hicc1=54 locc2=2 hicc2=10
              <region> sample=kick.wav locc1=10 hicc1=-1
          )");
          synth.dispatchMessage(client, 0, "/region0/cc_range1", "", nullptr);
          synth.dispatchMessage(client, 0, "/region1/cc_range1", "", nullptr);
          synth.dispatchMessage(client, 0, "/region2/cc_range1", "", nullptr);
          synth.dispatchMessage(client, 0, "/region2/cc_range2", "", nullptr);
          synth.dispatchMessage(client, 0, "/region3/cc_range1", "", nullptr);
          std::vector<std::string> expected {
              "/region0/cc_range1,ff : { 0, 1 }",
              "/region1/cc_range1,ff : { 0, 0.433071 }",
              "/region2/cc_range1,ff : { 0, 0.433071 }",
              "/region2/cc_range2,ff : { 0.015748, 0.0866142 }",
              "/region3/cc_range1,ff : { 0.0787402, -0.00787402 }",
          };
          REQUIRE(messageList == expected);
      }
  
      SECTION("hdcc")
      {
          synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"(
              <region> sample=kick.wav
              <region> sample=kick.wav lohdcc1=0 hihdcc1=0.1
              <region> sample=kick.wav lohdcc1=0 hihdcc1=0.1 lohdcc2=0.1 hihdcc2=0.2
              <region> sample=kick.wav lohdcc1=0.1 hihdcc1=-0.1
          )");
          synth.dispatchMessage(client, 0, "/region0/cc_range1", "", nullptr);
          synth.dispatchMessage(client, 0, "/region1/cc_range1", "", nullptr);
          synth.dispatchMessage(client, 0, "/region2/cc_range1", "", nullptr);
          synth.dispatchMessage(client, 0, "/region2/cc_range2", "", nullptr);
          synth.dispatchMessage(client, 0, "/region3/cc_range1", "", nullptr);
          std::vector<std::string> expected {
              "/region0/cc_range1,ff : { 0, 1 }",
              "/region1/cc_range1,ff : { 0, 0.1 }",
              "/region2/cc_range1,ff : { 0, 0.1 }",
              "/region2/cc_range2,ff : { 0.1, 0.2 }",
              "/region3/cc_range1,ff : { 0.1, -0.1 }",
          };
          REQUIRE(messageList == expected);
      }
  
      SECTION("realcc")
      {
          synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"(
              <region> sample=kick.wav
              <region> sample=kick.wav lorealcc1=0 hirealcc1=0.1
              <region> sample=kick.wav lorealcc1=0 hirealcc1=0.1 lorealcc2=0.1 hirealcc2=0.2
              <region> sample=kick.wav lorealcc1=0.1 hirealcc1=-0.1
          )");
          synth.dispatchMessage(client, 0, "/region0/cc_range1", "", nullptr);
          synth.dispatchMessage(client, 0, "/region1/cc_range1", "", nullptr);
          synth.dispatchMessage(client, 0, "/region2/cc_range1", "", nullptr);
          synth.dispatchMessage(client, 0, "/region2/cc_range2", "", nullptr);
          synth.dispatchMessage(client, 0, "/region3/cc_range1", "", nullptr);
          std::vector<std::string> expected {
              "/region0/cc_range1,ff : { 0, 1 }",
              "/region1/cc_range1,ff : { 0, 0.1 }",
              "/region2/cc_range1,ff : { 0, 0.1 }",
              "/region2/cc_range2,ff : { 0.1, 0.2 }",
              "/region3/cc_range1,ff : { 0.1, -0.1 }",
          };
          REQUIRE(messageList == expected);
      }
  }
  
  TEST_CASE("[Values] Last keyswitch")
  {
      Synth synth;
      std::vector<std::string> messageList;
      Client client(&messageList);
      client.setReceiveCallback(&simpleMessageReceiver);
  
      SECTION("Basic")
      {
          synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"(
              <region> sample=kick.wav
              <region> sample=kick.wav sw_last=12
              <region> sample=kick.wav sw_last=c4
              <region> sample=kick.wav sw_lolast=14 sw_hilast=16
              <region> sample=kick.wav sw_lolast=c4 sw_hilast=b5
              <region> sample=kick.wav sw_last=-1
          )");
          synth.dispatchMessage(client, 0, "/region0/sw_last", "", nullptr);
          synth.dispatchMessage(client, 0, "/region1/sw_last", "", nullptr);
          synth.dispatchMessage(client, 0, "/region2/sw_last", "", nullptr);
          synth.dispatchMessage(client, 0, "/region3/sw_last", "", nullptr);
          // TODO: activate for the new region parser ; can handle note names
          // synth.dispatchMessage(client, 0, "/region4/sw_last", "", nullptr);
          // TODO: activate for the new region parser ; ignore the second value
          // synth.dispatchMessage(client, 0, "/region5/sw_last", "", nullptr);
          std::vector<std::string> expected {
              "/region0/sw_last,N : {  }",
              "/region1/sw_last,i : { 12 }",
              "/region2/sw_last,i : { 60 }",
              "/region3/sw_last,ii : { 14, 16 }",
              // "/region4/sw_last,ii : { 60, 83 }",
              // "/region5/sw_last,ii : { 0, 0 }",
          };
          REQUIRE(messageList == expected);
      }
  
      SECTION("sw_lolast disables sw_last over the whole region")
      {
          synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"(
              <region> sample=kick.wav sw_last=12 sw_lolast=14 sw_last=16
          )");
          synth.dispatchMessage(client, 0, "/region0/sw_last", "", nullptr);
          std::vector<std::string> expected {
              "/region0/sw_last,ii : { 14, 14 }",
          };
          REQUIRE(messageList == expected);
      }
  }
  
  TEST_CASE("[Values] Keyswitch label")
  {
      Synth synth;
      std::vector<std::string> messageList;
      Client client(&messageList);
      client.setReceiveCallback(&simpleMessageReceiver);
      synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"(
          <region> sample=kick.wav
          <region> sample=kick.wav sw_label=hello
      )");
      synth.dispatchMessage(client, 0, "/region0/sw_label", "", nullptr);
      synth.dispatchMessage(client, 0, "/region1/sw_label", "", nullptr);
      std::vector<std::string> expected {
          "/region0/sw_label,N : {  }",
          "/region1/sw_label,s : { hello }",
      };
      REQUIRE(messageList == expected);
  }
  
  TEST_CASE("[Values] Upswitch")
  {
      Synth synth;
      std::vector<std::string> messageList;
      Client client(&messageList);
      client.setReceiveCallback(&simpleMessageReceiver);
      synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"(
          <region> sample=kick.wav
          <region> sample=kick.wav sw_up=16
          <region> sample=kick.wav sw_up=-1
          <region> sample=kick.wav sw_up=128
          <region> sample=kick.wav sw_up=c4
          <region> sample=kick.wav sw_up=64 sw_up=-1
      )");
      synth.dispatchMessage(client, 0, "/region0/sw_up", "", nullptr);
      synth.dispatchMessage(client, 0, "/region1/sw_up", "", nullptr);
      synth.dispatchMessage(client, 0, "/region2/sw_up", "", nullptr);
      synth.dispatchMessage(client, 0, "/region3/sw_up", "", nullptr);
      synth.dispatchMessage(client, 0, "/region4/sw_up", "", nullptr);
      synth.dispatchMessage(client, 0, "/region5/sw_up", "", nullptr);
      std::vector<std::string> expected {
          "/region0/sw_up,N : {  }",
          "/region1/sw_up,i : { 16 }",
          "/region2/sw_up,N : {  }",
          "/region3/sw_up,N : {  }",
          "/region4/sw_up,i : { 60 }",
          "/region5/sw_up,N : {  }",
      };
      REQUIRE(messageList == expected);
  }
  
  TEST_CASE("[Values] Downswitch")
  {
      Synth synth;
      std::vector<std::string> messageList;
      Client client(&messageList);
      client.setReceiveCallback(&simpleMessageReceiver);
      synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"(
          <region> sample=kick.wav
          <region> sample=kick.wav sw_down=16
          <region> sample=kick.wav sw_down=-1
          <region> sample=kick.wav sw_down=128
          <region> sample=kick.wav sw_down=c4
          <region> sample=kick.wav sw_down=64 sw_down=-1
      )");
      synth.dispatchMessage(client, 0, "/region0/sw_down", "", nullptr);
      synth.dispatchMessage(client, 0, "/region1/sw_down", "", nullptr);
      synth.dispatchMessage(client, 0, "/region2/sw_down", "", nullptr);
      synth.dispatchMessage(client, 0, "/region3/sw_down", "", nullptr);
      synth.dispatchMessage(client, 0, "/region4/sw_down", "", nullptr);
      synth.dispatchMessage(client, 0, "/region5/sw_down", "", nullptr);
      std::vector<std::string> expected {
          "/region0/sw_down,N : {  }",
          "/region1/sw_down,i : { 16 }",
          "/region2/sw_down,N : {  }",
          "/region3/sw_down,N : {  }",
          "/region4/sw_down,i : { 60 }",
          "/region5/sw_down,N : {  }",
      };
      REQUIRE(messageList == expected);
  }
  
  TEST_CASE("[Values] Previous keyswitch")
  {
      Synth synth;
      std::vector<std::string> messageList;
      Client client(&messageList);
      client.setReceiveCallback(&simpleMessageReceiver);
      synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"(
          <region> sample=kick.wav
          <region> sample=kick.wav sw_previous=16
          <region> sample=kick.wav sw_previous=-1
          <region> sample=kick.wav sw_previous=128
          <region> sample=kick.wav sw_previous=c4
          <region> sample=kick.wav sw_previous=64 sw_previous=-1
      )");
      synth.dispatchMessage(client, 0, "/region0/sw_previous", "", nullptr);
      synth.dispatchMessage(client, 0, "/region1/sw_previous", "", nullptr);
      synth.dispatchMessage(client, 0, "/region2/sw_previous", "", nullptr);
      synth.dispatchMessage(client, 0, "/region3/sw_previous", "", nullptr);
      synth.dispatchMessage(client, 0, "/region4/sw_previous", "", nullptr);
      synth.dispatchMessage(client, 0, "/region5/sw_previous", "", nullptr);
      std::vector<std::string> expected {
          "/region0/sw_previous,N : {  }",
          "/region1/sw_previous,i : { 16 }",
          "/region2/sw_previous,N : {  }",
          "/region3/sw_previous,N : {  }",
          "/region4/sw_previous,i : { 60 }",
          "/region5/sw_previous,N : {  }",
      };
      REQUIRE(messageList == expected);
  }
  
  TEST_CASE("[Values] Velocity override")
  {
      Synth synth;
      std::vector<std::string> messageList;
      Client client(&messageList);
      client.setReceiveCallback(&simpleMessageReceiver);
      synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"(
          <region> sample=kick.wav
          <region> sample=kick.wav sw_vel=current
          <region> sample=kick.wav sw_vel=previous
          <region> sample=kick.wav sw_vel=previous sw_vel=current
      )");
      synth.dispatchMessage(client, 0, "/region0/sw_vel", "", nullptr);
      synth.dispatchMessage(client, 0, "/region1/sw_vel", "", nullptr);
      synth.dispatchMessage(client, 0, "/region2/sw_vel", "", nullptr);
      synth.dispatchMessage(client, 0, "/region3/sw_vel", "", nullptr);
      std::vector<std::string> expected {
          "/region0/sw_vel,s : { current }",
          "/region1/sw_vel,s : { current }",
          "/region2/sw_vel,s : { previous }",
          "/region3/sw_vel,s : { current }",
      };
      REQUIRE(messageList == expected);
  }
  
  TEST_CASE("[Values] Aftertouch range")
  {
      Synth synth;
      std::vector<std::string> messageList;
      Client client(&messageList);
      client.setReceiveCallback(&simpleMessageReceiver);
      synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"(
          <region> sample=kick.wav
          <region> sample=kick.wav lochanaft=34 hichanaft=60
          <region> sample=kick.wav lochanaft=-3 hichanaft=60
          <region> sample=kick.wav lochanaft=20 hichanaft=-1
          <region> sample=kick.wav lochanaft=20 hichanaft=10
      )");
      synth.dispatchMessage(client, 0, "/region0/chanaft_range", "", nullptr);
      synth.dispatchMessage(client, 0, "/region1/chanaft_range", "", nullptr);
      synth.dispatchMessage(client, 0, "/region2/chanaft_range", "", nullptr);
      synth.dispatchMessage(client, 0, "/region3/chanaft_range", "", nullptr);
      synth.dispatchMessage(client, 0, "/region4/chanaft_range", "", nullptr);
      std::vector<std::string> expected {
          "/region0/chanaft_range,ff : { 0, 1 }",
          "/region1/chanaft_range,ff : { 0.267717, 0.480315 }",
          "/region2/chanaft_range,ff : { -0.023622, 0.480315 }",
          "/region3/chanaft_range,ff : { 0.15748, -0.00787402 }",
          "/region4/chanaft_range,ff : { 0.15748, 0.0866142 }",
      };
      REQUIRE(messageList == expected);
  }
  
  TEST_CASE("[Values] Polyaftertouch range")
  {
      Synth synth;
      std::vector<std::string> messageList;
      Client client(&messageList);
      client.setReceiveCallback(&simpleMessageReceiver);
      synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"(
          <region> sample=kick.wav
          <region> sample=kick.wav lopolyaft=34 hipolyaft=60
          <region> sample=kick.wav lopolyaft=-3 hipolyaft=60
          <region> sample=kick.wav lopolyaft=20 hipolyaft=-1
          <region> sample=kick.wav lopolyaft=20 hipolyaft=10
      )");
      synth.dispatchMessage(client, 0, "/region0/polyaft_range", "", nullptr);
      synth.dispatchMessage(client, 0, "/region1/polyaft_range", "", nullptr);
      synth.dispatchMessage(client, 0, "/region2/polyaft_range", "", nullptr);
      synth.dispatchMessage(client, 0, "/region3/polyaft_range", "", nullptr);
      synth.dispatchMessage(client, 0, "/region4/polyaft_range", "", nullptr);
      std::vector<std::string> expected {
          "/region0/polyaft_range,ff : { 0, 1 }",
          "/region1/polyaft_range,ff : { 0.267717, 0.480315 }",
          "/region2/polyaft_range,ff : { -0.023622, 0.480315 }",
          "/region3/polyaft_range,ff : { 0.15748, -0.00787402 }",
          "/region4/polyaft_range,ff : { 0.15748, 0.0866142 }",
      };
      REQUIRE(messageList == expected);
  }
  
  TEST_CASE("[Values] BPM range")
  {
      Synth synth;
      std::vector<std::string> messageList;
      Client client(&messageList);
      client.setReceiveCallback(&simpleMessageReceiver);
      synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"(
          <region> sample=kick.wav
          <region> sample=kick.wav lobpm=34.1 hibpm=60.2
          <region> sample=kick.wav lobpm=-3 hibpm=60
          <region> sample=kick.wav lobpm=20 hibpm=-1
          <region> sample=kick.wav lobpm=20 hibpm=10
      )");
      synth.dispatchMessage(client, 0, "/region0/bpm_range", "", nullptr);
      synth.dispatchMessage(client, 0, "/region1/bpm_range", "", nullptr);
      synth.dispatchMessage(client, 0, "/region2/bpm_range", "", nullptr);
      synth.dispatchMessage(client, 0, "/region3/bpm_range", "", nullptr);
      synth.dispatchMessage(client, 0, "/region4/bpm_range", "", nullptr);
      std::vector<std::string> expected {
          "/region0/bpm_range,ff : { 0, 500 }",
          "/region1/bpm_range,ff : { 34.1, 60.2 }",
          "/region2/bpm_range,ff : { -3, 60 }",
          "/region3/bpm_range,ff : { 20, -1 }",
          "/region4/bpm_range,ff : { 20, 10 }",
      };
      REQUIRE(messageList == expected);
  }
  
  TEST_CASE("[Values] Rand range")
  {
      Synth synth;
      std::vector<std::string> messageList;
      Client client(&messageList);
      client.setReceiveCallback(&simpleMessageReceiver);
      synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"(
          <region> sample=kick.wav
          <region> sample=kick.wav lorand=0.2 hirand=0.4
          <region> sample=kick.wav lorand=-0.1 hirand=0.4
          <region> sample=kick.wav lorand=0.2 hirand=-0.1
          <region> sample=kick.wav lorand=0.2 hirand=0.1
      )");
      synth.dispatchMessage(client, 0, "/region0/rand_range", "", nullptr);
      synth.dispatchMessage(client, 0, "/region1/rand_range", "", nullptr);
      synth.dispatchMessage(client, 0, "/region2/rand_range", "", nullptr);
      synth.dispatchMessage(client, 0, "/region3/rand_range", "", nullptr);
      synth.dispatchMessage(client, 0, "/region4/rand_range", "", nullptr);
      std::vector<std::string> expected {
          "/region0/rand_range,ff : { 0, 1 }",
          "/region1/rand_range,ff : { 0.2, 0.4 }",
          "/region2/rand_range,ff : { -0.1, 0.4 }",
          "/region3/rand_range,ff : { 0.2, -0.1 }",
          "/region4/rand_range,ff : { 0.2, 0.1 }",
      };
      REQUIRE(messageList == expected);
  }
  
  TEST_CASE("[Values] Sequence length")
  {
      Synth synth;
      std::vector<std::string> messageList;
      Client client(&messageList);
      client.setReceiveCallback(&simpleMessageReceiver);
  
      synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"(
          <region> sample=kick.wav
          <region> sample=kick.wav seq_length=12
          <region> sample=kick.wav seq_length=-1
          <region> sample=kick.wav seq_length=12 seq_length=-1
      )");
      synth.dispatchMessage(client, 0, "/region0/seq_length", "", nullptr);
      synth.dispatchMessage(client, 0, "/region1/seq_length", "", nullptr);
      synth.dispatchMessage(client, 0, "/region2/seq_length", "", nullptr);
      // TODO: activate for the new region parser ; ignore the second value
      // synth.dispatchMessage(client, 0, "/region3/seq_length", "", nullptr);
      std::vector<std::string> expected {
          "/region0/seq_length,h : { 1 }",
          "/region1/seq_length,h : { 12 }",
          "/region2/seq_length,h : { 1 }",
          // TODO: activate for the new region parser ; ignore the second value
          // "/region3/seq_length,f : { 12 }",
      };
      REQUIRE(messageList == expected);
  }
  
  TEST_CASE("[Values] Sequence position")
  {
      Synth synth;
      std::vector<std::string> messageList;
      Client client(&messageList);
      client.setReceiveCallback(&simpleMessageReceiver);
  
      synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"(
          <region> sample=kick.wav
          <region> sample=kick.wav seq_position=12
          <region> sample=kick.wav seq_position=-1
          <region> sample=kick.wav seq_position=12 seq_position=-1
      )");
      synth.dispatchMessage(client, 0, "/region0/seq_position", "", nullptr);
      synth.dispatchMessage(client, 0, "/region1/seq_position", "", nullptr);
      synth.dispatchMessage(client, 0, "/region2/seq_position", "", nullptr);
      // TODO: activate for the new region parser ; ignore the second value
      // synth.dispatchMessage(client, 0, "/region3/seq_position", "", nullptr);
      std::vector<std::string> expected {
          "/region0/seq_position,h : { 1 }",
          "/region1/seq_position,h : { 12 }",
          "/region2/seq_position,h : { 1 }",
          // TODO: activate for the new region parser ; ignore the second value
          // "/region3/seq_position,f : { 12 }",
      };
      REQUIRE(messageList == expected);
  }
  
  TEST_CASE("[Values] Trigger type")
  {
      Synth synth;
      std::vector<std::string> messageList;
      Client client(&messageList);
      client.setReceiveCallback(&simpleMessageReceiver);
      synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"(
          <region> sample=kick.wav
          <region> sample=kick.wav trigger=release
          <region> sample=kick.wav trigger=release_key
          <region> sample=kick.wav trigger=legato
          <region> sample=kick.wav trigger=first
          <region> sample=kick.wav trigger=nothing
          <region> sample=kick.wav trigger=release trigger=attack
      )");
      synth.dispatchMessage(client, 0, "/region0/trigger", "", nullptr);
      synth.dispatchMessage(client, 0, "/region1/trigger", "", nullptr);
      synth.dispatchMessage(client, 0, "/region2/trigger", "", nullptr);
      synth.dispatchMessage(client, 0, "/region3/trigger", "", nullptr);
      synth.dispatchMessage(client, 0, "/region4/trigger", "", nullptr);
      synth.dispatchMessage(client, 0, "/region5/trigger", "", nullptr);
      synth.dispatchMessage(client, 0, "/region6/trigger", "", nullptr);
      std::vector<std::string> expected {
          "/region0/trigger,s : { attack }",
          "/region1/trigger,s : { release }",
          "/region2/trigger,s : { release_key }",
          "/region3/trigger,s : { legato }",
          "/region4/trigger,s : { first }",
          "/region5/trigger,s : { attack }",
          "/region6/trigger,s : { attack }",
      };
      REQUIRE(messageList == expected);
  }
  
  TEST_CASE("[Values] Start on cc range")
  {
      Synth synth;
      std::vector<std::string> messageList;
      Client client(&messageList);
      client.setReceiveCallback(&simpleMessageReceiver);
      synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"(
          <region> sample=kick.wav
          <region> sample=kick.wav on_locc1=15
          <region> sample=kick.wav on_hicc1=84
          <region> sample=kick.wav on_locc1=15 on_hicc1=84
          <region> sample=kick.wav on_lohdcc2=0.1
          <region> sample=kick.wav on_hihdcc2=0.4
          <region> sample=kick.wav on_lohdcc2=0.1 on_hihdcc2=0.4
      )");
      synth.dispatchMessage(client, 0, "/region0/start_cc_range1", "", nullptr);
      synth.dispatchMessage(client, 0, "/region0/start_cc_range2", "", nullptr);
      synth.dispatchMessage(client, 0, "/region1/start_cc_range1", "", nullptr);
      synth.dispatchMessage(client, 0, "/region2/start_cc_range1", "", nullptr);
      synth.dispatchMessage(client, 0, "/region3/start_cc_range1", "", nullptr);
      synth.dispatchMessage(client, 0, "/region4/start_cc_range2", "", nullptr);
      synth.dispatchMessage(client, 0, "/region5/start_cc_range2", "", nullptr);
      synth.dispatchMessage(client, 0, "/region6/start_cc_range2", "", nullptr);
      std::vector<std::string> expected {
          "/region0/start_cc_range1,N : {  }",
          "/region0/start_cc_range2,N : {  }",
          "/region1/start_cc_range1,ff : { 0.11811, 1 }",
          "/region2/start_cc_range1,ff : { 0, 0.669291 }",
          "/region3/start_cc_range1,ff : { 0.11811, 0.669291 }",
          "/region4/start_cc_range2,ff : { 0.1, 1 }",
          "/region5/start_cc_range2,ff : { 0, 0.4 }",
          "/region6/start_cc_range2,ff : { 0.1, 0.4 }",
      };
      REQUIRE(messageList == expected);
  }
  
  TEST_CASE("[Values] Volume")
  {
      Synth synth;
      std::vector<std::string> messageList;
      Client client(&messageList);
      client.setReceiveCallback(&simpleMessageReceiver);
  
      SECTION("Basic")
      {
          synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"(
              <region> sample=kick.wav
              <region> sample=kick.wav volume=4.2
              <region> sample=kick.wav gain=-200
          )");
          synth.dispatchMessage(client, 0, "/region0/volume", "", nullptr);
          synth.dispatchMessage(client, 0, "/region1/volume", "", nullptr);
          // TODO: activate for the new region parser ; allow oob
          // synth.dispatchMessage(client, 0, "/region2/volume", "", nullptr);
          std::vector<std::string> expected {
              "/region0/volume,f : { 0 }",
              "/region1/volume,f : { 4.2 }",
              // "/region2/volume,f : { -200 }",
          };
          REQUIRE(messageList == expected);
      }
  
      SECTION("CC Depth")
      {
          synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"(
              <region> sample=kick.wav
              <region> sample=kick.wav volume_oncc42=4.2
              <region> sample=kick.wav gain_oncc2=-10
          )");
          synth.dispatchMessage(client, 0, "/region0/volume_cc42", "", nullptr);
          synth.dispatchMessage(client, 0, "/region1/volume_cc42", "", nullptr);
          synth.dispatchMessage(client, 0, "/region2/volume_cc2", "", nullptr);
          std::vector<std::string> expected {
              "/region0/volume_cc42,N : {  }",
              "/region1/volume_cc42,f : { 4.2 }",
              "/region2/volume_cc2,f : { -10 }",
          };
          REQUIRE(messageList == expected);
      }
  
      SECTION("CC Params")
      {
          synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"(
              <region> sample=kick.wav
              <region> sample=kick.wav volume_stepcc42=4.2
              <region> sample=kick.wav volume_smoothcc42=4
              <region> sample=kick.wav volume_curvecc42=2
              <region> sample=kick.wav volume_stepcc42=-1
              <region> sample=kick.wav volume_smoothcc42=-4
              <region> sample=kick.wav volume_curvecc42=300
          )");
          synth.dispatchMessage(client, 0, "/region0/volume_stepcc42", "", nullptr);
          synth.dispatchMessage(client, 0, "/region0/volume_smoothcc42", "", nullptr);
          synth.dispatchMessage(client, 0, "/region0/volume_curvecc42", "", nullptr);
          synth.dispatchMessage(client, 0, "/region1/volume_stepcc42", "", nullptr);
          synth.dispatchMessage(client, 0, "/region2/volume_smoothcc42", "", nullptr);
          synth.dispatchMessage(client, 0, "/region3/volume_curvecc42", "", nullptr);
          // TODO: activate for the new region parser ; ignore oob
          // synth.dispatchMessage(client, 0, "/region4/volume_stepcc42", "", nullptr);
          // synth.dispatchMessage(client, 0, "/region5/volume_smoothcc42", "", nullptr);
          // synth.dispatchMessage(client, 0, "/region6/volume_curvecc42", "", nullptr);
          std::vector<std::string> expected {
              "/region0/volume_stepcc42,N : {  }",
              "/region0/volume_smoothcc42,N : {  }",
              "/region0/volume_curvecc42,N : {  }",
              "/region1/volume_stepcc42,f : { 4.2 }",
              "/region2/volume_smoothcc42,i : { 4 }",
              "/region3/volume_curvecc42,i : { 2 }",
              // "/region4/volume_stepcc42,N : {  }",
              // "/region5/volume_smoothcc42,N : {  }",
              // "/region6/volume_curvecc42,N : {  }",
          };
          REQUIRE(messageList == expected);
      }
  
      SECTION("CC Params (with gain_)")
      {
          synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"(
              <region> sample=kick.wav
              <region> sample=kick.wav gain_stepcc42=4.2
              <region> sample=kick.wav gain_smoothcc42=4
              <region> sample=kick.wav gain_curvecc42=2
              <region> sample=kick.wav gain_stepcc42=-1
              <region> sample=kick.wav gain_smoothcc42=-4
              <region> sample=kick.wav gain_curvecc42=300
          )");
          synth.dispatchMessage(client, 0, "/region0/volume_stepcc42", "", nullptr);
          synth.dispatchMessage(client, 0, "/region0/volume_smoothcc42", "", nullptr);
          synth.dispatchMessage(client, 0, "/region0/volume_curvecc42", "", nullptr);
          synth.dispatchMessage(client, 0, "/region1/volume_stepcc42", "", nullptr);
          synth.dispatchMessage(client, 0, "/region2/volume_smoothcc42", "", nullptr);
          synth.dispatchMessage(client, 0, "/region3/volume_curvecc42", "", nullptr);
          // TODO: activate for the new region parser ; ignore oob
          // synth.dispatchMessage(client, 0, "/region4/volume_stepcc42", "", nullptr);
          // synth.dispatchMessage(client, 0, "/region5/volume_smoothcc42", "", nullptr);
          // synth.dispatchMessage(client, 0, "/region6/volume_curvecc42", "", nullptr);
          std::vector<std::string> expected {
              "/region0/volume_stepcc42,N : {  }",
              "/region0/volume_smoothcc42,N : {  }",
              "/region0/volume_curvecc42,N : {  }",
              "/region1/volume_stepcc42,f : { 4.2 }",
              "/region2/volume_smoothcc42,i : { 4 }",
              "/region3/volume_curvecc42,i : { 2 }",
              // "/region4/volume_stepcc42,N : {  }",
              // "/region5/volume_smoothcc42,N : {  }",
              // "/region6/volume_curvecc42,N : {  }",
          };
          REQUIRE(messageList == expected);
      }
  }
  
  TEST_CASE("[Values] Pan")
  {
      Synth synth;
      std::vector<std::string> messageList;
      Client client(&messageList);
      client.setReceiveCallback(&simpleMessageReceiver);
  
      SECTION("Basic")
      {
          synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"(
              <region> sample=kick.wav
              <region> sample=kick.wav pan=4.2
              <region> sample=kick.wav pan=-200
          )");
          synth.dispatchMessage(client, 0, "/region0/pan", "", nullptr);
          synth.dispatchMessage(client, 0, "/region1/pan", "", nullptr);
          // TODO: activate for the new region parser ; accept oob
          // synth.dispatchMessage(client, 0, "/region2/pan", "", nullptr);
          std::vector<std::string> expected {
              "/region0/pan,f : { 0 }",
              "/region1/pan,f : { 4.2 }",
              // TODO: activate for the new region parser ; accept oob
              // "/region2/pan,f : { -200 }",
          };
          REQUIRE(messageList == expected);
      }
  
      SECTION("CC Depth")
      {
          synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"(
              <region> sample=kick.wav
              <region> sample=kick.wav pan_oncc42=4.2
              <region> sample=kick.wav pan_oncc2=-10
          )");
          synth.dispatchMessage(client, 0, "/region0/pan_cc42", "", nullptr);
          synth.dispatchMessage(client, 0, "/region1/pan_cc42", "", nullptr);
          synth.dispatchMessage(client, 0, "/region2/pan_cc2", "", nullptr);
          std::vector<std::string> expected {
              "/region0/pan_cc42,N : {  }",
              "/region1/pan_cc42,f : { 4.2 }",
              "/region2/pan_cc2,f : { -10 }",
          };
          REQUIRE(messageList == expected);
      }
  
      SECTION("CC Params")
      {
          synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"(
              <region> sample=kick.wav
              <region> sample=kick.wav pan_stepcc42=4.2
              <region> sample=kick.wav pan_smoothcc42=4
              <region> sample=kick.wav pan_curvecc42=2
              <region> sample=kick.wav pan_stepcc42=-1
              <region> sample=kick.wav pan_smoothcc42=-4
              <region> sample=kick.wav pan_curvecc42=300
          )");
          synth.dispatchMessage(client, 0, "/region0/pan_stepcc42", "", nullptr);
          synth.dispatchMessage(client, 0, "/region0/pan_smoothcc42", "", nullptr);
          synth.dispatchMessage(client, 0, "/region0/pan_curvecc42", "", nullptr);
          synth.dispatchMessage(client, 0, "/region1/pan_stepcc42", "", nullptr);
          synth.dispatchMessage(client, 0, "/region2/pan_smoothcc42", "", nullptr);
          synth.dispatchMessage(client, 0, "/region3/pan_curvecc42", "", nullptr);
          // TODO: activate for the new region parser ; ignore oob
          // synth.dispatchMessage(client, 0, "/region4/pan_stepcc42", "", nullptr);
          // synth.dispatchMessage(client, 0, "/region5/pan_smoothcc42", "", nullptr);
          // synth.dispatchMessage(client, 0, "/region6/pan_curvecc42", "", nullptr);
          std::vector<std::string> expected {
              "/region0/pan_stepcc42,N : {  }",
              "/region0/pan_smoothcc42,N : {  }",
              "/region0/pan_curvecc42,N : {  }",
              "/region1/pan_stepcc42,f : { 4.2 }",
              "/region2/pan_smoothcc42,i : { 4 }",
              "/region3/pan_curvecc42,i : { 2 }",
              // "/region4/pan_stepcc42,N : {  }",
              // "/region5/pan_smoothcc42,N : {  }",
              // "/region6/pan_curvecc42,N : {  }",
          };
          REQUIRE(messageList == expected);
      }
  }
  
  TEST_CASE("[Values] Width")
  {
      Synth synth;
      std::vector<std::string> messageList;
      Client client(&messageList);
      client.setReceiveCallback(&simpleMessageReceiver);
  
      SECTION("Basic")
      {
          synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"(
              <region> sample=kick.wav
              <region> sample=kick.wav width=4.2
              <region> sample=kick.wav width=-200
          )");
          synth.dispatchMessage(client, 0, "/region0/width", "", nullptr);
          synth.dispatchMessage(client, 0, "/region1/width", "", nullptr);
          // TODO: activate for the new region parser ; accept oob
          // synth.dispatchMessage(client, 0, "/region2/width", "", nullptr);
          std::vector<std::string> expected {
              "/region0/width,f : { 100 }",
              "/region1/width,f : { 4.2 }",
              // TODO: activate for the new region parser ; accept oob
              // "/region2/width,f : { -200 }",
          };
          REQUIRE(messageList == expected);
      }
  
      SECTION("CC Depth")
      {
          synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"(
              <region> sample=kick.wav
              <region> sample=kick.wav width_oncc42=4.2
              <region> sample=kick.wav width_oncc2=-10
          )");
          synth.dispatchMessage(client, 0, "/region0/width_cc42", "", nullptr);
          synth.dispatchMessage(client, 0, "/region1/width_cc42", "", nullptr);
          synth.dispatchMessage(client, 0, "/region2/width_cc2", "", nullptr);
          std::vector<std::string> expected {
              "/region0/width_cc42,N : {  }",
              "/region1/width_cc42,f : { 4.2 }",
              "/region2/width_cc2,f : { -10 }",
          };
          REQUIRE(messageList == expected);
      }
  
      SECTION("CC Params")
      {
          synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"(
              <region> sample=kick.wav
              <region> sample=kick.wav width_stepcc42=4.2
              <region> sample=kick.wav width_smoothcc42=4
              <region> sample=kick.wav width_curvecc42=2
              <region> sample=kick.wav width_stepcc42=-1
              <region> sample=kick.wav width_smoothcc42=-4
              <region> sample=kick.wav width_curvecc42=300
          )");
          synth.dispatchMessage(client, 0, "/region0/width_stepcc42", "", nullptr);
          synth.dispatchMessage(client, 0, "/region0/width_smoothcc42", "", nullptr);
          synth.dispatchMessage(client, 0, "/region0/width_curvecc42", "", nullptr);
          synth.dispatchMessage(client, 0, "/region1/width_stepcc42", "", nullptr);
          synth.dispatchMessage(client, 0, "/region2/width_smoothcc42", "", nullptr);
          synth.dispatchMessage(client, 0, "/region3/width_curvecc42", "", nullptr);
          // TODO: activate for the new region parser ; ignore oob
          // synth.dispatchMessage(client, 0, "/region4/width_stepcc42", "", nullptr);
          // synth.dispatchMessage(client, 0, "/region5/width_smoothcc42", "", nullptr);
          // synth.dispatchMessage(client, 0, "/region6/width_curvecc42", "", nullptr);
          std::vector<std::string> expected {
              "/region0/width_stepcc42,N : {  }",
              "/region0/width_smoothcc42,N : {  }",
              "/region0/width_curvecc42,N : {  }",
              "/region1/width_stepcc42,f : { 4.2 }",
              "/region2/width_smoothcc42,i : { 4 }",
              "/region3/width_curvecc42,i : { 2 }",
              // "/region4/width_stepcc42,N : {  }",
              // "/region5/width_smoothcc42,N : {  }",
              // "/region6/width_curvecc42,N : {  }",
          };
          REQUIRE(messageList == expected);
      }
  }
  
  TEST_CASE("[Values] Position")
  {
      Synth synth;
      std::vector<std::string> messageList;
      Client client(&messageList);
      client.setReceiveCallback(&simpleMessageReceiver);
  
      SECTION("Basic")
      {
          synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"(
              <region> sample=kick.wav
              <region> sample=kick.wav position=4.2
              <region> sample=kick.wav position=-200
          )");
          synth.dispatchMessage(client, 0, "/region0/position", "", nullptr);
          synth.dispatchMessage(client, 0, "/region1/position", "", nullptr);
          // TODO: activate for the new region parser; accept oob
          // synth.dispatchMessage(client, 0, "/region2/position", "", nullptr);
          std::vector<std::string> expected {
              "/region0/position,f : { 0 }",
              "/region1/position,f : { 4.2 }",
              // TODO: activate for the new region parser; accept oob
              // "/region2/position,f : { -200 }",
          };
          REQUIRE(messageList == expected);
      }
  
      SECTION("CC Depth")
      {
          synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"(
              <region> sample=kick.wav
              <region> sample=kick.wav position_oncc42=4.2
              <region> sample=kick.wav position_oncc2=-10
          )");
          synth.dispatchMessage(client, 0, "/region0/position_cc42", "", nullptr);
          synth.dispatchMessage(client, 0, "/region1/position_cc42", "", nullptr);
          synth.dispatchMessage(client, 0, "/region2/position_cc2", "", nullptr);
          std::vector<std::string> expected {
              "/region0/position_cc42,N : {  }",
              "/region1/position_cc42,f : { 4.2 }",
              "/region2/position_cc2,f : { -10 }",
          };
          REQUIRE(messageList == expected);
      }
  
      SECTION("CC Params")
      {
          synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"(
              <region> sample=kick.wav
              <region> sample=kick.wav position_stepcc42=4.2
              <region> sample=kick.wav position_smoothcc42=4
              <region> sample=kick.wav position_curvecc42=2
              <region> sample=kick.wav position_stepcc42=-1
              <region> sample=kick.wav position_smoothcc42=-4
              <region> sample=kick.wav position_curvecc42=300
          )");
          synth.dispatchMessage(client, 0, "/region0/position_stepcc42", "", nullptr);
          synth.dispatchMessage(client, 0, "/region0/position_smoothcc42", "", nullptr);
          synth.dispatchMessage(client, 0, "/region0/position_curvecc42", "", nullptr);
          synth.dispatchMessage(client, 0, "/region1/position_stepcc42", "", nullptr);
          synth.dispatchMessage(client, 0, "/region2/position_smoothcc42", "", nullptr);
          synth.dispatchMessage(client, 0, "/region3/position_curvecc42", "", nullptr);
          // TODO: activate for the new region parser ; ignore oob
          // synth.dispatchMessage(client, 0, "/region4/position_stepcc42", "", nullptr);
          // synth.dispatchMessage(client, 0, "/region5/position_smoothcc42", "", nullptr);
          // synth.dispatchMessage(client, 0, "/region6/position_curvecc42", "", nullptr);
          std::vector<std::string> expected {
              "/region0/position_stepcc42,N : {  }",
              "/region0/position_smoothcc42,N : {  }",
              "/region0/position_curvecc42,N : {  }",
              "/region1/position_stepcc42,f : { 4.2 }",
              "/region2/position_smoothcc42,i : { 4 }",
              "/region3/position_curvecc42,i : { 2 }",
              // "/region4/position_stepcc42,N : {  }",
              // "/region5/position_smoothcc42,N : {  }",
              // "/region6/position_curvecc42,N : {  }",
          };
          REQUIRE(messageList == expected);
      }
  }
  
  TEST_CASE("[Values] Amplitude")
  {
      Synth synth;
      std::vector<std::string> messageList;
      Client client(&messageList);
      client.setReceiveCallback(&simpleMessageReceiver);
  
      SECTION("Basic")
      {
          synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"(
              <region> sample=kick.wav
              <region> sample=kick.wav amplitude=4.2
              <region> sample=kick.wav amplitude=-200
          )");
          synth.dispatchMessage(client, 0, "/region0/amplitude", "", nullptr);
          synth.dispatchMessage(client, 0, "/region1/amplitude", "", nullptr);
          // TODO: activate for the new region parser; ignore oob
          // synth.dispatchMessage(client, 0, "/region2/amplitude", "", nullptr);
          std::vector<std::string> expected {
              "/region0/amplitude,f : { 100 }",
              "/region1/amplitude,f : { 4.2 }",
              // "/region2/amplitude,f : { 100 }",
          };
          REQUIRE(messageList == expected);
      }
  
      SECTION("CC Depth")
      {
          synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"(
              <region> sample=kick.wav
              <region> sample=kick.wav amplitude_oncc42=4.2
              <region> sample=kick.wav amplitude_oncc2=-10
          )");
          synth.dispatchMessage(client, 0, "/region0/amplitude_cc42", "", nullptr);
          synth.dispatchMessage(client, 0, "/region1/amplitude_cc42", "", nullptr);
          // TODO: activate for the new region parser ; ignore oob
          // synth.dispatchMessage(client, 0, "/region2/amplitude_cc2", "", nullptr);
          std::vector<std::string> expected {
              "/region0/amplitude_cc42,N : {  }",
              "/region1/amplitude_cc42,f : { 4.2 }",
              // "/region2/amplitude_cc2,N : {  }",
          };
          REQUIRE(messageList == expected);
      }
  
      SECTION("CC Params")
      {
          synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"(
              <region> sample=kick.wav
              <region> sample=kick.wav amplitude_stepcc42=4.2
              <region> sample=kick.wav amplitude_smoothcc42=4
              <region> sample=kick.wav amplitude_curvecc42=2
              <region> sample=kick.wav amplitude_stepcc42=-1
              <region> sample=kick.wav amplitude_smoothcc42=-4
              <region> sample=kick.wav amplitude_curvecc42=300
          )");
          synth.dispatchMessage(client, 0, "/region0/amplitude_stepcc42", "", nullptr);
          synth.dispatchMessage(client, 0, "/region0/amplitude_smoothcc42", "", nullptr);
          synth.dispatchMessage(client, 0, "/region0/amplitude_curvecc42", "", nullptr);
          synth.dispatchMessage(client, 0, "/region1/amplitude_stepcc42", "", nullptr);
          synth.dispatchMessage(client, 0, "/region2/amplitude_smoothcc42", "", nullptr);
          synth.dispatchMessage(client, 0, "/region3/amplitude_curvecc42", "", nullptr);
          // TODO: activate for the new region parser ; ignore oob
          // synth.dispatchMessage(client, 0, "/region4/amplitude_stepcc42", "", nullptr);
          // synth.dispatchMessage(client, 0, "/region5/amplitude_smoothcc42", "", nullptr);
          // synth.dispatchMessage(client, 0, "/region6/amplitude_curvecc42", "", nullptr);
          std::vector<std::string> expected {
              "/region0/amplitude_stepcc42,N : {  }",
              "/region0/amplitude_smoothcc42,N : {  }",
              "/region0/amplitude_curvecc42,N : {  }",
              "/region1/amplitude_stepcc42,f : { 4.2 }",
              "/region2/amplitude_smoothcc42,i : { 4 }",
              "/region3/amplitude_curvecc42,i : { 2 }",
              // "/region4/amplitude_stepcc42,N : {  }",
              // "/region5/amplitude_smoothcc42,N : {  }",
              // "/region6/amplitude_curvecc42,N : {  }",
          };
          REQUIRE(messageList == expected);
      }
  }
  
  TEST_CASE("[Values] Amp Keycenter")
  {
      Synth synth;
      std::vector<std::string> messageList;
      Client client(&messageList);
      client.setReceiveCallback(&simpleMessageReceiver);
  
      synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"(
          <region> sample=kick.wav
          <region> sample=kick.wav amp_keycenter=40
          <region> sample=kick.wav amp_keycenter=-1
          <region> sample=kick.wav amp_keycenter=c3
      )");
      synth.dispatchMessage(client, 0, "/region0/amp_keycenter", "", nullptr);
      synth.dispatchMessage(client, 0, "/region1/amp_keycenter", "", nullptr);
      // TODO: activate for the new region parser ; ignore oob and parse note
      // synth.dispatchMessage(client, 0, "/region2/amp_keycenter", "", nullptr);
      // synth.dispatchMessage(client, 0, "/region3/amp_keycenter", "", nullptr);
      std::vector<std::string> expected {
          "/region0/amp_keycenter,i : { 60 }",
          "/region1/amp_keycenter,i : { 40 }",
          // "/region2/amp_keycenter,i : { 60 }",
          // "/region3/amp_keycenter,i : { 48 }",
      };
      REQUIRE(messageList == expected);
  }
  
  TEST_CASE("[Values] Amp Keytrack")
  {
      Synth synth;
      std::vector<std::string> messageList;
      Client client(&messageList);
      client.setReceiveCallback(&simpleMessageReceiver);
  
      synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"(
          <region> sample=kick.wav
          <region> sample=kick.wav amp_keytrack=10.1
          <region> sample=kick.wav amp_keytrack=40
      )");
      synth.dispatchMessage(client, 0, "/region0/amp_keytrack", "", nullptr);
      synth.dispatchMessage(client, 0, "/region1/amp_keytrack", "", nullptr);
      // TODO: activate for the new region parser ; accept oob
      // synth.dispatchMessage(client, 0, "/region2/amp_keytrack", "", nullptr);
      std::vector<std::string> expected {
          "/region0/amp_keytrack,f : { 0 }",
          "/region1/amp_keytrack,f : { 10.1 }",
          // "/region2/amp_keytrack,f : { 40 }",
      };
      REQUIRE(messageList == expected);
  }
  
  TEST_CASE("[Values] Amp Veltrack")
  {
      Synth synth;
      std::vector<std::string> messageList;
      Client client(&messageList);
      client.setReceiveCallback(&simpleMessageReceiver);
  
      SECTION("Basic")
      {
          synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"(
              <region> sample=kick.wav
              <region> sample=kick.wav amp_veltrack=10.1
              <region> sample=kick.wav amp_veltrack=-132
          )");
          synth.dispatchMessage(client, 0, "/region0/amp_veltrack", "", nullptr);
          synth.dispatchMessage(client, 0, "/region1/amp_veltrack", "", nullptr);
          synth.dispatchMessage(client, 0, "/region2/amp_veltrack", "", nullptr);
          std::vector<std::string> expected {
              "/region0/amp_veltrack,f : { 100 }",
              "/region1/amp_veltrack,f : { 10.1 }",
              "/region2/amp_veltrack,f : { -132 }",
          };
          REQUIRE(messageList == expected);
      }
  
      SECTION("CC")
      {
          synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"(
              <region> sample=kick.wav
              <region> sample=kick.wav amp_veltrack_cc1=10.1 amp_veltrack_curvecc1=3
              <region> sample=kick.wav amp_veltrack_oncc2=-40 amp_veltrack_curvecc3=4
          )");
          synth.dispatchMessage(client, 0, "/region0/amp_veltrack_cc1", "", nullptr);
          synth.dispatchMessage(client, 0, "/region1/amp_veltrack_cc1", "", nullptr);
          synth.dispatchMessage(client, 0, "/region1/amp_veltrack_curvecc1", "", nullptr);
          synth.dispatchMessage(client, 0, "/region2/amp_veltrack_cc2", "", nullptr);
          synth.dispatchMessage(client, 0, "/region2/amp_veltrack_curvecc3", "", nullptr);
          // TODO: activate for the new region parser ; accept oob
          // synth.dispatchMessage(client, 0, "/region2/amp_veltrack", "", nullptr);
          std::vector<std::string> expected {
              "/region0/amp_veltrack_cc1,N : {  }",
              "/region1/amp_veltrack_cc1,f : { 10.1 }",
              "/region1/amp_veltrack_curvecc1,i : { 3 }",
              "/region2/amp_veltrack_cc2,f : { -40 }",
              "/region2/amp_veltrack_curvecc3,i : { 4 }",
          };
          REQUIRE(messageList == expected);
      }
  }
  
  TEST_CASE("[Values] Amp Random")
  {
      Synth synth;
      std::vector<std::string> messageList;
      Client client(&messageList);
      client.setReceiveCallback(&simpleMessageReceiver);
  
      synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"(
          <region> sample=kick.wav
          <region> sample=kick.wav amp_random=10.1
          <region> sample=kick.wav amp_random=-4
      )");
      synth.dispatchMessage(client, 0, "/region0/amp_random", "", nullptr);
      synth.dispatchMessage(client, 0, "/region1/amp_random", "", nullptr);
      // TODO: activate for the new region parser ; ignore oob
      // synth.dispatchMessage(client, 0, "/region2/amp_random", "", nullptr);
      std::vector<std::string> expected {
          "/region0/amp_random,f : { 0 }",
          "/region1/amp_random,f : { 10.1 }",
          // "/region2/amp_random,f : { 0 }",
      };
      REQUIRE(messageList == expected);
  }
  
  TEST_CASE("[Values] Crossfade key range")
  {
      Synth synth;
      std::vector<std::string> messageList;
      Client client(&messageList);
      client.setReceiveCallback(&simpleMessageReceiver);
  
      SECTION("Xfin")
      {
          synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"(
              <region> sample=kick.wav
              <region> sample=kick.wav xfin_lokey=10 xfin_hikey=40
              <region> sample=kick.wav xfin_lokey=c4 xfin_hikey=b5
              <region> sample=kick.wav xfin_lokey=-10 xfin_hikey=40
              <region> sample=kick.wav xfin_lokey=10 xfin_hikey=140
          )");
          synth.dispatchMessage(client, 0, "/region0/xfin_key_range", "", nullptr);
          synth.dispatchMessage(client, 0, "/region1/xfin_key_range", "", nullptr);
          synth.dispatchMessage(client, 0, "/region2/xfin_key_range", "", nullptr);
          synth.dispatchMessage(client, 0, "/region3/xfin_key_range", "", nullptr);
          synth.dispatchMessage(client, 0, "/region4/xfin_key_range", "", nullptr);
          std::vector<std::string> expected {
              "/region0/xfin_key_range,ii : { 0, 0 }",
              "/region1/xfin_key_range,ii : { 10, 40 }",
              "/region2/xfin_key_range,ii : { 60, 83 }",
              "/region3/xfin_key_range,ii : { 0, 40 }",
              "/region4/xfin_key_range,ii : { 10, 0 }",
          };
          REQUIRE(messageList == expected);
      }
  
      SECTION("Xfout")
      {
          synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"(
              <region> sample=kick.wav
              <region> sample=kick.wav xfout_lokey=10 xfout_hikey=40
              <region> sample=kick.wav xfout_lokey=c4 xfout_hikey=b5
              <region> sample=kick.wav xfout_lokey=-10 xfout_hikey=40
              <region> sample=kick.wav xfout_lokey=10 xfout_hikey=140
          )");
          synth.dispatchMessage(client, 0, "/region0/xfout_key_range", "", nullptr);
          synth.dispatchMessage(client, 0, "/region1/xfout_key_range", "", nullptr);
          synth.dispatchMessage(client, 0, "/region2/xfout_key_range", "", nullptr);
          synth.dispatchMessage(client, 0, "/region3/xfout_key_range", "", nullptr);
          synth.dispatchMessage(client, 0, "/region4/xfout_key_range", "", nullptr);
          std::vector<std::string> expected {
              "/region0/xfout_key_range,ii : { 127, 127 }",
              "/region1/xfout_key_range,ii : { 10, 40 }",
              "/region2/xfout_key_range,ii : { 60, 83 }",
              "/region3/xfout_key_range,ii : { 127, 40 }",
              "/region4/xfout_key_range,ii : { 10, 127 }",
          };
          REQUIRE(messageList == expected);
      }
  }
  
  
  TEST_CASE("[Values] Crossfade velocity range")
  {
      Synth synth;
      std::vector<std::string> messageList;
      Client client(&messageList);
      client.setReceiveCallback(&simpleMessageReceiver);
  
      SECTION("Xfin")
      {
          synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"(
              <region> sample=kick.wav
              <region> sample=kick.wav xfin_lovel=10 xfin_hivel=40
              <region> sample=kick.wav xfin_lovel=-10 xfin_hivel=40
              <region> sample=kick.wav xfin_lovel=10 xfin_hivel=140
          )");
          synth.dispatchMessage(client, 0, "/region0/xfin_vel_range", "", nullptr);
          synth.dispatchMessage(client, 0, "/region1/xfin_vel_range", "", nullptr);
          synth.dispatchMessage(client, 0, "/region2/xfin_vel_range", "", nullptr);
          synth.dispatchMessage(client, 0, "/region3/xfin_vel_range", "", nullptr);
          std::vector<std::string> expected {
              "/region0/xfin_vel_range,ff : { 0, 0 }",
              "/region1/xfin_vel_range,ff : { 0.0787402, 0.322835 }",
              "/region2/xfin_vel_range,ff : { -0.0787402, 0.322835 }",
              "/region3/xfin_vel_range,ff : { 0.0787402, 1.10236 }",
          };
          REQUIRE(messageList == expected);
      }
  
      SECTION("Xfout")
      {
          synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"(
              <region> sample=kick.wav
              <region> sample=kick.wav xfout_lovel=10 xfout_hivel=40
              <region> sample=kick.wav xfout_lovel=-10 xfout_hivel=40
              <region> sample=kick.wav xfout_lovel=10 xfout_hivel=140
          )");
          synth.dispatchMessage(client, 0, "/region0/xfout_vel_range", "", nullptr);
          synth.dispatchMessage(client, 0, "/region1/xfout_vel_range", "", nullptr);
          synth.dispatchMessage(client, 0, "/region2/xfout_vel_range", "", nullptr);
          synth.dispatchMessage(client, 0, "/region3/xfout_vel_range", "", nullptr);
          std::vector<std::string> expected {
              "/region0/xfout_vel_range,ff : { 1, 1 }",
              "/region1/xfout_vel_range,ff : { 0.0787402, 0.322835 }",
              "/region2/xfout_vel_range,ff : { -0.0787402, 0.322835 }",
              "/region3/xfout_vel_range,ff : { 0.0787402, 1.10236 }",
          };
          REQUIRE(messageList == expected);
      }
  }
  
  TEST_CASE("[Values] Crossfade curves")
  {
      Synth synth;
      std::vector<std::string> messageList;
      Client client(&messageList);
      client.setReceiveCallback(&simpleMessageReceiver);
  
      SECTION("Key")
      {
          synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"(
              <region> sample=kick.wav
              <region> sample=kick.wav xf_keycurve=gain
              <region> sample=kick.wav xf_keycurve=something
              <region> sample=kick.wav xf_keycurve=gain xf_keycurve=power
          )");
          synth.dispatchMessage(client, 0, "/region0/xf_keycurve", "", nullptr);
          synth.dispatchMessage(client, 0, "/region1/xf_keycurve", "", nullptr);
          synth.dispatchMessage(client, 0, "/region2/xf_keycurve", "", nullptr);
          synth.dispatchMessage(client, 0, "/region3/xf_keycurve", "", nullptr);
          std::vector<std::string> expected {
              "/region0/xf_keycurve,s : { power }",
              "/region1/xf_keycurve,s : { gain }",
              "/region2/xf_keycurve,s : { power }",
              "/region3/xf_keycurve,s : { power }",
          };
          REQUIRE(messageList == expected);
      }
  
      SECTION("Velocity")
      {
          synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"(
              <region> sample=kick.wav
              <region> sample=kick.wav xf_velcurve=gain
              <region> sample=kick.wav xf_velcurve=something
              <region> sample=kick.wav xf_velcurve=gain xf_velcurve=power
          )");
          synth.dispatchMessage(client, 0, "/region0/xf_velcurve", "", nullptr);
          synth.dispatchMessage(client, 0, "/region1/xf_velcurve", "", nullptr);
          synth.dispatchMessage(client, 0, "/region2/xf_velcurve", "", nullptr);
          synth.dispatchMessage(client, 0, "/region3/xf_velcurve", "", nullptr);
          std::vector<std::string> expected {
              "/region0/xf_velcurve,s : { power }",
              "/region1/xf_velcurve,s : { gain }",
              "/region2/xf_velcurve,s : { power }",
              "/region3/xf_velcurve,s : { power }",
          };
          REQUIRE(messageList == expected);
      }
  
      SECTION("CC")
      {
          synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"(
              <region> sample=kick.wav
              <region> sample=kick.wav xf_cccurve=gain
              <region> sample=kick.wav xf_cccurve=something
              <region> sample=kick.wav xf_cccurve=gain xf_cccurve=power
          )");
          synth.dispatchMessage(client, 0, "/region0/xf_cccurve", "", nullptr);
          synth.dispatchMessage(client, 0, "/region1/xf_cccurve", "", nullptr);
          synth.dispatchMessage(client, 0, "/region2/xf_cccurve", "", nullptr);
          synth.dispatchMessage(client, 0, "/region3/xf_cccurve", "", nullptr);
          std::vector<std::string> expected {
              "/region0/xf_cccurve,s : { power }",
              "/region1/xf_cccurve,s : { gain }",
              "/region2/xf_cccurve,s : { power }",
              "/region3/xf_cccurve,s : { power }",
          };
          REQUIRE(messageList == expected);
      }
  }
  
  TEST_CASE("[Values] Crossfade CC range")
  {
      Synth synth;
      std::vector<std::string> messageList;
      Client client(&messageList);
      client.setReceiveCallback(&simpleMessageReceiver);
  
      SECTION("Xfin")
      {
          synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"(
              <region> sample=kick.wav
              <region> sample=kick.wav xfin_locc4=10 xfin_hicc4=40
              <region> sample=kick.wav xfin_locc4=-10 xfin_hicc4=40
              <region> sample=kick.wav xfin_locc4=10 xfin_hicc4=140
          )");
          synth.dispatchMessage(client, 0, "/region0/xfin_cc_range4", "", nullptr);
          synth.dispatchMessage(client, 0, "/region1/xfin_cc_range4", "", nullptr);
          synth.dispatchMessage(client, 0, "/region2/xfin_cc_range4", "", nullptr);
          synth.dispatchMessage(client, 0, "/region3/xfin_cc_range4", "", nullptr);
          std::vector<std::string> expected {
              "/region0/xfin_cc_range4,N : {  }",
              "/region1/xfin_cc_range4,ff : { 0.0787402, 0.322835 }",
              "/region2/xfin_cc_range4,ff : { -0.0787402, 0.322835 }",
              "/region3/xfin_cc_range4,ff : { 0.0787402, 1.10236 }",
          };
          REQUIRE(messageList == expected);
      }
  
      SECTION("Xfout")
      {
          synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"(
              <region> sample=kick.wav
              <region> sample=kick.wav xfout_locc4=10 xfout_hicc4=40
              <region> sample=kick.wav xfout_locc4=-10 xfout_hicc4=40
              <region> sample=kick.wav xfout_locc4=10 xfout_hicc4=140
          )");
          synth.dispatchMessage(client, 0, "/region0/xfout_cc_range4", "", nullptr);
          synth.dispatchMessage(client, 0, "/region1/xfout_cc_range4", "", nullptr);
          synth.dispatchMessage(client, 0, "/region2/xfout_cc_range4", "", nullptr);
          synth.dispatchMessage(client, 0, "/region3/xfout_cc_range4", "", nullptr);
          std::vector<std::string> expected {
              "/region0/xfout_cc_range4,N : {  }",
              "/region1/xfout_cc_range4,ff : { 0.0787402, 0.322835 }",
              "/region2/xfout_cc_range4,ff : { -0.0787402, 0.322835 }",
              "/region3/xfout_cc_range4,ff : { 0.0787402, 1.10236 }",
          };
          REQUIRE(messageList == expected);
      }
  }
  
  TEST_CASE("[Values] Global volumes and amplitudes")
  {
      Synth synth;
      std::vector<std::string> messageList;
      Client client(&messageList);
      client.setReceiveCallback(&simpleMessageReceiver);
  
      SECTION("Volumes")
      {
          synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"(
              <region> sample=kick.wav
              <global> global_volume=4.4
              <master> master_volume=5.5
              <group> group_volume=6.6
              <region> sample=kick.wav
          )");
          synth.dispatchMessage(client, 0, "/region0/global_volume", "", nullptr);
          synth.dispatchMessage(client, 0, "/region0/master_volume", "", nullptr);
          synth.dispatchMessage(client, 0, "/region0/group_volume", "", nullptr);
          synth.dispatchMessage(client, 0, "/region1/global_volume", "", nullptr);
          synth.dispatchMessage(client, 0, "/region1/master_volume", "", nullptr);
          synth.dispatchMessage(client, 0, "/region1/group_volume", "", nullptr);
          std::vector<std::string> expected {
              "/region0/global_volume,f : { 0 }",
              "/region0/master_volume,f : { 0 }",
              "/region0/group_volume,f : { 0 }",
              "/region1/global_volume,f : { 4.4 }",
              "/region1/master_volume,f : { 5.5 }",
              "/region1/group_volume,f : { 6.6 }",
          };
          REQUIRE(messageList == expected);
      }
  
      SECTION("Amplitudes")
      {
          synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"(
              <region> sample=kick.wav
              <global> global_amplitude=4.4
              <master> master_amplitude=5.5
              <group> group_amplitude=6.6
              <region> sample=kick.wav
          )");
          synth.dispatchMessage(client, 0, "/region0/global_amplitude", "", nullptr);
          synth.dispatchMessage(client, 0, "/region0/master_amplitude", "", nullptr);
          synth.dispatchMessage(client, 0, "/region0/group_amplitude", "", nullptr);
          synth.dispatchMessage(client, 0, "/region1/global_amplitude", "", nullptr);
          synth.dispatchMessage(client, 0, "/region1/master_amplitude", "", nullptr);
          synth.dispatchMessage(client, 0, "/region1/group_amplitude", "", nullptr);
          std::vector<std::string> expected {
              "/region0/global_amplitude,f : { 100 }",
              "/region0/master_amplitude,f : { 100 }",
              "/region0/group_amplitude,f : { 100 }",
              "/region1/global_amplitude,f : { 4.4 }",
              "/region1/master_amplitude,f : { 5.5 }",
              "/region1/group_amplitude,f : { 6.6 }",
          };
          REQUIRE(messageList == expected);
      }
  }
  
  TEST_CASE("[Values] Pitch Keytrack")
  {
      Synth synth;
      std::vector<std::string> messageList;
      Client client(&messageList);
      client.setReceiveCallback(&simpleMessageReceiver);
  
      synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"(
          <region> sample=kick.wav
          <region> sample=kick.wav pitch_keytrack=1000
          <region> sample=kick.wav pitch_keytrack=-100
      )");
      synth.dispatchMessage(client, 0, "/region0/pitch_keytrack", "", nullptr);
      synth.dispatchMessage(client, 0, "/region1/pitch_keytrack", "", nullptr);
      synth.dispatchMessage(client, 0, "/region2/pitch_keytrack", "", nullptr);
      std::vector<std::string> expected {
          "/region0/pitch_keytrack,i : { 100 }",
          "/region1/pitch_keytrack,i : { 1000 }",
          "/region2/pitch_keytrack,i : { -100 }",
      };
      REQUIRE(messageList == expected);
  }
  
  TEST_CASE("[Values] Pitch Veltrack")
  {
      Synth synth;
      std::vector<std::string> messageList;
      Client client(&messageList);
      client.setReceiveCallback(&simpleMessageReceiver);
  
      SECTION("Basic")
      {
          synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"(
              <region> sample=kick.wav
              <region> sample=kick.wav pitch_veltrack=10
              <region> sample=kick.wav pitch_veltrack=-132
          )");
          synth.dispatchMessage(client, 0, "/region0/pitch_veltrack", "", nullptr);
          synth.dispatchMessage(client, 0, "/region1/pitch_veltrack", "", nullptr);
          synth.dispatchMessage(client, 0, "/region2/pitch_veltrack", "", nullptr);
          std::vector<std::string> expected {
              "/region0/pitch_veltrack,i : { 0 }",
              "/region1/pitch_veltrack,i : { 10 }",
              "/region2/pitch_veltrack,i : { -132 }",
          };
          REQUIRE(messageList == expected);
      }
  
      SECTION("CC")
      {
          synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"(
              <region> sample=kick.wav
              <region> sample=kick.wav pitch_veltrack_cc1=10.1 pitch_veltrack_curvecc1=3
              <region> sample=kick.wav pitch_veltrack_oncc2=-40 pitch_veltrack_curvecc3=4
          )");
          synth.dispatchMessage(client, 0, "/region0/pitch_veltrack_cc1", "", nullptr);
          synth.dispatchMessage(client, 0, "/region1/pitch_veltrack_cc1", "", nullptr);
          synth.dispatchMessage(client, 0, "/region1/pitch_veltrack_curvecc1", "", nullptr);
          synth.dispatchMessage(client, 0, "/region2/pitch_veltrack_cc2", "", nullptr);
          synth.dispatchMessage(client, 0, "/region2/pitch_veltrack_curvecc3", "", nullptr);
          // TODO: activate for the new region parser ; accept oob
          // synth.dispatchMessage(client, 0, "/region2/pitch_veltrack", "", nullptr);
          std::vector<std::string> expected {
              "/region0/pitch_veltrack_cc1,N : {  }",
              "/region1/pitch_veltrack_cc1,f : { 10.1 }",
              "/region1/pitch_veltrack_curvecc1,i : { 3 }",
              "/region2/pitch_veltrack_cc2,f : { -40 }",
              "/region2/pitch_veltrack_curvecc3,i : { 4 }",
          };
          REQUIRE(messageList == expected);
      }
  }
  
  TEST_CASE("[Values] Pitch Random")
  {
      Synth synth;
      std::vector<std::string> messageList;
      Client client(&messageList);
      client.setReceiveCallback(&simpleMessageReceiver);
  
      synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"(
          <region> sample=kick.wav
          <region> sample=kick.wav pitch_random=10
          <region> sample=kick.wav pitch_random=-4
      )");
      synth.dispatchMessage(client, 0, "/region0/pitch_random", "", nullptr);
      synth.dispatchMessage(client, 0, "/region1/pitch_random", "", nullptr);
      synth.dispatchMessage(client, 0, "/region2/pitch_random", "", nullptr);
      std::vector<std::string> expected {
          "/region0/pitch_random,f : { 0 }",
          "/region1/pitch_random,f : { 10 }",
          "/region2/pitch_random,f : { -4 }",
      };
      REQUIRE(messageList == expected);
  }
  
  TEST_CASE("[Values] Transpose")
  {
      Synth synth;
      std::vector<std::string> messageList;
      Client client(&messageList);
      client.setReceiveCallback(&simpleMessageReceiver);
  
      synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"(
          <region> sample=kick.wav
          <region> sample=kick.wav transpose=10
          <region> sample=kick.wav transpose=-4
          <region> sample=kick.wav transpose=-400
          <region> sample=kick.wav transpose=400
      )");
      synth.dispatchMessage(client, 0, "/region0/transpose", "", nullptr);
      synth.dispatchMessage(client, 0, "/region1/transpose", "", nullptr);
      synth.dispatchMessage(client, 0, "/region2/transpose", "", nullptr);
      synth.dispatchMessage(client, 0, "/region3/transpose", "", nullptr);
      synth.dispatchMessage(client, 0, "/region4/transpose", "", nullptr);
      std::vector<std::string> expected {
          "/region0/transpose,i : { 0 }",
          "/region1/transpose,i : { 10 }",
          "/region2/transpose,i : { -4 }",
          "/region3/transpose,i : { -400 }",
          "/region4/transpose,i : { 400 }",
      };
      REQUIRE(messageList == expected);
  }
  
  TEST_CASE("[Values] Pitch/Tune")
  {
      Synth synth;
      std::vector<std::string> messageList;
      Client client(&messageList);
      client.setReceiveCallback(&simpleMessageReceiver);
  
      SECTION("Basic")
      {
          synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"(
              <region> sample=kick.wav
              <region> sample=kick.wav pitch=4.2
              <region> sample=kick.wav tune=-200
          )");
          synth.dispatchMessage(client, 0, "/region0/pitch", "", nullptr);
          synth.dispatchMessage(client, 0, "/region1/pitch", "", nullptr);
          synth.dispatchMessage(client, 0, "/region2/pitch", "", nullptr);
          std::vector<std::string> expected {
              "/region0/pitch,f : { 0 }",
              "/region1/pitch,f : { 4.2 }",
              "/region2/pitch,f : { -200 }",
          };
          REQUIRE(messageList == expected);
      }
  
      SECTION("CC Depth")
      {
          synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"(
              <region> sample=kick.wav
              <region> sample=kick.wav pitch_oncc42=4.2
              <region> sample=kick.wav pitch_oncc2=-10
          )");
          synth.dispatchMessage(client, 0, "/region0/pitch_cc42", "", nullptr);
          synth.dispatchMessage(client, 0, "/region1/pitch_cc42", "", nullptr);
          synth.dispatchMessage(client, 0, "/region2/pitch_cc2", "", nullptr);
          std::vector<std::string> expected {
              "/region0/pitch_cc42,N : {  }",
              "/region1/pitch_cc42,f : { 4.2 }",
              "/region2/pitch_cc2,f : { -10 }",
          };
          REQUIRE(messageList == expected);
      }
  
      SECTION("CC Params")
      {
          synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"(
              <region> sample=kick.wav
              <region> sample=kick.wav pitch_stepcc42=4.2
              <region> sample=kick.wav pitch_smoothcc42=4
              <region> sample=kick.wav pitch_curvecc42=2
              <region> sample=kick.wav pitch_stepcc42=-1
              <region> sample=kick.wav pitch_smoothcc42=-4
              <region> sample=kick.wav pitch_curvecc42=300
          )");
          synth.dispatchMessage(client, 0, "/region0/pitch_stepcc42", "", nullptr);
          synth.dispatchMessage(client, 0, "/region0/pitch_smoothcc42", "", nullptr);
          synth.dispatchMessage(client, 0, "/region0/pitch_curvecc42", "", nullptr);
          synth.dispatchMessage(client, 0, "/region1/pitch_stepcc42", "", nullptr);
          synth.dispatchMessage(client, 0, "/region2/pitch_smoothcc42", "", nullptr);
          synth.dispatchMessage(client, 0, "/region3/pitch_curvecc42", "", nullptr);
          // TODO: activate for the new region parser ; ignore oob
          // synth.dispatchMessage(client, 0, "/region4/pitch_stepcc42", "", nullptr);
          // synth.dispatchMessage(client, 0, "/region5/pitch_smoothcc42", "", nullptr);
          // synth.dispatchMessage(client, 0, "/region6/pitch_curvecc42", "", nullptr);
          std::vector<std::string> expected {
              "/region0/pitch_stepcc42,N : {  }",
              "/region0/pitch_smoothcc42,N : {  }",
              "/region0/pitch_curvecc42,N : {  }",
              "/region1/pitch_stepcc42,f : { 4.2 }",
              "/region2/pitch_smoothcc42,i : { 4 }",
              "/region3/pitch_curvecc42,i : { 2 }",
              // "/region4/pitch_stepcc42,N : {  }",
              // "/region5/pitch_smoothcc42,N : {  }",
              // "/region6/pitch_curvecc42,N : {  }",
          };
          REQUIRE(messageList == expected);
      }
  
      SECTION("CC Params (with pitch_)")
      {
          synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"(
              <region> sample=kick.wav
              <region> sample=kick.wav pitch_stepcc42=4.2
              <region> sample=kick.wav pitch_smoothcc42=4
              <region> sample=kick.wav pitch_curvecc42=2
              <region> sample=kick.wav pitch_stepcc42=-1
              <region> sample=kick.wav pitch_smoothcc42=-4
              <region> sample=kick.wav pitch_curvecc42=300
          )");
          synth.dispatchMessage(client, 0, "/region0/pitch_stepcc42", "", nullptr);
          synth.dispatchMessage(client, 0, "/region0/pitch_smoothcc42", "", nullptr);
          synth.dispatchMessage(client, 0, "/region0/pitch_curvecc42", "", nullptr);
          synth.dispatchMessage(client, 0, "/region1/pitch_stepcc42", "", nullptr);
          synth.dispatchMessage(client, 0, "/region2/pitch_smoothcc42", "", nullptr);
          synth.dispatchMessage(client, 0, "/region3/pitch_curvecc42", "", nullptr);
          // TODO: activate for the new region parser ; ignore oob
          // synth.dispatchMessage(client, 0, "/region4/pitch_stepcc42", "", nullptr);
          // synth.dispatchMessage(client, 0, "/region5/pitch_smoothcc42", "", nullptr);
          // synth.dispatchMessage(client, 0, "/region6/pitch_curvecc42", "", nullptr);
          std::vector<std::string> expected {
              "/region0/pitch_stepcc42,N : {  }",
              "/region0/pitch_smoothcc42,N : {  }",
              "/region0/pitch_curvecc42,N : {  }",
              "/region1/pitch_stepcc42,f : { 4.2 }",
              "/region2/pitch_smoothcc42,i : { 4 }",
              "/region3/pitch_curvecc42,i : { 2 }",
              // "/region4/pitch_stepcc42,N : {  }",
              // "/region5/pitch_smoothcc42,N : {  }",
              // "/region6/pitch_curvecc42,N : {  }",
          };
          REQUIRE(messageList == expected);
      }
  }
  
  TEST_CASE("[Values] Bend behavior")
  {
      Synth synth;
      std::vector<std::string> messageList;
      Client client(&messageList);
      client.setReceiveCallback(&simpleMessageReceiver);
  
      synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"(
          <region> sample=kick.wav
          <region> sample=kick.wav bend_up=100 bend_down=-400 bend_step=10 bend_smooth=10
          <region> sample=kick.wav bend_up=-100 bend_down=400 bend_step=-10 bend_smooth=-10
      )");
      synth.dispatchMessage(client, 0, "/region0/bend_up", "", nullptr);
      synth.dispatchMessage(client, 0, "/region0/bend_down", "", nullptr);
      synth.dispatchMessage(client, 0, "/region0/bend_step", "", nullptr);
      synth.dispatchMessage(client, 0, "/region0/bend_smooth", "", nullptr);
      synth.dispatchMessage(client, 0, "/region1/bend_up", "", nullptr);
      synth.dispatchMessage(client, 0, "/region1/bend_down", "", nullptr);
      synth.dispatchMessage(client, 0, "/region1/bend_step", "", nullptr);
      synth.dispatchMessage(client, 0, "/region1/bend_smooth", "", nullptr);
      synth.dispatchMessage(client, 0, "/region2/bend_up", "", nullptr);
      synth.dispatchMessage(client, 0, "/region2/bend_down", "", nullptr);
      synth.dispatchMessage(client, 0, "/region2/bend_step", "", nullptr);
      synth.dispatchMessage(client, 0, "/region2/bend_smooth", "", nullptr);
      std::vector<std::string> expected {
          "/region0/bend_up,f : { 200 }",
          "/region0/bend_down,f : { -200 }",
          "/region0/bend_step,f : { 1 }",
          "/region0/bend_smooth,i : { 0 }",
          "/region1/bend_up,f : { 100 }",
          "/region1/bend_down,f : { -400 }",
          "/region1/bend_step,f : { 10 }",
          "/region1/bend_smooth,i : { 10 }",
          "/region2/bend_up,f : { -100 }",
          "/region2/bend_down,f : { 400 }",
          "/region2/bend_step,f : { 1 }",
          "/region2/bend_smooth,i : { 0 }",
      };
      REQUIRE(messageList == expected);
  }
  
  TEST_CASE("[Values] ampeg")
  {
      Synth synth;
      std::vector<std::string> messageList;
      Client client(&messageList);
      client.setReceiveCallback(&simpleMessageReceiver);
  
      SECTION("Basic")
      {
          synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"(
              <region> sample=kick.wav
              <region> sample=kick.wav
                  ampeg_attack=1 ampeg_delay=2 ampeg_decay=3
                  ampeg_hold=4 ampeg_release=5 ampeg_start=6
                  ampeg_sustain=7 ampeg_depth=8
              <region> sample=kick.wav
                  ampeg_attack=-1 ampeg_delay=-2 ampeg_decay=-3
                  ampeg_hold=-4 ampeg_release=-5 ampeg_start=-6
                  ampeg_sustain=-7 ampeg_depth=-8
          )");
          synth.dispatchMessage(client, 0, "/region0/ampeg_attack", "", nullptr);
          synth.dispatchMessage(client, 0, "/region0/ampeg_delay", "", nullptr);
          synth.dispatchMessage(client, 0, "/region0/ampeg_decay", "", nullptr);
          synth.dispatchMessage(client, 0, "/region0/ampeg_hold", "", nullptr);
          synth.dispatchMessage(client, 0, "/region0/ampeg_release", "", nullptr);
          synth.dispatchMessage(client, 0, "/region0/ampeg_start", "", nullptr);
          synth.dispatchMessage(client, 0, "/region0/ampeg_sustain", "", nullptr);
          synth.dispatchMessage(client, 0, "/region0/ampeg_depth", "", nullptr);
          synth.dispatchMessage(client, 0, "/region1/ampeg_attack", "", nullptr);
          synth.dispatchMessage(client, 0, "/region1/ampeg_delay", "", nullptr);
          synth.dispatchMessage(client, 0, "/region1/ampeg_decay", "", nullptr);
          synth.dispatchMessage(client, 0, "/region1/ampeg_hold", "", nullptr);
          synth.dispatchMessage(client, 0, "/region1/ampeg_release", "", nullptr);
          synth.dispatchMessage(client, 0, "/region1/ampeg_start", "", nullptr);
          synth.dispatchMessage(client, 0, "/region1/ampeg_sustain", "", nullptr);
          synth.dispatchMessage(client, 0, "/region1/ampeg_depth", "", nullptr);
          // TODO after new parser : ignore oob
          // synth.dispatchMessage(client, 0, "/region2/ampeg_attack", "", nullptr);
          // synth.dispatchMessage(client, 0, "/region2/ampeg_delay", "", nullptr);
          // synth.dispatchMessage(client, 0, "/region2/ampeg_decay", "", nullptr);
          // synth.dispatchMessage(client, 0, "/region2/ampeg_hold", "", nullptr);
          // synth.dispatchMessage(client, 0, "/region2/ampeg_release", "", nullptr);
          // synth.dispatchMessage(client, 0, "/region2/ampeg_start", "", nullptr);
          // synth.dispatchMessage(client, 0, "/region2/ampeg_sustain", "", nullptr);
          // synth.dispatchMessage(client, 0, "/region2/ampeg_depth", "", nullptr);
          std::vector<std::string> expected {
              "/region0/ampeg_attack,f : { 0 }",
              "/region0/ampeg_delay,f : { 0 }",
              "/region0/ampeg_decay,f : { 0 }",
              "/region0/ampeg_hold,f : { 0 }",
              "/region0/ampeg_release,f : { 0.001 }",
              "/region0/ampeg_start,f : { 0 }",
              "/region0/ampeg_sustain,f : { 100 }",
              "/region0/ampeg_depth,f : { 0 }",
              "/region1/ampeg_attack,f : { 1 }",
              "/region1/ampeg_delay,f : { 2 }",
              "/region1/ampeg_decay,f : { 3 }",
              "/region1/ampeg_hold,f : { 4 }",
              "/region1/ampeg_release,f : { 5 }",
              "/region1/ampeg_start,f : { 6 }",
              "/region1/ampeg_sustain,f : { 7 }",
              "/region1/ampeg_depth,f : { 0 }",
              // "/region2/ampeg_attack,f : { 0 }",
              // "/region2/ampeg_delay,f : { 0 }",
              // "/region2/ampeg_decay,f : { 0 }",
              // "/region2/ampeg_hold,f : { 0 }",
              // "/region2/ampeg_release,f : { 0.001 }",
              // "/region2/ampeg_start,f : { 0 }",
              // "/region2/ampeg_sustain,f : { 100 }",
              // "/region2/ampeg_depth,f : { 0 }",
          };
          REQUIRE(messageList == expected);
      }
  
      SECTION("Velocity")
      {
          synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"(
              <region> sample=kick.wav
              <region> sample=kick.wav
                  ampeg_vel2attack=1 ampeg_vel2delay=2 ampeg_vel2decay=3
                  ampeg_vel2hold=4 ampeg_vel2release=5
                  ampeg_vel2sustain=7 ampeg_vel2depth=8
          )");
          synth.dispatchMessage(client, 0, "/region0/ampeg_vel2attack", "", nullptr);
          synth.dispatchMessage(client, 0, "/region0/ampeg_vel2delay", "", nullptr);
          synth.dispatchMessage(client, 0, "/region0/ampeg_vel2decay", "", nullptr);
          synth.dispatchMessage(client, 0, "/region0/ampeg_vel2hold", "", nullptr);
          synth.dispatchMessage(client, 0, "/region0/ampeg_vel2release", "", nullptr);
          synth.dispatchMessage(client, 0, "/region0/ampeg_vel2sustain", "", nullptr);
          synth.dispatchMessage(client, 0, "/region0/ampeg_vel2depth", "", nullptr);
          synth.dispatchMessage(client, 0, "/region1/ampeg_vel2attack", "", nullptr);
          synth.dispatchMessage(client, 0, "/region1/ampeg_vel2delay", "", nullptr);
          synth.dispatchMessage(client, 0, "/region1/ampeg_vel2decay", "", nullptr);
          synth.dispatchMessage(client, 0, "/region1/ampeg_vel2hold", "", nullptr);
          synth.dispatchMessage(client, 0, "/region1/ampeg_vel2release", "", nullptr);
          synth.dispatchMessage(client, 0, "/region1/ampeg_vel2sustain", "", nullptr);
          synth.dispatchMessage(client, 0, "/region1/ampeg_vel2depth", "", nullptr);
          std::vector<std::string> expected {
              "/region0/ampeg_vel2attack,f : { 0 }",
              "/region0/ampeg_vel2delay,f : { 0 }",
              "/region0/ampeg_vel2decay,f : { 0 }",
              "/region0/ampeg_vel2hold,f : { 0 }",
              "/region0/ampeg_vel2release,f : { 0 }",
              "/region0/ampeg_vel2sustain,f : { 0 }",
              "/region0/ampeg_vel2depth,f : { 0 }",
              "/region1/ampeg_vel2attack,f : { 1 }",
              "/region1/ampeg_vel2delay,f : { 2 }",
              "/region1/ampeg_vel2decay,f : { 3 }",
              "/region1/ampeg_vel2hold,f : { 4 }",
              "/region1/ampeg_vel2release,f : { 5 }",
              "/region1/ampeg_vel2sustain,f : { 7 }",
              "/region1/ampeg_vel2depth,f : { 0 }",
          };
          REQUIRE(messageList == expected);
      }
  }
  
  TEST_CASE("[Values] Note polyphony")
  {
      Synth synth;
      std::vector<std::string> messageList;
      Client client(&messageList);
      client.setReceiveCallback(&simpleMessageReceiver);
  
      synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"(
          <region> sample=kick.wav
          <region> sample=kick.wav note_polyphony=10
          <region> sample=kick.wav note_polyphony=-4
          <region> sample=kick.wav note_polyphony=10 note_polyphony=-4
      )");
      synth.dispatchMessage(client, 0, "/region0/note_polyphony", "", nullptr);
      synth.dispatchMessage(client, 0, "/region1/note_polyphony", "", nullptr);
      // TODO: activate for the new region parser ; ignore oob
      // synth.dispatchMessage(client, 0, "/region2/note_polyphony", "", nullptr);
      // synth.dispatchMessage(client, 0, "/region3/note_polyphony", "", nullptr);
      std::vector<std::string> expected {
          "/region0/note_polyphony,N : {  }",
          "/region1/note_polyphony,i : { 10 }",
          // "/region2/note_polyphony,N : {  }",
          // "/region3/note_polyphony,i : { 10 }",
      };
      REQUIRE(messageList == expected);
  }
  
  TEST_CASE("[Values] Self-mask")
  {
      Synth synth;
      std::vector<std::string> messageList;
      Client client(&messageList);
      client.setReceiveCallback(&simpleMessageReceiver);
  
      synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"(
          <region> sample=kick.wav
          <region> sample=kick.wav note_selfmask=off
          <region> sample=kick.wav note_selfmask=off note_selfmask=on
          <region> sample=kick.wav note_selfmask=off note_selfmask=garbage
      )");
      synth.dispatchMessage(client, 0, "/region0/note_selfmask", "", nullptr);
      synth.dispatchMessage(client, 0, "/region1/note_selfmask", "", nullptr);
      synth.dispatchMessage(client, 0, "/region2/note_selfmask", "", nullptr);
      synth.dispatchMessage(client, 0, "/region3/note_selfmask", "", nullptr);
      std::vector<std::string> expected {
          "/region0/note_selfmask,T : {  }",
          "/region1/note_selfmask,F : {  }",
          "/region2/note_selfmask,T : {  }",
          "/region3/note_selfmask,T : {  }",
      };
      REQUIRE(messageList == expected);
  }
  
  TEST_CASE("[Values] RT dead")
  {
      Synth synth;
      std::vector<std::string> messageList;
      Client client(&messageList);
      client.setReceiveCallback(&simpleMessageReceiver);
  
      synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"(
          <region> sample=kick.wav
          <region> sample=kick.wav rt_dead=on
          <region> sample=kick.wav rt_dead=on rt_dead=off
          <region> sample=kick.wav rt_dead=on rt_dead=garbage
      )");
      synth.dispatchMessage(client, 0, "/region0/rt_dead", "", nullptr);
      synth.dispatchMessage(client, 0, "/region1/rt_dead", "", nullptr);
      synth.dispatchMessage(client, 0, "/region2/rt_dead", "", nullptr);
      synth.dispatchMessage(client, 0, "/region3/rt_dead", "", nullptr);
      std::vector<std::string> expected {
          "/region0/rt_dead,F : {  }",
          "/region1/rt_dead,T : {  }",
          "/region2/rt_dead,F : {  }",
          "/region3/rt_dead,F : {  }",
      };
      REQUIRE(messageList == expected);
  }
  
  TEST_CASE("[Values] Sustain switch")
  {
      Synth synth;
      std::vector<std::string> messageList;
      Client client(&messageList);
      client.setReceiveCallback(&simpleMessageReceiver);
  
      synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"(
          <region> sample=kick.wav
          <region> sample=kick.wav sustain_sw=off
          <region> sample=kick.wav sustain_sw=off sustain_sw=on
          <region> sample=kick.wav sustain_sw=off sustain_sw=garbage
      )");
      synth.dispatchMessage(client, 0, "/region0/sustain_sw", "", nullptr);
      synth.dispatchMessage(client, 0, "/region1/sustain_sw", "", nullptr);
      synth.dispatchMessage(client, 0, "/region2/sustain_sw", "", nullptr);
      synth.dispatchMessage(client, 0, "/region3/sustain_sw", "", nullptr);
      std::vector<std::string> expected {
          "/region0/sustain_sw,T : {  }",
          "/region1/sustain_sw,F : {  }",
          "/region2/sustain_sw,T : {  }",
          "/region3/sustain_sw,T : {  }",
      };
      REQUIRE(messageList == expected);
  }
  
  TEST_CASE("[Values] Sostenuto switch")
  {
      Synth synth;
      std::vector<std::string> messageList;
      Client client(&messageList);
      client.setReceiveCallback(&simpleMessageReceiver);
  
      synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"(
          <region> sample=kick.wav
          <region> sample=kick.wav sostenuto_sw=off
          <region> sample=kick.wav sostenuto_sw=off sostenuto_sw=on
          <region> sample=kick.wav sostenuto_sw=off sostenuto_sw=garbage
      )");
      synth.dispatchMessage(client, 0, "/region0/sostenuto_sw", "", nullptr);
      synth.dispatchMessage(client, 0, "/region1/sostenuto_sw", "", nullptr);
      synth.dispatchMessage(client, 0, "/region2/sostenuto_sw", "", nullptr);
      synth.dispatchMessage(client, 0, "/region3/sostenuto_sw", "", nullptr);
      std::vector<std::string> expected {
          "/region0/sostenuto_sw,T : {  }",
          "/region1/sostenuto_sw,F : {  }",
          "/region2/sostenuto_sw,T : {  }",
          "/region3/sostenuto_sw,T : {  }",
      };
      REQUIRE(messageList == expected);
  }
  
  TEST_CASE("[Values] Sustain CC")
  {
      Synth synth;
      std::vector<std::string> messageList;
      Client client(&messageList);
      client.setReceiveCallback(&simpleMessageReceiver);
  
      synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"(
          <region> sample=kick.wav
          <region> sample=kick.wav sustain_cc=10
          <region> sample=kick.wav sustain_cc=20 sustain_cc=-1
      )");
      synth.dispatchMessage(client, 0, "/region0/sustain_cc", "", nullptr);
      synth.dispatchMessage(client, 0, "/region1/sustain_cc", "", nullptr);
      synth.dispatchMessage(client, 0, "/region2/sustain_cc", "", nullptr);
      std::vector<std::string> expected {
          "/region0/sustain_cc,i : { 64 }",
          "/region1/sustain_cc,i : { 10 }",
          "/region2/sustain_cc,i : { 64 }",
      };
      REQUIRE(messageList == expected);
  }
  
  TEST_CASE("[Values] Sustain low")
  {
      Synth synth;
      std::vector<std::string> messageList;
      Client client(&messageList);
      client.setReceiveCallback(&simpleMessageReceiver);
  
      synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"(
          <region> sample=kick.wav
          <region> sample=kick.wav sustain_lo=10
          <region> sample=kick.wav sustain_lo=10 sustain_lo=-1
      )");
      synth.dispatchMessage(client, 0, "/region0/sustain_lo", "", nullptr);
      synth.dispatchMessage(client, 0, "/region1/sustain_lo", "", nullptr);
      synth.dispatchMessage(client, 0, "/region2/sustain_lo", "", nullptr);
      std::vector<std::string> expected {
          "/region0/sustain_lo,f : { 0.00787402 }",
          "/region1/sustain_lo,f : { 0.0787402 }",
          "/region2/sustain_lo,f : { -0.00787402 }",
      };
      REQUIRE(messageList == expected);
  }
  
  TEST_CASE("[Values] Sostenuto CC")
  {
      Synth synth;
      std::vector<std::string> messageList;
      Client client(&messageList);
      client.setReceiveCallback(&simpleMessageReceiver);
  
      synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"(
          <region> sample=kick.wav
          <region> sample=kick.wav sostenuto_cc=10
          <region> sample=kick.wav sostenuto_cc=20 sostenuto_cc=-1
      )");
      synth.dispatchMessage(client, 0, "/region0/sostenuto_cc", "", nullptr);
      synth.dispatchMessage(client, 0, "/region1/sostenuto_cc", "", nullptr);
      synth.dispatchMessage(client, 0, "/region2/sostenuto_cc", "", nullptr);
      std::vector<std::string> expected {
          "/region0/sostenuto_cc,i : { 66 }",
          "/region1/sostenuto_cc,i : { 10 }",
          "/region2/sostenuto_cc,i : { 66 }",
      };
      REQUIRE(messageList == expected);
  }
  
  TEST_CASE("[Values] Sostenuto low")
  {
      Synth synth;
      std::vector<std::string> messageList;
      Client client(&messageList);
      client.setReceiveCallback(&simpleMessageReceiver);
  
      synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"(
          <region> sample=kick.wav
          <region> sample=kick.wav sostenuto_lo=10
          <region> sample=kick.wav sostenuto_lo=10 sostenuto_lo=-1
      )");
      synth.dispatchMessage(client, 0, "/region0/sostenuto_lo", "", nullptr);
      synth.dispatchMessage(client, 0, "/region1/sostenuto_lo", "", nullptr);
      synth.dispatchMessage(client, 0, "/region2/sostenuto_lo", "", nullptr);
      std::vector<std::string> expected {
          "/region0/sostenuto_lo,f : { 0.00787402 }",
          "/region1/sostenuto_lo,f : { 0.0787402 }",
          "/region2/sostenuto_lo,f : { -0.00787402 }",
      };
      REQUIRE(messageList == expected);
  }
  
  TEST_CASE("[Values] Oscillator phase")
  {
      Synth synth;
      std::vector<std::string> messageList;
      Client client(&messageList);
      client.setReceiveCallback(&simpleMessageReceiver);
  
      synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"(
          <region> sample=kick.wav
          <region> sample=kick.wav oscillator_phase=0.1
          <region> sample=kick.wav oscillator_phase=1.1
          <region> sample=kick.wav oscillator_phase=-1.2
      )");
      synth.dispatchMessage(client, 0, "/region0/oscillator_phase", "", nullptr);
      synth.dispatchMessage(client, 0, "/region1/oscillator_phase", "", nullptr);
      synth.dispatchMessage(client, 0, "/region2/oscillator_phase", "", nullptr);
      synth.dispatchMessage(client, 0, "/region3/oscillator_phase", "", nullptr);
      std::vector<std::string> expected {
          "/region0/oscillator_phase,f : { 0 }",
          "/region1/oscillator_phase,f : { 0.1 }",
          "/region2/oscillator_phase,f : { 0.1 }",
          "/region3/oscillator_phase,f : { -1 }",
      };
      REQUIRE(messageList == expected);
  }
  
  TEST_CASE("[Values] Oscillator quality")
  {
      Synth synth;
      std::vector<std::string> messageList;
      Client client(&messageList);
      client.setReceiveCallback(&simpleMessageReceiver);
  
      synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"(
          <region> sample=kick.wav
          <region> sample=kick.wav oscillator_quality=2
          <region> sample=kick.wav oscillator_quality=0 oscillator_quality=-2
      )");
      synth.dispatchMessage(client, 0, "/region0/oscillator_quality", "", nullptr);
      synth.dispatchMessage(client, 0, "/region1/oscillator_quality", "", nullptr);
      synth.dispatchMessage(client, 0, "/region2/oscillator_quality", "", nullptr);
      std::vector<std::string> expected {
          "/region0/oscillator_quality,N : {  }",
          "/region1/oscillator_quality,i : { 2 }",
          "/region2/oscillator_quality,N : {  }",
      };
      REQUIRE(messageList == expected);
  }
  
  TEST_CASE("[Values] Oscillator mode/multi")
  {
      Synth synth;
      std::vector<std::string> messageList;
      Client client(&messageList);
      client.setReceiveCallback(&simpleMessageReceiver);
  
      synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"(
          <region> sample=kick.wav
          <region> sample=kick.wav oscillator_mode=2
          <region> sample=kick.wav oscillator_mode=1 oscillator_mode=-2
          <region> sample=kick.wav oscillator_multi=9
          <region> sample=kick.wav oscillator_multi=-2
      )");
      synth.dispatchMessage(client, 0, "/region0/oscillator_mode", "", nullptr);
      synth.dispatchMessage(client, 0, "/region1/oscillator_mode", "", nullptr);
      synth.dispatchMessage(client, 0, "/region2/oscillator_mode", "", nullptr);
      synth.dispatchMessage(client, 0, "/region0/oscillator_multi", "", nullptr);
      synth.dispatchMessage(client, 0, "/region3/oscillator_multi", "", nullptr);
      synth.dispatchMessage(client, 0, "/region4/oscillator_multi", "", nullptr);
      std::vector<std::string> expected {
          "/region0/oscillator_mode,i : { 0 }",
          "/region1/oscillator_mode,i : { 2 }",
          "/region2/oscillator_mode,i : { 0 }",
          "/region0/oscillator_multi,i : { 1 }",
          "/region3/oscillator_multi,i : { 9 }",
          "/region4/oscillator_multi,i : { 1 }",
      };
      REQUIRE(messageList == expected);
  }
  
  TEST_CASE("[Values] Oscillator detune/mod depth")
  {
      Synth synth;
      std::vector<std::string> messageList;
      Client client(&messageList);
      client.setReceiveCallback(&simpleMessageReceiver);
  
      synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"(
          <region> sample=kick.wav
          <region> sample=kick.wav oscillator_detune=9.2
          <region> sample=kick.wav oscillator_detune=-1200.2
          <region> sample=kick.wav oscillator_mod_depth=1564.75
          <region> sample=kick.wav oscillator_mod_depth=-2.2
      )");
      synth.dispatchMessage(client, 0, "/region0/oscillator_detune", "", nullptr);
      synth.dispatchMessage(client, 0, "/region1/oscillator_detune", "", nullptr);
      synth.dispatchMessage(client, 0, "/region2/oscillator_detune", "", nullptr);
      synth.dispatchMessage(client, 0, "/region0/oscillator_mod_depth", "", nullptr);
      synth.dispatchMessage(client, 0, "/region3/oscillator_mod_depth", "", nullptr);
      synth.dispatchMessage(client, 0, "/region4/oscillator_mod_depth", "", nullptr);
      std::vector<std::string> expected {
          "/region0/oscillator_detune,f : { 0 }",
          "/region1/oscillator_detune,f : { 9.2 }",
          "/region2/oscillator_detune,f : { -1200.2 }",
          "/region0/oscillator_mod_depth,f : { 0 }",
          "/region3/oscillator_mod_depth,f : { 1564.75 }",
          "/region4/oscillator_mod_depth,f : { -2.2 }",
      };
      REQUIRE(messageList == expected);
  }
  
  TEST_CASE("[Values] Effect sends")
  {
      Synth synth;
      std::vector<std::string> messageList;
      Client client(&messageList);
      client.setReceiveCallback(&simpleMessageReceiver);
  
      synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"(
          <region> sample=kick.wav
          <region> sample=kick.wav effect1=10
          <region> sample=kick.wav effect2=50.4
          <region> sample=kick.wav effect1=-1
      )");
      synth.dispatchMessage(client, 0, "/region0/effect1", "", nullptr);
      synth.dispatchMessage(client, 0, "/region1/effect1", "", nullptr);
      synth.dispatchMessage(client, 0, "/region2/effect1", "", nullptr);
      synth.dispatchMessage(client, 0, "/region2/effect2", "", nullptr);
      synth.dispatchMessage(client, 0, "/region4/effect1", "", nullptr);
      std::vector<std::string> expected {
          // No reply to the first question
          "/region1/effect1,f : { 10 }",
          "/region2/effect1,f : { 0 }",
          "/region2/effect2,f : { 50.4 }",
          // No reply to the last question
      };
      REQUIRE(messageList == expected);
  }
  
  TEST_CASE("[Values] Support floating point for int values")
  {
      Synth synth;
      std::vector<std::string> messageList;
      Client client(&messageList);
      client.setReceiveCallback(&simpleMessageReceiver);
  
      synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"(
          <region> sample=kick.wav offset=1042.5
          <region> sample=kick.wav pitch_keytrack=-2.1
      )");
      synth.dispatchMessage(client, 0, "/region0/offset", "", nullptr);
      synth.dispatchMessage(client, 0, "/region1/pitch_keytrack", "", nullptr);
      std::vector<std::string> expected {
          "/region0/offset,h : { 1042 }",
          "/region1/pitch_keytrack,i : { -2 }",
      };
      REQUIRE(messageList == expected);
  }
  
  TEST_CASE("[Values] ampeg CC")
  {
      Synth synth;
      std::vector<std::string> messageList;
      Client client(&messageList);
      client.setReceiveCallback(&simpleMessageReceiver);
  
      SECTION("Basic")
      {
          synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"(
              <region> sample=kick.wav
          )");
          synth.dispatchMessage(client, 0, "/region0/ampeg_attack_cc1", "", nullptr);
          synth.dispatchMessage(client, 0, "/region0/ampeg_delay_cc2", "", nullptr);
          synth.dispatchMessage(client, 0, "/region0/ampeg_decay_cc3", "", nullptr);
          synth.dispatchMessage(client, 0, "/region0/ampeg_hold_cc4", "", nullptr);
          synth.dispatchMessage(client, 0, "/region0/ampeg_release_cc5", "", nullptr);
          synth.dispatchMessage(client, 0, "/region0/ampeg_start_cc6", "", nullptr);
          synth.dispatchMessage(client, 0, "/region0/ampeg_sustain_cc7", "", nullptr);
          std::vector<std::string> expected {
              "/region0/ampeg_attack_cc1,f : { 0 }",
              "/region0/ampeg_delay_cc2,f : { 0 }",
              "/region0/ampeg_decay_cc3,f : { 0 }",
              "/region0/ampeg_hold_cc4,f : { 0 }",
              "/region0/ampeg_release_cc5,f : { 0 }",
              "/region0/ampeg_start_cc6,f : { 0 }",
              "/region0/ampeg_sustain_cc7,f : { 0 }",
          };
          REQUIRE(messageList == expected);
      }
  
      SECTION("Positive values")
      {
          synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"(
              <region> sample=kick.wav
                  ampeg_attack_oncc1=1 ampeg_delay_oncc2=2 ampeg_decay_oncc3=3
                  ampeg_hold_oncc4=4 ampeg_release_oncc5=5 ampeg_start_oncc6=6
                  ampeg_sustain_oncc7=7
          )");
          synth.dispatchMessage(client, 0, "/region0/ampeg_attack_cc1", "", nullptr);
          synth.dispatchMessage(client, 0, "/region0/ampeg_delay_cc2", "", nullptr);
          synth.dispatchMessage(client, 0, "/region0/ampeg_decay_cc3", "", nullptr);
          synth.dispatchMessage(client, 0, "/region0/ampeg_hold_cc4", "", nullptr);
          synth.dispatchMessage(client, 0, "/region0/ampeg_release_cc5", "", nullptr);
          synth.dispatchMessage(client, 0, "/region0/ampeg_start_cc6", "", nullptr);
          synth.dispatchMessage(client, 0, "/region0/ampeg_sustain_cc7", "", nullptr);
          std::vector<std::string> expected {
              "/region0/ampeg_attack_cc1,f : { 1 }",
              "/region0/ampeg_delay_cc2,f : { 2 }",
              "/region0/ampeg_decay_cc3,f : { 3 }",
              "/region0/ampeg_hold_cc4,f : { 4 }",
              "/region0/ampeg_release_cc5,f : { 5 }",
              "/region0/ampeg_start_cc6,f : { 6 }",
              "/region0/ampeg_sustain_cc7,f : { 7 }",
          };
          REQUIRE(messageList == expected);
      }
  
      SECTION("Basic")
      {
          synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"(
              <region> sample=kick.wav
                  ampeg_attack_cc1=-1 ampeg_delay_cc2=-2 ampeg_decay_cc3=-3
                  ampeg_hold_cc4=-4 ampeg_release_cc5=-5 ampeg_start_cc6=-6
                  ampeg_sustain_cc7=-7
          )");
          synth.dispatchMessage(client, 0, "/region0/ampeg_attack_cc1", "", nullptr);
          synth.dispatchMessage(client, 0, "/region0/ampeg_delay_cc2", "", nullptr);
          synth.dispatchMessage(client, 0, "/region0/ampeg_decay_cc3", "", nullptr);
          synth.dispatchMessage(client, 0, "/region0/ampeg_hold_cc4", "", nullptr);
          synth.dispatchMessage(client, 0, "/region0/ampeg_release_cc5", "", nullptr);
          synth.dispatchMessage(client, 0, "/region0/ampeg_start_cc6", "", nullptr);
          synth.dispatchMessage(client, 0, "/region0/ampeg_sustain_cc7", "", nullptr);
          std::vector<std::string> expected {
              "/region0/ampeg_attack_cc1,f : { -1 }",
              "/region0/ampeg_delay_cc2,f : { -2 }",
              "/region0/ampeg_decay_cc3,f : { -3 }",
              "/region0/ampeg_hold_cc4,f : { -4 }",
              "/region0/ampeg_release_cc5,f : { -5 }",
              "/region0/ampeg_start_cc6,f : { -6 }",
              "/region0/ampeg_sustain_cc7,f : { -7 }",
          };
          REQUIRE(messageList == expected);
      }
  }
  
  TEST_CASE("[Values] Filter stacking and cutoffs")
  {
      Synth synth;
      std::vector<std::string> messageList;
      Client client(&messageList);
      client.setReceiveCallback(&simpleMessageReceiver);
  
      synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"(
          <region> sample=kick.wav
          <region> sample=kick.wav cutoff=50
          <region> sample=kick.wav cutoff2=500
      )");
  
      SECTION("Test first region")
      {
          synth.dispatchMessage(client, 0, "/region0/filter0/cutoff", "", nullptr);
          synth.dispatchMessage(client, 0, "/region0/filter0/gain", "", nullptr);
          synth.dispatchMessage(client, 0, "/region0/filter0/resonance", "", nullptr);
          synth.dispatchMessage(client, 0, "/region0/filter0/keycenter", "", nullptr);
          synth.dispatchMessage(client, 0, "/region0/filter0/keytrack", "", nullptr);
          synth.dispatchMessage(client, 0, "/region0/filter0/veltrack", "", nullptr);
          synth.dispatchMessage(client, 0, "/region0/filter0/type", "", nullptr);
          synth.dispatchMessage(client, 0, "/region0/filter1/cutoff", "", nullptr);
          synth.dispatchMessage(client, 0, "/region0/filter1/gain", "", nullptr);
          synth.dispatchMessage(client, 0, "/region0/filter1/resonance", "", nullptr);
          synth.dispatchMessage(client, 0, "/region0/filter1/keycenter", "", nullptr);
          synth.dispatchMessage(client, 0, "/region0/filter1/keytrack", "", nullptr);
          synth.dispatchMessage(client, 0, "/region0/filter1/veltrack", "", nullptr);
          synth.dispatchMessage(client, 0, "/region0/filter1/type", "", nullptr);
          std::vector<std::string> expected {
              // No filters
          };
          REQUIRE(messageList == expected);
      }
  
      SECTION("Test second region")
      {
          synth.dispatchMessage(client, 0, "/region1/filter0/cutoff", "", nullptr);
          synth.dispatchMessage(client, 0, "/region1/filter0/gain", "", nullptr);
          synth.dispatchMessage(client, 0, "/region1/filter0/resonance", "", nullptr);
          synth.dispatchMessage(client, 0, "/region1/filter0/keycenter", "", nullptr);
          synth.dispatchMessage(client, 0, "/region1/filter0/keytrack", "", nullptr);
          synth.dispatchMessage(client, 0, "/region1/filter0/veltrack", "", nullptr);
          synth.dispatchMessage(client, 0, "/region1/filter0/type", "", nullptr);
          synth.dispatchMessage(client, 0, "/region1/filter1/cutoff", "", nullptr);
          synth.dispatchMessage(client, 0, "/region1/filter1/gain", "", nullptr);
          synth.dispatchMessage(client, 0, "/region1/filter1/resonance", "", nullptr);
          synth.dispatchMessage(client, 0, "/region1/filter1/keycenter", "", nullptr);
          synth.dispatchMessage(client, 0, "/region1/filter1/keytrack", "", nullptr);
          synth.dispatchMessage(client, 0, "/region1/filter1/veltrack", "", nullptr);
          synth.dispatchMessage(client, 0, "/region1/filter1/type", "", nullptr);
          std::vector<std::string> expected {
              "/region1/filter0/cutoff,f : { 50 }",
              "/region1/filter0/gain,f : { 0 }",
              "/region1/filter0/resonance,f : { 0 }",
              "/region1/filter0/keycenter,i : { 60 }",
              "/region1/filter0/keytrack,i : { 0 }",
              "/region1/filter0/veltrack,i : { 0 }",
              "/region1/filter0/type,s : { lpf_2p }",
              // No second filter
          };
          REQUIRE(messageList == expected);
      }
  
      SECTION("Test third region")
      {
          synth.dispatchMessage(client, 0, "/region2/filter0/cutoff", "", nullptr);
          synth.dispatchMessage(client, 0, "/region2/filter0/gain", "", nullptr);
          synth.dispatchMessage(client, 0, "/region2/filter0/resonance", "", nullptr);
          synth.dispatchMessage(client, 0, "/region2/filter0/keycenter", "", nullptr);
          synth.dispatchMessage(client, 0, "/region2/filter0/keytrack", "", nullptr);
          synth.dispatchMessage(client, 0, "/region2/filter0/veltrack", "", nullptr);
          synth.dispatchMessage(client, 0, "/region2/filter0/type", "", nullptr);
          synth.dispatchMessage(client, 0, "/region2/filter1/cutoff", "", nullptr);
          synth.dispatchMessage(client, 0, "/region2/filter1/gain", "", nullptr);
          synth.dispatchMessage(client, 0, "/region2/filter1/resonance", "", nullptr);
          synth.dispatchMessage(client, 0, "/region2/filter1/keycenter", "", nullptr);
          synth.dispatchMessage(client, 0, "/region2/filter1/keytrack", "", nullptr);
          synth.dispatchMessage(client, 0, "/region2/filter1/veltrack", "", nullptr);
          synth.dispatchMessage(client, 0, "/region2/filter1/type", "", nullptr);
          std::vector<std::string> expected {
              // The first filter is default-filled
              "/region2/filter0/cutoff,f : { 0 }",
              "/region2/filter0/gain,f : { 0 }",
              "/region2/filter0/resonance,f : { 0 }",
              "/region2/filter0/keycenter,i : { 60 }",
              "/region2/filter0/keytrack,i : { 0 }",
              "/region2/filter0/veltrack,i : { 0 }",
              "/region2/filter0/type,s : { lpf_2p }",
              "/region2/filter1/cutoff,f : { 500 }",
              "/region2/filter1/gain,f : { 0 }",
              "/region2/filter1/resonance,f : { 0 }",
              "/region2/filter1/keycenter,i : { 60 }",
              "/region2/filter1/keytrack,i : { 0 }",
              "/region2/filter1/veltrack,i : { 0 }",
              "/region2/filter1/type,s : { lpf_2p }",
              // No second filter
          };
          REQUIRE(messageList == expected);
      }
  }
  
  TEST_CASE("[Values] Filter types")
  {
      Synth synth;
      std::vector<std::string> messageList;
      Client client(&messageList);
      client.setReceiveCallback(&simpleMessageReceiver);
  
      synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"(
          <region> sample=kick.wav fil_type=lpf_1p
          <region> sample=kick.wav fil_type=hpf_1p
          <region> sample=kick.wav fil_type=lpf_2p
          <region> sample=kick.wav fil_type=hpf_2p
          <region> sample=kick.wav fil_type=bpf_2p
          <region> sample=kick.wav fil_type=brf_2p
          <region> sample=kick.wav fil_type=bpf_1p
          <region> sample=kick.wav fil_type=brf_1p
          <region> sample=kick.wav fil_type=apf_1p
          <region> sample=kick.wav fil_type=lpf_2p_sv
          <region> sample=kick.wav fil_type=hpf_2p_sv
          <region> sample=kick.wav fil_type=bpf_2p_sv
          <region> sample=kick.wav fil_type=brf_2p_sv
          <region> sample=kick.wav fil_type=lpf_4p
          <region> sample=kick.wav fil_type=hpf_4p
          <region> sample=kick.wav fil_type=lpf_6p
          <region> sample=kick.wav fil_type=hpf_6p
          <region> sample=kick.wav fil_type=pink
          <region> sample=kick.wav fil_type=lsh
          <region> sample=kick.wav fil_type=hsh
          <region> sample=kick.wav fil_type=peq
          <region> sample=kick.wav fil2_type=peq
          <region> sample=kick.wav fil2_type=something
      )");
  
      synth.dispatchMessage(client, 0, "/region0/filter0/type", "", nullptr);
      synth.dispatchMessage(client, 0, "/region1/filter0/type", "", nullptr);
      synth.dispatchMessage(client, 0, "/region2/filter0/type", "", nullptr);
      synth.dispatchMessage(client, 0, "/region3/filter0/type", "", nullptr);
      synth.dispatchMessage(client, 0, "/region4/filter0/type", "", nullptr);
      synth.dispatchMessage(client, 0, "/region5/filter0/type", "", nullptr);
      synth.dispatchMessage(client, 0, "/region6/filter0/type", "", nullptr);
      synth.dispatchMessage(client, 0, "/region7/filter0/type", "", nullptr);
      synth.dispatchMessage(client, 0, "/region8/filter0/type", "", nullptr);
      synth.dispatchMessage(client, 0, "/region9/filter0/type", "", nullptr);
      synth.dispatchMessage(client, 0, "/region10/filter0/type", "", nullptr);
      synth.dispatchMessage(client, 0, "/region11/filter0/type", "", nullptr);
      synth.dispatchMessage(client, 0, "/region12/filter0/type", "", nullptr);
      synth.dispatchMessage(client, 0, "/region13/filter0/type", "", nullptr);
      synth.dispatchMessage(client, 0, "/region14/filter0/type", "", nullptr);
      synth.dispatchMessage(client, 0, "/region15/filter0/type", "", nullptr);
      synth.dispatchMessage(client, 0, "/region16/filter0/type", "", nullptr);
      synth.dispatchMessage(client, 0, "/region17/filter0/type", "", nullptr);
      synth.dispatchMessage(client, 0, "/region18/filter0/type", "", nullptr);
      synth.dispatchMessage(client, 0, "/region19/filter0/type", "", nullptr);
      synth.dispatchMessage(client, 0, "/region20/filter0/type", "", nullptr);
      synth.dispatchMessage(client, 0, "/region21/filter1/type", "", nullptr);
      synth.dispatchMessage(client, 0, "/region22/filter1/type", "", nullptr);
      std::vector<std::string> expected {
          "/region0/filter0/type,s : { lpf_1p }",
          "/region1/filter0/type,s : { hpf_1p }",
          "/region2/filter0/type,s : { lpf_2p }",
          "/region3/filter0/type,s : { hpf_2p }",
          "/region4/filter0/type,s : { bpf_2p }",
          "/region5/filter0/type,s : { brf_2p }",
          "/region6/filter0/type,s : { bpf_1p }",
          "/region7/filter0/type,s : { brf_2p }", // If we have a 1-pole brf at one point, change it back
          "/region8/filter0/type,s : { none }", // If the apf 1-pole works, change it back
          "/region9/filter0/type,s : { lpf_2p_sv }",
          "/region10/filter0/type,s : { hpf_2p_sv }",
          "/region11/filter0/type,s : { bpf_2p_sv }",
          "/region12/filter0/type,s : { brf_2p_sv }",
          "/region13/filter0/type,s : { lpf_4p }",
          "/region14/filter0/type,s : { hpf_4p }",
          "/region15/filter0/type,s : { lpf_6p }",
          "/region16/filter0/type,s : { hpf_6p }",
          "/region17/filter0/type,s : { pink }",
          "/region18/filter0/type,s : { lsh }",
          "/region19/filter0/type,s : { hsh }",
          "/region20/filter0/type,s : { peq }",
          "/region21/filter1/type,s : { peq }",
          "/region22/filter1/type,s : { none }",
      };
      REQUIRE(messageList == expected);
  }
  
  TEST_CASE("[Values] Filter dispatching")
  {
      Synth synth;
      std::vector<std::string> messageList;
      Client client(&messageList);
      client.setReceiveCallback(&simpleMessageReceiver);
  
      synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"(
          <region> sample=kick.wav
              cutoff3=50 resonance2=3 fil2_gain=-5 fil3_keytrack=100
              fil_gain=5 fil1_gain=-5 fil2_veltrack=-100
              fil4_veltrack_cc7=-100 fil5_veltrack_curvecc2=2
      )");
  
      synth.dispatchMessage(client, 0, "/region0/filter2/cutoff", "", nullptr);
      synth.dispatchMessage(client, 0, "/region0/filter1/resonance", "", nullptr);
      synth.dispatchMessage(client, 0, "/region0/filter1/gain", "", nullptr);
      synth.dispatchMessage(client, 0, "/region0/filter2/keytrack", "", nullptr);
      synth.dispatchMessage(client, 0, "/region0/filter0/gain", "", nullptr);
      synth.dispatchMessage(client, 0, "/region0/filter1/veltrack", "", nullptr);
      synth.dispatchMessage(client, 0, "/region0/filter3/veltrack_cc7", "", nullptr);
      synth.dispatchMessage(client, 0, "/region0/filter4/veltrack_curvecc2", "", nullptr);
      std::vector<std::string> expected {
          "/region0/filter2/cutoff,f : { 50 }",
          "/region0/filter1/resonance,f : { 3 }",
          "/region0/filter1/gain,f : { -5 }",
          "/region0/filter2/keytrack,i : { 100 }",
          "/region0/filter0/gain,f : { -5 }",
          "/region0/filter1/veltrack,i : { -100 }",
          "/region0/filter3/veltrack_cc7,f : { -100 }",
          "/region0/filter4/veltrack_curvecc2,i : { 2 }",
      };
      REQUIRE(messageList == expected);
  }
  
  TEST_CASE("[Values] Filter value bounds")
  {
      Synth synth;
      std::vector<std::string> messageList;
      Client client(&messageList);
      client.setReceiveCallback(&simpleMessageReceiver);
  
      SECTION("Cutoff")
      {
          synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"(
              <region> sample=kick.wav cutoff=100000
              <region> sample=kick.wav cutoff=50 cutoff=-100
          )");
          synth.dispatchMessage(client, 0, "/region0/filter0/cutoff", "", nullptr);
          synth.dispatchMessage(client, 0, "/region1/filter0/cutoff", "", nullptr);
          std::vector<std::string> expected {
              "/region0/filter0/cutoff,f : { 100000 }",
              "/region1/filter0/cutoff,f : { -100 }",
          };
          REQUIRE(messageList == expected);
      }
  
      SECTION("Cutoff")
      {
          synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"(
              <region> sample=kick.wav resonance=5 resonance=-5
          )");
          synth.dispatchMessage(client, 0, "/region0/filter0/resonance", "", nullptr);
          std::vector<std::string> expected {
              "/region0/filter0/resonance,f : { -5 }",
          };
          REQUIRE(messageList == expected);
      }
  
      SECTION("Keycenter")
      {
          synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"(
              <region> sample=kick.wav fil_keycenter=40
              <region> sample=kick.wav fil_keycenter=40 fil_keycenter=1000
              <region> sample=kick.wav fil_keycenter=c3
          )");
          synth.dispatchMessage(client, 0, "/region0/filter0/keycenter", "", nullptr);
          synth.dispatchMessage(client, 0, "/region1/filter0/keycenter", "", nullptr);
          synth.dispatchMessage(client, 0, "/region2/filter0/keycenter", "", nullptr);
          std::vector<std::string> expected {
              "/region0/filter0/keycenter,i : { 40 }",
              "/region1/filter0/keycenter,i : { 60 }",
              "/region2/filter0/keycenter,i : { 48 }",
          };
          REQUIRE(messageList == expected);
      }
  }
  
  TEST_CASE("[Values] EQ stacking and gains")
  {
      Synth synth;
      std::vector<std::string> messageList;
      Client client(&messageList);
      client.setReceiveCallback(&simpleMessageReceiver);
  
      synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"(
          <region> sample=kick.wav
          <region> sample=kick.wav eq1_gain=3
          <region> sample=kick.wav eq4_gain=6
      )");
  
      SECTION("Test first region")
      {
          synth.dispatchMessage(client, 0, "/region0/eq0/gain", "", nullptr);
          synth.dispatchMessage(client, 0, "/region0/eq0/type", "", nullptr);
          synth.dispatchMessage(client, 0, "/region0/eq0/bandwidth", "", nullptr);
          synth.dispatchMessage(client, 0, "/region0/eq0/frequency", "", nullptr);
          synth.dispatchMessage(client, 0, "/region0/eq0/vel2gain", "", nullptr);
          synth.dispatchMessage(client, 0, "/region0/eq0/vel2freq", "", nullptr);
          synth.dispatchMessage(client, 0, "/region0/eq1/gain", "", nullptr);
          synth.dispatchMessage(client, 0, "/region0/eq1/type", "", nullptr);
          synth.dispatchMessage(client, 0, "/region0/eq1/bandwidth", "", nullptr);
          synth.dispatchMessage(client, 0, "/region0/eq1/frequency", "", nullptr);
          synth.dispatchMessage(client, 0, "/region0/eq1/vel2gain", "", nullptr);
          synth.dispatchMessage(client, 0, "/region0/eq1/vel2freq", "", nullptr);
          std::vector<std::string> expected {
              // No eqs
          };
          REQUIRE(messageList == expected);
      }
  
      SECTION("Test second region")
      {
          synth.dispatchMessage(client, 0, "/region1/eq0/gain", "", nullptr);
          synth.dispatchMessage(client, 0, "/region1/eq0/type", "", nullptr);
          synth.dispatchMessage(client, 0, "/region1/eq0/bandwidth", "", nullptr);
          synth.dispatchMessage(client, 0, "/region1/eq0/frequency", "", nullptr);
          synth.dispatchMessage(client, 0, "/region1/eq0/vel2gain", "", nullptr);
          synth.dispatchMessage(client, 0, "/region1/eq0/vel2freq", "", nullptr);
          synth.dispatchMessage(client, 0, "/region1/eq1/gain", "", nullptr);
          synth.dispatchMessage(client, 0, "/region1/eq1/type", "", nullptr);
          synth.dispatchMessage(client, 0, "/region1/eq1/bandwidth", "", nullptr);
          synth.dispatchMessage(client, 0, "/region1/eq1/frequency", "", nullptr);
          synth.dispatchMessage(client, 0, "/region1/eq1/vel2gain", "", nullptr);
          synth.dispatchMessage(client, 0, "/region1/eq1/vel2freq", "", nullptr);
          std::vector<std::string> expected {
              "/region1/eq0/gain,f : { 3 }",
              "/region1/eq0/type,s : { peak }",
              "/region1/eq0/bandwidth,f : { 1 }",
              "/region1/eq0/frequency,f : { 50 }",
              "/region1/eq0/vel2gain,f : { 0 }",
              "/region1/eq0/vel2freq,f : { 0 }",
              // No second eq
          };
          REQUIRE(messageList == expected);
      }
  
      SECTION("Test third region")
      {
          synth.dispatchMessage(client, 0, "/region2/eq0/gain", "", nullptr);
          synth.dispatchMessage(client, 0, "/region2/eq0/type", "", nullptr);
          synth.dispatchMessage(client, 0, "/region2/eq0/bandwidth", "", nullptr);
          synth.dispatchMessage(client, 0, "/region2/eq0/frequency", "", nullptr);
          synth.dispatchMessage(client, 0, "/region2/eq0/vel2gain", "", nullptr);
          synth.dispatchMessage(client, 0, "/region2/eq0/vel2freq", "", nullptr);
          synth.dispatchMessage(client, 0, "/region2/eq3/gain", "", nullptr);
          synth.dispatchMessage(client, 0, "/region2/eq3/type", "", nullptr);
          synth.dispatchMessage(client, 0, "/region2/eq3/bandwidth", "", nullptr);
          synth.dispatchMessage(client, 0, "/region2/eq3/frequency", "", nullptr);
          synth.dispatchMessage(client, 0, "/region2/eq3/vel2gain", "", nullptr);
          synth.dispatchMessage(client, 0, "/region2/eq3/vel2freq", "", nullptr);
          synth.dispatchMessage(client, 0, "/region2/eq1/frequency", "", nullptr);
          synth.dispatchMessage(client, 0, "/region2/eq2/frequency", "", nullptr);
          std::vector<std::string> expected {
              // The first eq is default-filled
              "/region2/eq0/gain,f : { 0 }",
              "/region2/eq0/type,s : { peak }",
              "/region2/eq0/bandwidth,f : { 1 }",
              "/region2/eq0/frequency,f : { 50 }",
              "/region2/eq0/vel2gain,f : { 0 }",
              "/region2/eq0/vel2freq,f : { 0 }",
              "/region2/eq3/gain,f : { 6 }",
              "/region2/eq3/type,s : { peak }",
              "/region2/eq3/bandwidth,f : { 1 }",
              "/region2/eq3/frequency,f : { 0 }",
              "/region2/eq3/vel2gain,f : { 0 }",
              "/region2/eq3/vel2freq,f : { 0 }",
              "/region2/eq1/frequency,f : { 500 }",
              "/region2/eq2/frequency,f : { 5000 }",
          };
          REQUIRE(messageList == expected);
      }
  }
  
  TEST_CASE("[Values] EQ types")
  {
      Synth synth;
      std::vector<std::string> messageList;
      Client client(&messageList);
      client.setReceiveCallback(&simpleMessageReceiver);
  
      synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"(
          <region> sample=kick.wav eq1_type=hshelf
          <region> sample=kick.wav eq1_type=lshelf
          <region> sample=kick.wav eq1_type=hshelf eq1_type=peak
          <region> sample=kick.wav eq1_type=something
      )");
  
      synth.dispatchMessage(client, 0, "/region0/eq0/type", "", nullptr);
      synth.dispatchMessage(client, 0, "/region1/eq0/type", "", nullptr);
      synth.dispatchMessage(client, 0, "/region2/eq0/type", "", nullptr);
      synth.dispatchMessage(client, 0, "/region3/eq0/type", "", nullptr);
      std::vector<std::string> expected {
          "/region0/eq0/type,s : { hshelf }",
          "/region1/eq0/type,s : { lshelf }",
          "/region2/eq0/type,s : { peak }",
          "/region3/eq0/type,s : { none }",
      };
      REQUIRE(messageList == expected);
  }
  
  TEST_CASE("[Values] EQ dispatching")
  {
      Synth synth;
      std::vector<std::string> messageList;
      Client client(&messageList);
      client.setReceiveCallback(&simpleMessageReceiver);
  
      synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"(
          <region> sample=kick.wav
              eq3_bw=2 eq1_gain=-25 eq2_freq=300 eq3_type=lshelf
              eq3_vel2gain=10 eq1_vel2freq=100
      )");
  
      synth.dispatchMessage(client, 0, "/region0/eq2/bandwidth", "", nullptr);
      synth.dispatchMessage(client, 0, "/region0/eq0/gain", "", nullptr);
      synth.dispatchMessage(client, 0, "/region0/eq1/frequency", "", nullptr);
      synth.dispatchMessage(client, 0, "/region0/eq2/type", "", nullptr);
      synth.dispatchMessage(client, 0, "/region0/eq2/vel2gain", "", nullptr);
      synth.dispatchMessage(client, 0, "/region0/eq0/vel2freq", "", nullptr);
      std::vector<std::string> expected {
          "/region0/eq2/bandwidth,f : { 2 }",
          "/region0/eq0/gain,f : { -25 }",
          "/region0/eq1/frequency,f : { 300 }",
          "/region0/eq2/type,s : { lshelf }",
          "/region0/eq2/vel2gain,f : { 10 }",
          "/region0/eq0/vel2freq,f : { 100 }",
      };
      REQUIRE(messageList == expected);
  }
  
  TEST_CASE("[Values] EQ value bounds")
  {
      Synth synth;
      std::vector<std::string> messageList;
      Client client(&messageList);
      client.setReceiveCallback(&simpleMessageReceiver);
  
      SECTION("Frequency")
      {
          synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"(
              <region> sample=kick.wav eq1_freq=100000
              <region> sample=kick.wav eq1_freq=50 eq1_freq=-100
          )");
          synth.dispatchMessage(client, 0, "/region0/eq0/frequency", "", nullptr);
          synth.dispatchMessage(client, 0, "/region1/eq0/frequency", "", nullptr);
          std::vector<std::string> expected {
              "/region0/eq0/frequency,f : { 100000 }",
              "/region1/eq0/frequency,f : { -100 }",
          };
          REQUIRE(messageList == expected);
      }
  
      SECTION("Bandwidth")
      {
          synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"(
              <region> sample=kick.wav eq1_bw=5 eq1_bw=-5
          )");
          synth.dispatchMessage(client, 0, "/region0/eq0/bandwidth", "", nullptr);
          std::vector<std::string> expected {
              "/region0/eq0/bandwidth,f : { -5 }",
          };
          REQUIRE(messageList == expected);
      }
  }
  
  TEST_CASE("[Values] Flex EGs")
  {
      Synth synth;
      std::vector<std::string> messageList;
      Client client(&messageList);
      client.setReceiveCallback(&simpleMessageReceiver);
  
      synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"(
          <region> sample=kick.wav eg1_time1=0.1 eg1_level1=0.5 eg1_time2=0.4 eg1_level2=2 eg2_time1=4 eg2_level1=0.1
      )");
      synth.dispatchMessage(client, 0, "/region0/eg0/point0/time", "", nullptr);
      synth.dispatchMessage(client, 0, "/region0/eg0/point0/level", "", nullptr);
      synth.dispatchMessage(client, 0, "/region0/eg0/point1/time", "", nullptr);
      synth.dispatchMessage(client, 0, "/region0/eg0/point1/level", "", nullptr);
      synth.dispatchMessage(client, 0, "/region0/eg1/point0/time", "", nullptr);
      synth.dispatchMessage(client, 0, "/region0/eg1/point0/level", "", nullptr);
      std::vector<std::string> expected {
          "/region0/eg0/point0/time,f : { 0.1 }",
          "/region0/eg0/point0/level,f : { 0.5 }",
          "/region0/eg0/point1/time,f : { 0.4 }",
          "/region0/eg0/point1/level,f : { 1 }", // Level values in EGs are clamped in Sforzando
          "/region0/eg1/point0/time,f : { 4 }",
          "/region0/eg1/point0/level,f : { 0.1 }",
      };
      REQUIRE(messageList == expected);
  }
  
  TEST_CASE("[Values] Flex EGs CC")
  {
      Synth synth;
      std::vector<std::string> messageList;
      Client client(&messageList);
      client.setReceiveCallback(&simpleMessageReceiver);
  
      synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"(
          <region> sample=kick.wav eg1_time1_cc2=0.1 eg1_level1_oncc3=0.5
      )");
      synth.dispatchMessage(client, 0, "/region0/eg0/point0/time_cc2", "", nullptr);
      synth.dispatchMessage(client, 0, "/region0/eg0/point0/time_cc4", "", nullptr);
      synth.dispatchMessage(client, 0, "/region0/eg0/point0/level_cc3", "", nullptr);
      synth.dispatchMessage(client, 0, "/region0/eg0/point0/level_cc12", "", nullptr);
      std::vector<std::string> expected {
          "/region0/eg0/point0/time_cc2,f : { 0.1 }",
          "/region0/eg0/point0/time_cc4,f : { 0 }",
          "/region0/eg0/point0/level_cc3,f : { 0.5 }",
          "/region0/eg0/point0/level_cc12,f : { 0 }",
      };
      REQUIRE(messageList == expected);
  }
  
  TEST_CASE("[Values] Dynamic EGs")
  {
      Synth synth;
      std::vector<std::string> messageList;
      Client client(&messageList);
      client.setReceiveCallback(&simpleMessageReceiver);
  
      synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"(
          <region> sample=kick.wav
          <region> sample=kick.wav ampeg_dynamic=1 pitcheg_dynamic=1 fileg_dynamic=1
      )");
      synth.dispatchMessage(client, 0, "/region0/ampeg_dynamic", "", nullptr);
      synth.dispatchMessage(client, 0, "/region0/pitcheg_dynamic", "", nullptr);
      synth.dispatchMessage(client, 0, "/region0/fileg_dynamic", "", nullptr);
      synth.dispatchMessage(client, 0, "/region1/ampeg_dynamic", "", nullptr);
      synth.dispatchMessage(client, 0, "/region1/pitcheg_dynamic", "", nullptr);
      synth.dispatchMessage(client, 0, "/region1/fileg_dynamic", "", nullptr);
      std::vector<std::string> expected {
          "/region0/ampeg_dynamic,F : {  }",
          "/region0/pitcheg_dynamic,F : {  }",
          "/region0/fileg_dynamic,F : {  }",
          "/region1/ampeg_dynamic,T : {  }",
          "/region1/pitcheg_dynamic,T : {  }",
          "/region1/fileg_dynamic,T : {  }",
      };
      REQUIRE(messageList == expected);
  }
  