Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion cmake/avendish.examples.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -238,7 +238,7 @@ avnd_make_all(
TARGET SampleAccurateControls
MAIN_FILE examples/Raw/SampleAccurateControls.hpp
MAIN_CLASS examples::SampleAccurateControls
C_NAME avnd_sample_accurate_controls
C_NAME avnd_sampleaccurate # must match SampleAccurateControls::c_name()
)

avnd_make_all(
Expand Down
12 changes: 12 additions & 0 deletions include/avnd/binding/golden/prototype.cpp.in
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,18 @@ struct config
int main(int argc, char** argv)
{
using type = decltype(avnd::configure<golden::config, @AVND_MAIN_CLASS@>())::type;

// Every object is built for the golden harness (SDK-free, always on), so this
// single check enforces the name invariant for all back-ends at once: when an
// object declares an explicit halp_meta(c_name, ...), the avnd_addon_object /
// avnd_make_* C_NAME must equal it -- they name the same external (the file and
// class Pd/Max load by), and a mismatch ships something that can't be
// instantiated. Objects with no c_name leave the C_NAME authoritative.
static_assert(
avnd::c_name_matches<type>("@AVND_C_NAME@"),
"avendish: the CMake C_NAME does not match this object's halp_meta(c_name, ...). "
"Make the avnd_addon_object / avnd_make_* C_NAME equal the object's c_name.");

return golden::run<type>(argc > 1 ? argv[1] : std::string_view{"golden.json"});
}
// clang-format on
11 changes: 7 additions & 4 deletions include/avnd/binding/pd/audio_processor.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,10 @@ struct audio_processor_metaclass
static inline t_class* g_class{};
static inline audio_processor_metaclass* instance{};

audio_processor_metaclass();
// class_name is the Pd class symbol; the setup function passes @AVND_C_NAME@ so
// the registered class matches the external's filename (nullptr -> fall back to
// the introspected name, for callers that construct the metaclass directly).
audio_processor_metaclass(t_symbol* class_name = nullptr);
};

template <typename T>
Expand Down Expand Up @@ -205,7 +208,7 @@ struct audio_processor
};

template <typename T>
audio_processor_metaclass<T>::audio_processor_metaclass()
audio_processor_metaclass<T>::audio_processor_metaclass(t_symbol* class_name)
{
audio_processor_metaclass::instance = this;
using instance = audio_processor<T>;
Expand Down Expand Up @@ -249,8 +252,8 @@ audio_processor_metaclass<T>::audio_processor_metaclass()

/// Class creation ///
g_class = class_new(
symbol_from_name<T>(), (t_newmethod)obj_new, (t_method)obj_free,
sizeof(audio_processor<T>), CLASS_DEFAULT, A_GIMME, 0);
class_name ? class_name : symbol_from_name<T>(), (t_newmethod)obj_new,
(t_method)obj_free, sizeof(audio_processor<T>), CLASS_DEFAULT, A_GIMME, 0);

// First port will receive messages
CLASS_MAINSIGNALIN(g_class, audio_processor<T>, f);
Expand Down
11 changes: 7 additions & 4 deletions include/avnd/binding/pd/message_processor.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,10 @@ struct message_processor_metaclass
static inline t_class* g_class{};
static inline message_processor_metaclass* instance{};

message_processor_metaclass();
// class_name is the Pd class symbol; the setup function passes @AVND_C_NAME@ so
// the registered class matches the external's filename (nullptr -> fall back to
// the introspected name, for callers that construct the metaclass directly).
message_processor_metaclass(t_symbol* class_name = nullptr);
};

template <typename T>
Expand Down Expand Up @@ -187,7 +190,7 @@ struct message_processor
};

template <typename T>
message_processor_metaclass<T>::message_processor_metaclass()
message_processor_metaclass<T>::message_processor_metaclass(t_symbol* class_name)
{
message_processor_metaclass::instance = this;
using instance = message_processor<T>;
Expand Down Expand Up @@ -228,8 +231,8 @@ message_processor_metaclass<T>::message_processor_metaclass()

/// Class creation ///
g_class = class_new(
symbol_from_name<T>(), (t_newmethod)obj_new, (t_method)obj_free,
sizeof(message_processor<T>), CLASS_DEFAULT, A_GIMME, 0);
class_name ? class_name : symbol_from_name<T>(), (t_newmethod)obj_new,
(t_method)obj_free, sizeof(message_processor<T>), CLASS_DEFAULT, A_GIMME, 0);

// Connect our methods
class_addanything(g_class, (t_method)obj_process);
Expand Down
12 changes: 9 additions & 3 deletions include/avnd/binding/pd/prototype.cpp.in
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,23 @@ using type = decltype(avnd::configure<pd::config, @AVND_MAIN_CLASS@>())::type;

extern "C" AVND_EXPORTED_SYMBOL void @AVND_C_NAME@_setup()
{
[]<typename T = type> {
// Register the class under the external's own name (the file Pd just loaded is
// @AVND_C_NAME@.pd_*, and this function is @AVND_C_NAME@_setup). Pd looks up a
// single-object external by filename, so the class symbol must match it exactly;
// otherwise the object loads but the class is registered under a different name,
// Pd never finds it, and its loader retries until it hits the recursion limit.
t_symbol* const avnd_class_name = gensym("@AVND_C_NAME@");
[avnd_class_name]<typename T = type> {
if constexpr(
avnd::monophonic_audio_processor<T> || avnd::polyphonic_audio_processor<T>)
{
// If we're an audio effect, make a type with the whole DSP stuff
static const pd::audio_processor_metaclass<T> instance{};
static const pd::audio_processor_metaclass<T> instance{avnd_class_name};
}
else
{
// Simpler case which just processes messages
static const pd::message_processor_metaclass<T> instance{};
static const pd::message_processor_metaclass<T> instance{avnd_class_name};
}
}();
}
15 changes: 15 additions & 0 deletions include/avnd/wrappers/metadatas.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -318,6 +318,21 @@ static constexpr auto get_static_symbol()
return avnd::get_c_identifier<T, Symtab>();
}

// True unless the object declares an explicit c_name (halp_meta(c_name, ...)) that
// differs from the external's CMake C_NAME. The per-backend prototypes call this so
// a C_NAME that disagrees with the object's own c_name is a compile error instead of
// an external whose file name and registered class name silently differ (which Pd and
// Max load by, so it can't be instantiated). Objects with no c_name meta leave the
// CMake C_NAME authoritative and always pass.
template <typename T>
consteval bool c_name_matches(std::string_view cmake_c_name)
{
if constexpr(avnd::has_c_name<T>)
return avnd::get_c_name<T>() == cmake_c_name;
else
return true;
}



template <typename T>
Expand Down
Loading