Skip to content

Commit

Permalink
fixed multi bindings/same source in rtc_bindings
Browse files Browse the repository at this point in the history
  • Loading branch information
ypujante committed Apr 14, 2023
1 parent 9c7277b commit 21f0a8d
Show file tree
Hide file tree
Showing 9 changed files with 133 additions and 16 deletions.
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ cmake_minimum_required(VERSION 3.17)
project(re-mock LANGUAGES CXX)
set(re-mock_VERSION_MAJOR 1)
set(re-mock_VERSION_MINOR 4)
set(re-mock_VERSION_PATCH 0)
set(re-mock_VERSION_PATCH 1)
set(re-mock_VERSION "${re-mock_VERSION_MAJOR}.${re-mock_VERSION_MINOR}.${re-mock_VERSION_PATCH}")

# Using C++17
Expand Down
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,10 @@ Links
Release notes
-------------

#### 1.4.1 - 2023-04-14

- Fixed issue when the same `source` was defined multiple times (to different `dest`) in `rtc_bindings` in `realtime_controler.lua`

#### 1.4.0 - 2023-04-11

- Use miniaudio instead of libsndfile for loading/saving audio files: this makes generating the CMake project and compiling much faster. As a result the CMake option `RE_MOCK_SUPPORT_FOR_AUDIO_FILE` has been removed entirely.
Expand Down
25 changes: 17 additions & 8 deletions src/cpp/re/mock/Motherboard.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -557,10 +557,13 @@ void Motherboard::init()
}

// rtc_bindings
for(auto const &[propertyPath, bindingKey]: fRealtimeController->getBindings())
for(auto const &[propertyPath, bindingKeys]: fRealtimeController->getBindings())
{
auto diff = registerRTCBinding(propertyPath, bindingKey);
fRealtimeController->invokeBinding(this, bindingKey, getPropertyPath(diff.fPropertyRef), diff.fCurrentValue);
for(auto const &bindingKey: bindingKeys)
{
auto diff = registerRTCBinding(propertyPath, bindingKey);
fRealtimeController->invokeBinding(this, bindingKey, getPropertyPath(diff.fPropertyRef), diff.fCurrentValue);
}
}
}

Expand Down Expand Up @@ -768,7 +771,9 @@ void Motherboard::registerRTCNotify(std::string const &iPropertyPath)
impl::JboxPropertyDiff Motherboard::registerRTCBinding(std::string const &iPropertyPath, std::string const &iBindingKey)
{
auto ref = getPropertyRef(iPropertyPath);
fRTCBindings[ref] = iBindingKey;
if(!stl::contains_key(fRTCBindings, ref))
fRTCBindings[ref] = {};
fRTCBindings[ref].emplace(iBindingKey);
return fJboxObjects.get(ref.fObject)->watchPropertyForChange(ref.fKey);
}

Expand Down Expand Up @@ -864,10 +869,14 @@ void Motherboard::nextBatch()

for(auto &diff : diffs)
{
fRealtimeController->invokeBinding(this,
fRTCBindings.at(diff.fPropertyRef),
getPropertyPath(diff.fPropertyRef),
diff.fCurrentValue);
auto const &bindingKeys = fRTCBindings.at(diff.fPropertyRef);
for(auto binding: bindingKeys)
{
fRealtimeController->invokeBinding(this,
binding,
getPropertyPath(diff.fPropertyRef),
diff.fCurrentValue);
}
}

