Skip to content

Commit

Permalink
[backends] Implement a dump-to-json backend and a way to convert said…
Browse files Browse the repository at this point in the history
… json to .maxref.xml
  • Loading branch information
jcelerier committed Oct 24, 2023
1 parent 4ce0313 commit f68c375
Show file tree
Hide file tree
Showing 16 changed files with 1,059 additions and 58 deletions.
4 changes: 4 additions & 0 deletions cmake/avendish.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -120,10 +120,12 @@ set(AVENDISH_SOURCES

add_library(avnd_dummy_lib OBJECT "${AVND_SOURCE_DIR}/src/dummy.cpp")

include(avendish.dependencies)
include(avendish.disableexceptions)
include(avendish.sources)

include(avendish.ui.qt)
include(avendish.dump)
include(avendish.max)
include(avendish.pd)
include(avendish.python)
Expand Down Expand Up @@ -158,6 +160,7 @@ endfunction()
function(avnd_make_object)
avnd_register(${ARGV})

avnd_make_dump(${ARGV})
avnd_make_ossia(${ARGV})
avnd_make_python(${ARGV})
avnd_make_pd(${ARGV})
Expand All @@ -170,6 +173,7 @@ endfunction()
function(avnd_make_audioplug)
avnd_register(${ARGV})

avnd_make_dump(${ARGV})
avnd_make_ossia(${ARGV})
avnd_make_vintage(${ARGV})
avnd_make_clap(${ARGV})
Expand Down
27 changes: 27 additions & 0 deletions cmake/avendish.dependencies.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
include(FetchContent)
FetchContent_Declare(
concurrentqueue
GIT_REPOSITORY "https://github.com/jcelerier/concurrentqueue"
GIT_TAG master
GIT_PROGRESS true
)
FetchContent_MakeAvailable(concurrentqueue)

FetchContent_Declare(
nlohmann_json
GIT_REPOSITORY "https://github.com/nlohmann/json"
GIT_TAG master
GIT_PROGRESS true
)
FetchContent_MakeAvailable(nlohmann_json)

set(BUILD_TESTING 0)
set(BUILD_BENCHMARK 0)
set(INJA_USE_EMBEDDED_JSON 0)
FetchContent_Declare(
pantor_inja
GIT_REPOSITORY "https://github.com/pantor/inja"
GIT_TAG master
GIT_PROGRESS true
)
FetchContent_MakeAvailable(pantor_inja)
58 changes: 58 additions & 0 deletions cmake/avendish.dump.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
get_cmake_property (multi_config GENERATOR_IS_MULTI_CONFIG)
file(GENERATE
OUTPUT "$<IF:${multi_config},$<CONFIG>/,>maxref_template.xml"
INPUT ${AVND_SOURCE_DIR}/examples/Demos/maxref_template.xml)

function(avnd_make_dump)
cmake_parse_arguments(AVND "" "TARGET;MAIN_FILE;MAIN_CLASS;C_NAME" "" ${ARGN})

set(AVND_FX_TARGET "${AVND_TARGET}_dump")
if(TARGET "${AVND_FX_TARGET}")
# Target has already been created in avendish.cmake
return()
endif()

string(MAKE_C_IDENTIFIER "${AVND_MAIN_CLASS}" MAIN_OUT_FILE)

configure_file(
"${AVND_SOURCE_DIR}/include/avnd/binding/dump/prototype.cpp.in"
"${CMAKE_BINARY_DIR}/${MAIN_OUT_FILE}_dump.cpp"
@ONLY
NEWLINE_STYLE LF
)

add_executable(${AVND_FX_TARGET})

set_target_properties(
${AVND_FX_TARGET}
PROPERTIES
# OUTPUT_NAME "py${AVND_C_NAME}"
LIBRARY_OUTPUT_DIRECTORY dump
RUNTIME_OUTPUT_DIRECTORY dump
)

target_sources(
${AVND_FX_TARGET}
PRIVATE
"${AVND_MAIN_FILE}"
"${CMAKE_BINARY_DIR}/${MAIN_OUT_FILE}_dump.cpp"
)

target_link_libraries(
${AVND_FX_TARGET}
PRIVATE
Avendish::Avendish_dump
)

add_custom_command(
TARGET ${AVND_FX_TARGET}
COMMAND ${AVND_FX_TARGET} "dump/$<IF:${multi_config},$<CONFIG>/,>${AVND_TARGET}.json"
POST_BUILD
)
avnd_common_setup("${AVND_TARGET}" "${AVND_FX_TARGET}")
endfunction()

add_library(Avendish_dump INTERFACE)
target_link_libraries(Avendish_dump INTERFACE Avendish)
add_library(Avendish::Avendish_dump ALIAS Avendish_dump)

12 changes: 9 additions & 3 deletions cmake/avendish.examples.cmake
Original file line number Diff line number Diff line change
@@ -1,4 +1,11 @@

avnd_make_object(
TARGET Construct
MAIN_FILE examples/Raw/Construct.hpp
MAIN_CLASS examples::Construct
C_NAME avnd_construct
)

avnd_make_all(
TARGET Minimal
MAIN_FILE examples/Raw/Minimal.hpp
Expand Down Expand Up @@ -291,9 +298,8 @@ avnd_make_object(


# Demo: dump all the known metadata.

add_executable(demo_dump examples/Demos/Dump.cpp)
target_link_libraries(demo_dump PRIVATE Avendish)
add_executable(json_to_maxref examples/Demos/JSONToMaxref.cpp)
target_link_libraries(json_to_maxref PRIVATE Avendish pantor::inja)

# Demo: generate matching pd help patches
add_executable(generate_pd_help examples/Demos/GeneratePdHelp.cpp)
Expand Down
123 changes: 123 additions & 0 deletions examples/Demos/JSONToMaxref.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
#include <inja/inja.hpp>
#include <nlohmann/json.hpp>

std::string match_type(std::string_view tp)
{
if(tp == "float" || tp == "double")
return "float";
if(tp == "int" || tp == "long" || tp == "long long")
return "long";
if(tp == "const char*" || tp == "std::string" || tp == "std::string_view")
return "symbol";
if(tp == "char")
return "char";
if(tp == "bool")
return "boolean";
return "atom";
}

int main(int argc, char** argv)
{
using namespace inja;
Environment env;

env.set_trim_blocks(true);
env.set_lstrip_blocks(true);

env.add_callback("tag", [](inja::Arguments& arg) -> bool {
const nlohmann::json& port = *arg.at(0);
auto tags = port.find("tags");
if(tags == port.end())
return false;

const auto& str = arg.at(1)->get<std::string>();
return tags->contains(str);
});

env.add_callback("port_name", [](inja::Arguments& arg) -> std::string {
const nlohmann::json& a = *arg.at(0);
if(auto it = a.find("name"); it != a.cend())
return it->get<std::string>();
return "<unnamed port>";
});

env.add_callback("arg_type", [](inja::Arguments& arg) -> std::string {
const nlohmann::json& a = *arg.at(0);
return match_type(a.get<std::string>());
;
});
env.add_callback("port_type", [](inja::Arguments& arg) -> std::string {
// signal
// signal/float
// symbol
// float64
// long
// signal/integer
// char
// message
// list
const nlohmann::json& a = *arg.at(0);
if(auto p_it = a.find("parameter"); p_it != a.end())
{
if(auto v_it = p_it->find("value_type"); v_it != p_it->end())
{
auto tp = v_it->get<std::string>();
return match_type(tp);
}
}
else if(auto p_it = a.find("audio"); p_it != a.end())
{
return "signal";
}
return "atom"; // any?
});

env.add_callback("make_digest", [](inja::Arguments& arg) -> std::string {
const nlohmann::json* a = arg.at(0);
if(!a)
return "";
auto& o = *a;
if(auto it = o.find("digest"); it != o.end())
return it->get<std::string>();
if(auto it = o.find("short_description"); it != o.end())
return it->get<std::string>();
if(auto it = o.find("description"); it != o.end())
return it->get<std::string>();
return "";
});
env.add_callback("make_description", [](inja::Arguments& arg) -> std::string {
const nlohmann::json* a = arg.at(0);
if(!a)
return "";
auto& o = *a;
if(auto it = o.find("long_description"); it != o.end())
return it->get<std::string>();
if(auto it = o.find("description"); it != o.end())
return it->get<std::string>();
if(auto it = o.find("short_description"); it != o.end())
return it->get<std::string>();
if(auto it = o.find("digest"); it != o.end())
return it->get<std::string>();
return "";
});
// Or directly read a template file

std::ifstream f(argv[1]);
auto data = json::parse(f);

Template temp = env.parse_template("./maxref_template.xml");
std::string result = env.render(temp, data); // "Hello world!"

std::cout << result << std::endl;
return 0;
data["name"] = "Inja";
// std::string result = env.render(temp, data); // "Hello Inja!"

// Or read the template file (and/or the json file) directly from the environment
result = env.render_file("./templates/greeting.txt", data);
result = env.render_file_with_json_file("./templates/greeting.txt", "./data.json");

// Or write a rendered template file
env.write(temp, data, "./result.txt");
env.write_with_json_file("./templates/greeting.txt", "./data.json", "./result.txt");
}
86 changes: 86 additions & 0 deletions examples/Demos/maxref_template.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<?xml-stylesheet href="./_c74_ref.xsl" type="text/xsl"?>

<c74object
name="{{metadatas.c_name}}"
{% if existsIn(metadatas, "module") %} module="{{metadatas.module}}" {% endif %}
{% if existsIn(metadatas, "category") %} category="{{metadatas.category}}" {% endif %}
>

<digest>{{ make_digest(metadatas) }}</digest>
<description>{{ make_description(metadatas) }}</description>

<metadatalist>
{% if existsIn(metadatas, "author") %}
<metadata name="author">{{metadatas.author}}</metadata>
{% endif %}

{% if existsIn(metadatas, "tags") %}
{% for tag in metadatas.tags %}
<metadata name="tag">{{ tag }}</metadata>
{% endfor %}
{% endif %}
</metadatalist>

<inletlist>
{% set inlet_count=0 %}
{% if exists("inputs") %}
{% for port in inputs %}
{% if not tag(port, "class_attribute") %}
{% set inlet_count=inlet_count+1 %}
<inlet id="{{ inlet_count }}" name="{{ port_name(port) }}" type="{{ port_type(port) }}">
<digest>{{ make_digest(port) }}</digest>
<description>{{ make_description(port) }}</description>
</inlet>
{% endif %}
{% endfor %}
{% endif %}
</inletlist>

<outletlist>
{% set outlet_count=0 %}
{% if exists("outputs") %}
{% for port in outputs %}
{% set outlet_count=outlet_count+1 %}
<outlet id="{{ outlet_count }}" name="{{ port_name(port) }}" type="{{ port_type(port) }}">
<digest>{{ make_digest(port) }}</digest>
<description>{{ make_description(port) }}</description>
</outlet>
{% endfor %}
{% endif %}
</outletlist>

<methodlist>
{% if exists("messages") %}
{% for port in messages %}
<method name="{{ port_name(port) }}">
<arglist>
{% if existsIn(port, "arguments") %}
{% for arg in port.arguments %}
<arg name="argument {{ loop.index1 }}" type="{{ arg_type(arg) }}" optional="1"/>
{% endfor %}
{% endif %}
</arglist>
<digest>{{ make_digest(port) }}</digest>
<description>{{ make_description(port) }}</description>
</method>
{% endfor %}
{% endif %}
</methodlist>

<attributelist>
{% if exists("inputs") %}
{% for port in inputs %}
{% if tag(port, "class_attribute") %}
<attribute name="{{ port_name(port) }}" get="1" set="1" type="atom" size="1">
<digest>{{ make_digest(port) }}</digest>
<description>{{ make_description(port) }}</description>
</attribute>
{% endif %}
{% endfor %}
{% endif %}
</attributelist>

<seealsolist>
</seealsolist>
</c74object>
Loading

0 comments on commit f68c375

Please sign in to comment.