// next we call render_realtime
Expand Down
2 changes: 1 addition & 1 deletion src/cpp/re/mock/Motherboard.h
Original file line number Diff line number Diff line change
Expand Up @@ -349,7 +349,7 @@ class Motherboard
std::set<TJBox_PropertyRef, ComparePropertyRef> fRTCNotify{compare};
std::vector<impl::JboxPropertyDiff> fRTCNotifyDiffs{};
bool fRTCNotifyEnabled{true};
std::map<TJBox_PropertyRef, std::string, ComparePropertyRef> fRTCBindings{compare};
std::map<TJBox_PropertyRef, std::set<std::string>, ComparePropertyRef> fRTCBindings{compare};
std::vector<impl::JboxPropertyDiff> fRTCBindingsDiffs{};
bool fRTCBindingsEnabled{true};
std::vector<std::string> fUserSamplePropertyPaths{};
Expand Down
8 changes: 5 additions & 3 deletions src/cpp/re/mock/lua/RealtimeController.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -476,11 +476,11 @@ void RealtimeController::invokeBinding(Motherboard *iMotherboard,
//------------------------------------------------------------------------
// RealtimeController::getBindings
//------------------------------------------------------------------------
std::map<std::string, std::string> const &RealtimeController::getBindings()
std::map<std::string, std::set<std::string>> const &RealtimeController::getBindings()
{
if(!fBindings)
{
std::map<std::string, std::string> bindings{};
std::map<std::string, std::set<std::string>> bindings{};
if(lua_getglobal(L, "rtc_bindings") != LUA_TNIL)
{
auto mapIndex = lua_gettop(L);
Expand All @@ -495,7 +495,9 @@ std::map<std::string, std::string> const &RealtimeController::getBindings()
dest = dest.substr(12); // skip /global_rtc/
putBindingOnTopOfStack(dest); // this will check that the binding exists
lua_pop(L, 1);
bindings[source] = dest;
if(!stl::contains_key(bindings, source))
bindings[source] = {};
bindings[source].emplace(dest);

// also add it to reverse bindings
if(!stl::contains_key(fReverseBindings, dest))
Expand Down
4 changes: 2 additions & 2 deletions src/cpp/re/mock/lua/RealtimeController.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ class RealtimeController: public MockJBox
int luaGetSampleInfo();
int luaGetSampleMetaData();

std::map<std::string, std::string> const &getBindings();
std::map<std::string, std::set<std::string>> const &getBindings();
std::set<std::string> getRTInputSetupNotify();

void invokeBinding(Motherboard *iMotherboard,
Expand All @@ -80,7 +80,7 @@ class RealtimeController: public MockJBox
Motherboard *fMotherboard{};
std::string fCurrentBindingName{};
ObjectManager<std::shared_ptr<const JboxValue>> fJboxValues{};
std::optional<std::map<std::string, std::string>> fBindings{};
std::optional<std::map<std::string, std::set<std::string>>> fBindings{};
std::map<std::string, std::set<std::string>> fReverseBindings{};
};

Expand Down
64 changes: 64 additions & 0 deletions test/cpp/re/mock/TestRackExtension.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -385,6 +385,70 @@ TEST(RackExtension, Motherboard_NativeObject)
ASSERT_EQ("abc", o->fStringValue);
}

// RackExtension.RealtimeController_MultiBindings
TEST(RackExtension, RealtimeController_MultiBindings)
{
Rack rack{};

auto c = DeviceConfig<MockDevice>::fromSkeleton()
.mdef(Config::document_owner_property("source_1", lua::jbox_string_property{}))
.mdef(Config::document_owner_property("source_2", lua::jbox_string_property{}))
.mdef(Config::rtc_owner_property("source_1_return", lua::jbox_string_property{}))
.mdef(Config::rtc_owner_property("any_source_1_return", lua::jbox_string_property{}))
.mdef(Config::rtc_owner_property("any_source_2_return", lua::jbox_string_property{}))

.rtc(resource::File{fs::path(RE_MOCK_PROJECT_DIR) / "test" / "resources" / "re" / "mock" / "lua" /
"RackExtension_RealtimeController_MultiBindings.lua"})
;

auto re = rack.newDevice(c);

ASSERT_EQ("", re.getString("/custom_properties/source_1"));
ASSERT_EQ("", re.getString("/custom_properties/source_2"));
ASSERT_EQ("", re.getString("/custom_properties/source_1_return"));
ASSERT_EQ("", re.getString("/custom_properties/any_source_1_return"));
ASSERT_EQ("", re.getString("/custom_properties/any_source_2_return"));

rack.nextBatch();

ASSERT_EQ("", re.getString("/custom_properties/source_1"));
ASSERT_EQ("", re.getString("/custom_properties/source_2"));
ASSERT_EQ("", re.getString("/custom_properties/source_1_return"));
ASSERT_EQ("", re.getString("/custom_properties/any_source_1_return"));
ASSERT_EQ("", re.getString("/custom_properties/any_source_2_return"));

re.setString("/custom_properties/source_1", "s1");

rack.nextBatch();

ASSERT_EQ("s1", re.getString("/custom_properties/source_1"));
ASSERT_EQ("", re.getString("/custom_properties/source_2"));
ASSERT_EQ("s1", re.getString("/custom_properties/source_1_return"));
ASSERT_EQ("s1", re.getString("/custom_properties/any_source_1_return"));
ASSERT_EQ("", re.getString("/custom_properties/any_source_2_return"));

re.setString("/custom_properties/source_2", "s2");

rack.nextBatch();

ASSERT_EQ("s1", re.getString("/custom_properties/source_1"));
ASSERT_EQ("s2", re.getString("/custom_properties/source_2"));
ASSERT_EQ("s1", re.getString("/custom_properties/source_1_return"));
ASSERT_EQ("s1", re.getString("/custom_properties/any_source_1_return"));
ASSERT_EQ("s2", re.getString("/custom_properties/any_source_2_return"));

re.setString("/custom_properties/source_1", "s1.2");
re.setString("/custom_properties/source_2", "s2.2");

rack.nextBatch();

ASSERT_EQ("s1.2", re.getString("/custom_properties/source_1"));
ASSERT_EQ("s2.2", re.getString("/custom_properties/source_2"));
ASSERT_EQ("s1.2", re.getString("/custom_properties/source_1_return"));
ASSERT_EQ("s1.2", re.getString("/custom_properties/any_source_1_return"));
ASSERT_EQ("s2.2", re.getString("/custom_properties/any_source_2_return"));
}

// RackExtension.RealtimeController_NativeObject
TEST(RackExtension, RealtimeController_NativeObject)
{
Expand Down
2 changes: 1 addition & 1 deletion test/cpp/re/mock/lua/TestRealtimeController.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ TEST(RealtimeController, BlankEffect)
ASSERT_EQ(def->getStackString(), "<empty>");

ASSERT_EQ(def->getBindings().size(), 1);
ASSERT_EQ("init_instance", def->getBindings().at("/environment/system_sample_rate"));
ASSERT_EQ(std::set<std::string>{"init_instance"}, def->getBindings().at("/environment/system_sample_rate"));

ASSERT_EQ(def->getRTInputSetupNotify().size(), 4);
ASSERT_THAT(def->getRTInputSetupNotify(), UnorderedElementsAre("/audio_inputs/MainInLeft/connected",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
format_version = "1.0"

rtc_bindings = {
-- this will initialize the C++ object
{ source = "/environment/system_sample_rate", dest = "/global_rtc/init_instance" },
{ source = "/custom_properties/source_1", dest = "/global_rtc/on_source_1" },
{ source = "/custom_properties/source_1", dest = "/global_rtc/on_any_source" },
{ source = "/custom_properties/source_2", dest = "/global_rtc/on_any_source" },
}

global_rtc = {
init_instance = function(source_property_path, new_value)
local sample_rate = jbox.load_property("/environment/system_sample_rate")
local new_no = jbox.make_native_object_rw("Instance", { sample_rate })
jbox.store_property("/custom_properties/instance", new_no)
end,

on_source_1 = function(source_property_path, new_value)
--print("from on_source_1 " .. tostring(new_value))
jbox.store_property("/custom_properties/source_1_return", new_value)
end,

on_any_source = function(source_property_path, new_value)
--print("from on_any_source(" .. tostring(source_property_path) .. "," .. tostring(new_value) .. ")")
-- allowed because both are declared as sources of the callback
local s1_value = jbox.load_property("/custom_properties/source_1")
local s2_value = jbox.load_property("/custom_properties/source_2")
if source_property_path == "/custom_properties/source_1" then
assert(s1_value == new_value)
jbox.store_property("/custom_properties/any_source_1_return", new_value)
end
if source_property_path == "/custom_properties/source_2" then
assert(s2_value == new_value)
jbox.store_property("/custom_properties/any_source_2_return", new_value)
end
end,

}

0 comments on commit 21f0a8d

Please sign in to comment.