Version

menu_open
Wwise SDK 2024.1.0
PluginInfoGenerator.h
Go to the documentation of this file.
1 /*******************************************************************************
2 The content of this file includes portions of the AUDIOKINETIC Wwise Technology
3 released in source code form as part of the SDK installer package.
4 
5 Commercial License Usage
6 
7 Licensees holding valid commercial licenses to the AUDIOKINETIC Wwise Technology
8 may use this file in accordance with the end user license agreement provided
9 with the software or, alternatively, in accordance with the terms contained in a
10 written agreement between you and Audiokinetic Inc.
11 
12 Apache License Usage
13 
14 Alternatively, this file may be used under the Apache License, Version 2.0 (the
15 "Apache License"); you may not use this file except in compliance with the
16 Apache License. You may obtain a copy of the Apache License at
17 http://www.apache.org/licenses/LICENSE-2.0.
18 
19 Unless required by applicable law or agreed to in writing, software distributed
20 under the Apache License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES
21 OR CONDITIONS OF ANY KIND, either express or implied. See the Apache License for
22 the specific language governing permissions and limitations under the License.
23 
24  Copyright (c) 2024 Audiokinetic Inc.
25 *******************************************************************************/
26 
27 /**
28  * \brief Wwise Authoring Plug-ins - C++ class helper to automatically determine the plug-in interfaces used in a class.
29  * \file AK/Wwise/Plugin/PluginInfoGenerator.h
30  */
31 
32 #pragma once
33 
34 #include "PluginContainer.h"
35 
36 #ifdef __cplusplus
37 #include <array>
38 #include <memory>
39 
40 /**
41  * \brief The specific version for native plug-in interfaces. Must be identical down to the build number.
42  * \warning Private API. Using this makes the plug-in compatible with this Authoring's build version only.
43  */
44 #define AK_WWISESDK_VERSION_NATIVE_COMBINED ((AK_WWISESDK_VERSION_MAJOR << 19) | (AK_WWISESDK_VERSION_MINOR << 16) | AK_WWISESDK_VERSION_SUBMINOR)
45 
46 namespace AK::Wwise::Plugin
47 {
48  using InterfaceType = decltype(BaseInterface::m_interface); ///< PluginInfoGenerator: Type for the m_interface value in BaseInterface
49  using InterfaceTypeValue = std::underlying_type<InterfaceType>::type; ///< PluginInfoGenerator: Underlying storage type for the m_interface value in BaseInterface
50  using InterfaceVersion = decltype(BaseInterface::m_version); ///< PluginInfoGenerator: Type for the m_version value in BaseInterface
51 
52  /**
53  * \brief The interface information of the plug-in currently being instantiated.
54  *
55  * When the host calls the Instantiate of the plug-in, PluginInfoGenerator will automatically set this thread
56  * variable to the provided \c in_pluginInfo. This allows the interfaces to bind themselves without having
57  * to pass this parameter throughout the constructor.
58  *
59  * \akwarning This variable is only set up during instantiation. \endakwarning
60  */
61  template <bool = false>
62  struct PluginInfoTLS
63  {
64 #ifndef _MANAGED
65  thread_local
66 #endif
68  };
69 
70  /**
71  * \brief PluginInfoGenerator: For each plug-in interface type, provides a single static instance used throughout this plug-in container.
72  *
73  * This uses a C++ template principle where you can define a static variable inside a templated class, and you
74  * can have the compiler generate one unique static instance for each individual templated class.
75  *
76  * Also, having a class outer shell means the static member can reside in a header and be instantiated in that same
77  * header without the linker refusing multiple definitions.
78  *
79  * \tparam CInterface Which interface (In C)
80  *
81  * \sa
82  * - \ref AK::Wwise::Plugin::PluginInfoGenerator
83  */
84  template <typename CInterface>
86  {
87  public:
88  using GluedInterface = CInterface;
89  static GluedInterface* g_cinterface; ///< The unique instance of the CInterface interface. Defined at nullptr first, overridden by the Host once loaded.
90  };
91  template<typename CInterface> CInterface* CBaseInterfaceGlue<CInterface>::g_cinterface = nullptr;
92 
93  /**
94  * \brief PluginInfoGenerator: Associates an existing C Interface with a variable that can be used. Derives from the instance that uses it.
95  *
96  * \tparam CInterface The C Interface that needs to be instantiated into a CInstance.
97  * \tparam CInstance The C Instance that will be instantiated. Automatically derived from the CInterface::Instance typedef.
98  *
99  * \sa
100  * - \ref AK::Wwise::Plugin::PluginInfoGenerator
101  */
102  template <typename CInterface, typename CInstance = typename CInterface::Instance>
103  class CBaseInstanceGlue : public CInstance, public CBaseInterfaceGlue<CInterface>
104  {
105  public:
106  using Instance = CInstance;
107  };
108 
109  /**
110  * \brief PluginInfoGenerator: Base class for every C++ instance that retrieves a service from the Wwise Authoring host.
111  *
112  * Compared to C, where the interface contains all the functions and the instance is an opaque block, the C++
113  * version is the opposite; the instance is a class containing all the methods, and the interface is hidden as
114  * implementation details.
115  *
116  * The HostInterfaceGlue helper class provides that distinction. Depending on the in_baseInstance parameter,
117  * it will either have only a C interface (true) or also have its default instantiation (false).
118  *
119  * \tparam CPPInstance The C++ instance to instantiate.
120  * \tparam in_baseInstance Only provide a bridge (true) or also a default instance (false).
121  *
122  * \sa
123  * - \ref AK::Wwise::Plugin::PluginInfoGenerator
124  */
125  template <typename CPPInstance, bool in_baseInstance>
127  {
128  public:
129  enum : InterfaceTypeValue { k_interfaceType = CPPInstance::k_interfaceType };
130  enum : InterfaceVersion { k_interfaceVersion = CPPInstance::k_interfaceVersion };
131  using GluedInterface = typename CPPInstance::GluedInterface;
132  using Instance = CPPInstance;
133  using CInstance = typename CPPInstance::Instance;
134 
135  static GluedInterface g_cppinterface; ///< The unique interface for this plug-in interface.
136  };
137  template<typename CPPInstance, bool in_baseInstance> typename CPPInstance::GluedInterface HostInterfaceGlue<CPPInstance, in_baseInstance>::g_cppinterface;
138 
139  template <typename CPPInstance>
140  class HostInterfaceGlue<CPPInstance, true> : public HostInterfaceGlue<CPPInstance, false>
141  {
142  public:
144  using CInstance = typename Super::CInstance;
145  using Instance = typename Super::Instance;
147 
148  CPPInstance* m_instance; ///< The default instance for this plug-in interface.
149 
150  HostInterfaceGlue(CInstance* in_instance) : m_instance(static_cast<CPPInstance*>(in_instance)) {}
151  HostInterfaceGlue() : HostInterfaceGlue(GetCInterfaceInstance()) {}
152 
153  private:
154  /**
155  * \brief Locate the C interface of our CPPInstance in our current plug-in.
156  *
157  * \ref PluginInfoTLS<>::tls_pluginInfo is used to retrieve the plug-in we are trying to instantiate.
158  * \return CInstance* The C interface related to our CPPInstance.
159  */
160  static CInstance* GetCInterfaceInstance()
161  {
162  auto pluginInfo = PluginInfoTLS<>::tls_pluginInfo;
163  for (int i = 0; i < pluginInfo->m_arraySize; ++i)
164  {
165  InterfaceArrayItem& intf = pluginInfo->m_interfaces[i];
166  if (intf.m_interface->m_interface == static_cast<InterfaceType>(HostInterfaceGlue::k_interfaceType) &&
168  {
169  return static_cast<CInstance*>(intf.m_instance);
170  }
171  }
172  return nullptr;
173  }
174  };
175 
176 
177  /**
178  * \brief PluginInfoGenerator: Compile-time dictionary of known interface-version.
179  *
180  * Used so we can ask a KnownInterfaceClass<in_interface, in_version> and receive which class and interface it points to.
181  *
182  * \tparam in_interfaceType
183  * \tparam in_interfaceVersion
184  *
185  * \sa
186  * - \ref AK::Wwise::Plugin::PluginInfoGenerator
187  */
188  template <InterfaceType in_interfaceType, InterfaceVersion in_interfaceVersion>
190  {
191  using Type = void;
192  using Interface = void;
193  };
194 
195 /**
196  * \brief PluginInfoGenerator: Defines a C++ known interface-version to Type dictionary entry.
197  *
198  * \aknote Macro assumes a AK::Wwise::Plugin namespace root. \endaknote
199  *
200  * \param in_name Class name.
201  *
202  * \sa
203  * - \ref AK::Wwise::Plugin::PluginInfoGenerator
204  */
205 #define AK_WWISE_PLUGIN_SPECIALIZE_INTERFACE_CLASS(in_name) \
206  template<> struct KnownInterfaceClass<(AK::Wwise::Plugin::InterfaceType)in_name::k_interfaceType, in_name::k_interfaceVersion> \
207  { \
208  using Type = in_name; \
209  using Interface = typename Type::Interface; \
210  }
211 
212 
213  /**
214  * \brief PluginInfoGenerator: Requests a host-provided service, and optionally receives a variable containing the default instance.
215  *
216  * \tparam T The C++ class to request.
217  *
218  * \sa
219  * - \ref AK::Wwise::Plugin::PluginInfoGenerator
220  */
221  template <typename T>
223 
224 /**
225  * \brief PluginInfoGenerator: Creates a C++ host specialization for interface class specified in in_name, and creates a variable instance named m_ followed by in_varname.
226  *
227  * \aknote Macro assumes a AK::Wwise::Plugin namespace root. \endaknote
228  *
229  * \param in_name Name of the C++ class
230  * \param in_varname Name of the variable to instantiate. Will be prefixed by m_. A second static variable is created with g_ prefix, containing the C++ interface.
231  * \param ... Supplemental class derivations can be added as additional parameters
232  *
233  * \sa
234  * - \ref AK_WWISE_PLUGIN_SPECIALIZE_HOST_INTERFACE_NO_BASE_INSTANCE
235  * - \ref AK::Wwise::Plugin::PluginInfoGenerator
236  */
237 #define AK_WWISE_PLUGIN_SPECIALIZE_HOST_INTERFACE(in_name, in_varname, ...) \
238  template <> \
239  class RequestedHostInterface<in_name> : public HostInterfaceGlue<in_name, true> __VA_ARGS__ \
240  { \
241  public: \
242  using HostInterfaceDefinition = HostInterfaceGlue<in_name, true>; \
243  in_name::Interface& g_ ## in_varname ## Interface = HostInterfaceDefinition::g_cppinterface; \
244  HostInterfaceDefinition::Instance& m_ ## in_varname = *HostInterfaceDefinition::m_instance; \
245  \
246  RequestedHostInterface() {} \
247  }
248 
249 /**
250  * \brief PluginInfoGenerator: Creates a C++ host specialization for interface class specified in in_name.
251  *
252  * \aknote Macro assumes a AK::Wwise::Plugin namespace root. \endaknote
253  *
254  * \param in_name Name of the C++ class
255  * \param in_varname Name of the static variable to be created with g_ prefix, containing the C++ interface.
256  * \param ... Supplemental class derivations can be added as additional parameters
257  *
258  * \sa
259  * - \ref AK_WWISE_PLUGIN_SPECIALIZE_HOST_INTERFACE
260  * - \ref AK::Wwise::Plugin::PluginInfoGenerator
261  */
262 #define AK_WWISE_PLUGIN_SPECIALIZE_HOST_INTERFACE_NO_BASE_INSTANCE(in_name, in_varname) \
263  template <> \
264  class RequestedHostInterface<in_name> : public HostInterfaceGlue<in_name, false> \
265  { \
266  public: \
267  using HostInterfaceDefinition = HostInterfaceGlue<in_name, false>; \
268  in_name::Interface& g_ ## in_varname ## Interface = HostInterfaceDefinition::g_cppinterface; \
269  \
270  RequestedHostInterface() {} \
271  }
272 
273  /**
274  * \brief PluginInfoGenerator: Defines a compile-time dictionary with the latest version known to the SDK for each interface.
275  *
276  * \tparam in_interfaceType The interface ID to define.
277  *
278  * \sa
279  * - \ref AK::Wwise::Plugin::PluginInfoGenerator
280  */
281  template <InterfaceType in_interfaceType>
283  {
284  enum { k_interfaceVersion = 1 };
285  };
286 
287 /**
288  * \brief PluginInfoGenerator: Creates a C++ link to the latest version known to the SDK for each interface.
289  *
290  * \param in_interface C++ interface to retrieve the interface type and version.
291  *
292  * \sa
293  * - \ref AK::Wwise::Plugin::PluginInfoGenerator
294  */
295 #define AK_WWISE_PLUGIN_SPECIALIZE_INTERFACE_VERSION(in_interface) \
296  template <> \
297  struct LatestInterfaceVersion<(InterfaceType)in_interface::k_interfaceType> \
298  { \
299  enum { k_interfaceVersion = (InterfaceVersion)in_interface::k_interfaceVersion }; \
300  }
301 
302 
303  // These are the default structural known interface classes / Current Interface version
305  {
306  using Type = void;
308  };
310  {
311  enum { k_interfaceVersion = 1 };
312  };
313 
314  /**
315  * \brief C++ PluginInfo Generator.
316  *
317  * Retrieves the list of plug-in interfaces required by a plug-in through derivation, and automatically creates a
318  * related ak_wwise_plugin_info structure.
319  *
320  * Compared to a manually generated C version, the generated structure is done through a function that fills all
321  * the required data. Since it's a static global function called only once, and contains only value stores, the cost
322  * is, so far, quite minimal.
323  *
324  * \tparam PluginT The plug-in class that needs to be instantiated in order to use that plug-in.
325  */
326  template <typename PluginT>
328  {
329  /**
330  * \brief Compile-time dictionary about a particular interface type.
331  *
332  * \tparam in_interfaceType The interface ID with the information to request.
333  */
334  template <InterfaceType in_interfaceType>
335  struct InterfaceInfo
336  {
337  enum
338  {
339  /**
340  * \brief Most up-to-date version of the interface in the current SDK.
341  */
343  };
344 
345  /**
346  * \brief Compile-time container of version numbers.
347  *
348  * \tparam in_versions,... Version numbers to store in the container in ascending order.
349  */
350  template <uint32_t... in_versions>
351  struct VersionPack : public std::integer_sequence<uint32_t, in_versions...>
352  {
353  /**
354  * \brief Get the latest version stored in the container. Assumes the container is sorted in ascending order.
355  *
356  * \return uint32_t The latest version of the pack.
357  */
358  static constexpr uint32_t GetLatest()
359  {
360  return (in_versions, ...); // Fold-expression with comma operator
361  }
362  };
363 
364  /**
365  * \brief Recursively accumulate each version of the interface requested or provided by the plug-in (there should be one or none).
366  *
367  * \aknote Assumes the interface versions range from 1 to k_latestInterfaceVersion, except for native interfaces. \endaknote
368  *
369  * \return A pair containing a VersionPack of the requested versions and a VersionPack of the provided versions of the interface.
370  *
371  * \sa
372  * - \ref k_latestInterfaceVersion
373  * - \ref VersionPack
374  */
375  template <uint32_t in_interfaceVersion = k_latestInterfaceVersion, uint32_t... in_requestedVersions, uint32_t... in_providedVersions>
376  static constexpr auto GetUsedInterfaceVersions(VersionPack<in_requestedVersions...> = {}, VersionPack<in_providedVersions...> = {})
377  {
378  if constexpr (in_interfaceVersion >= 1)
379  {
381  using RequestedInterfaceVersions = std::conditional_t<
382  std::is_base_of_v<RequestedHostInterface<InterfaceClass>, PluginT>,
383  VersionPack<in_interfaceVersion, in_requestedVersions...>,
384  VersionPack<in_requestedVersions...>>;
385  using ProvidedInterfaceVersions = std::conditional_t<
386  std::is_base_of_v<InterfaceClass, PluginT>,
387  VersionPack<in_interfaceVersion, in_providedVersions...>,
388  VersionPack<in_providedVersions...>>;
389  return GetUsedInterfaceVersions<
390  // If the interface is native, there can only be a single version of it
391  k_latestInterfaceVersion == AK_WWISESDK_VERSION_NATIVE_COMBINED ? 0 : in_interfaceVersion - 1>
393  }
394  else
395  {
396  return std::pair<VersionPack<in_requestedVersions...>, VersionPack<in_providedVersions...>>();
397  }
398  }
399 
400  /**
401  * \brief Pair type containing a VersionPack of the requested versions and a VersionPack of the provided versions of the interface.
402  *
403  * \sa
404  * - \ref GetUsedInterfaceVersions
405  * - \ref VersionPack
406  */
408 
409  /**
410  * \brief VersionPack containing the requested versions of the interface by the plug-in.
411  *
412  * \sa
413  * - \ref UsedInterfaceVersions
414  * - \ref VersionPack
415  */
416  using RequestedInterfaceVersions = typename UsedInterfaceVersions::first_type;
417 
418  /**
419  * \brief VersionPack containing the provided versions of the interface by the plug-in.
420  *
421  * \sa
422  * - \ref UsedInterfaceVersions
423  * - \ref VersionPack
424  */
425  using ProvidedInterfaceVersions = typename UsedInterfaceVersions::second_type;
426 
427  enum : bool
428  {
429  /**
430  * \brief Is the interface requested (interface provided by host) by the generated plug-in class.
431  *
432  * \sa
433  * - \ref RequestedInterfaceVersions
434  */
435  k_requested = RequestedInterfaceVersions::size() >= 1,
436 
437  /**
438  * \brief Is the interface provided (interface used by host) by the generated plug-in class.
439  *
440  * \sa
441  * - \ref ProvidedInterfaceVersions
442  */
443  k_provides = ProvidedInterfaceVersions::size() >= 1,
444 
445  /**
446  * \brief Are we using this interface in our plug-in.
447  */
448  k_has = k_requested || k_provides
449  };
450 
451  static_assert(RequestedInterfaceVersions::size() <= 1, "Plugin can't request more than one version of the same interface");
452  static_assert(ProvidedInterfaceVersions::size() <= 1, "Plugin can't provide more than one version of the same interface");
453  static_assert(!(k_requested && k_provides), "Requested interfaces can't be provided and provided interfaces can't be requested");
454 
455  /**
456  * \brief Extract the version of the interface used by the plug-in.
457  *
458  * \aknote If this interface hasn't been requested or provided at all by the plug-in, k_latestInterfaceVersion is returned. \endaknote
459  *
460  * \return uint32_t The version of the interface.
461  *
462  * \sa
463  * - \ref RequestedInterfaceVersions
464  * - \ref ProvidedInterfaceVersions
465  * - \ref k_latestInterfaceVersion
466  */
467  static constexpr uint32_t GetInterfaceVersion()
468  {
469  if constexpr (k_requested)
470  {
471  return RequestedInterfaceVersions::GetLatest();
472  }
473  else if constexpr (k_provides)
474  {
475  return ProvidedInterfaceVersions::GetLatest();
476  }
477  else
478  {
479  return k_latestInterfaceVersion;
480  }
481  }
482 
483  enum
484  {
485  /**
486  * \brief Version of the interface used by the plug-in or k_latestInterfaceVersion if unused.
487  *
488  * \sa
489  * - \ref GetInterfaceVersion
490  * - \ref k_latestInterfaceVersion
491  */
493  };
494 
495  /**
496  * \brief Interface class of the versioned interface type.
497  *
498  * \sa
499  * - \ref AK::Wwise::Plugin::KnownInterfaceClass
500  * - \ref k_interfaceVersion
501  */
503 
504  /**
505  * \brief Casts the plug-in class to the requested interface class.
506  *
507  * \aknote This needs to be in a template, as the interface might not be castable. \endaknote
508  */
509  template <bool>
511  {
512  constexpr static inline InterfaceClass* Cast(PluginT* in_plugin)
513  {
514  return static_cast<InterfaceClass*>(in_plugin);
515  }
516  };
517 
518  /**
519  * \brief Casts the plug-in class to the requested interface class.
520  */
522 
523  /**
524  * \brief Get a Placeholder Pointer object.
525  *
526  * \return BaseInterface* An empty Base Interface pointing to the proper type and version. This is used
527  * when requesting an interface with the host, and the placeholder object pointer will get replaced.
528  */
530  {
531  static BaseInterface s_placeholder(in_interfaceType, k_interfaceVersion);
532  return &s_placeholder;
533  }
534  };
535 
536  /**
537  * \brief Count the number of interfaces we are currently using.
538  *
539  * \sa
540  * - \ref k_interfaceCount
541  */
542  template <InterfaceType in_interface = (InterfaceType)(AK_WWISE_PLUGIN_INTERFACE_TYPE_NUM - 1)>
543  static constexpr size_t CountInterfaces()
544  {
545  if constexpr (in_interface != AK_WWISE_PLUGIN_INTERFACE_TYPE_UNKNOWN)
546  {
547  if constexpr (InterfaceInfo<in_interface>::k_has)
548  {
549  return CountInterfaces<(InterfaceType)(in_interface - 1)>() + 1;
550  }
551  else
552  {
553  return CountInterfaces<(InterfaceType)(in_interface - 1)>();
554  }
555  }
556  else
557  {
558  return 0;
559  }
560  }
561 
562  enum : size_t
563  {
564  /**
565  * \brief Number of interfaces we are currently using.
566  *
567  * \sa
568  * - \ref CountInterfaces
569  */
571  };
572 
573  /**
574  * \brief Generates the InterfaceArrayItem for our particular type.
575  *
576  * \tparam in_interfaceType Interface ID
577  */
578  template <InterfaceType in_interfaceType>
580  {
582  {
584  }
585  else if constexpr (InterfaceInfo<in_interfaceType>::k_provides)
586  {
587  return InterfaceArrayItem(InterfaceInfo<in_interfaceType>::ToInterfaceClass::Cast(nullptr)->GetInterfacePointer());
588  }
589  else
590  {
591  return InterfaceArrayItem();
592  }
593  }
594 
595  /**
596  * \brief Recursively generates an interface array of all the Interfaces pointers.
597  *
598  * \tparam in_interfaceType The current interface being processed. They are processed recursively from max to 0
599  */
600  template <InterfaceType in_interfaceType>
601  static constexpr void GenerateInterfaceArray(InterfaceArrayItem out_interfaces[k_interfaceCount], int in_count, InterfaceArrayItem)
602  {
603  if constexpr (in_interfaceType != AK_WWISE_PLUGIN_INTERFACE_TYPE_UNKNOWN && in_interfaceType != AK_WWISE_PLUGIN_INTERFACE_TYPE_NUM)
604  {
605  GenerateInterfaceArray<(InterfaceType)(in_interfaceType + 1)>(
606  out_interfaces,
607  in_count + (InterfaceInfo<in_interfaceType>::k_has ? 1 : 0),
608  InterfaceInfo<in_interfaceType>::k_has ? out_interfaces[in_count] = GenerateInterface<in_interfaceType>() : InterfaceArrayItem());
609  }
610  }
611 
613  {
614  GenerateInterfaceArray<(InterfaceType)1>(out_interfaces, 0, InterfaceArrayItem());
615  return out_interfaces;
616  }
617 
618  /**
619  * \brief Generates the constructor for our particular type
620  *
621  * \tparam in_interfaceType Interface ID
622  */
623  template <InterfaceType in_interfaceType>
625  {
626  static inline void UpdateCInterface(const InterfaceArrayItem& in_original)
627  {
629  {
630  // Update our global interface (that's used in calls) to the new value
632  CBaseInterfaceGlue<InterfaceToUpdate>::g_cinterface = static_cast<InterfaceToUpdate*>(in_original.m_interface);
633  }
634  }
635 
636  static inline void Constructor(InterfaceArrayItem& out_interface, const InterfaceArrayItem& in_original, PluginT* in_instance)
637  {
639  {
640  out_interface.m_interface = in_original.m_interface;
641  out_interface.m_instance = in_original.m_instance;
642  }
643  else if constexpr (InterfaceInfo<in_interfaceType>::k_provides)
644  {
645  out_interface.m_interface = in_original.m_interface;
646  out_interface.m_instance = InterfaceInfo<in_interfaceType>::ToInterfaceClass::Cast(in_instance)->GetInstancePointer();
647  }
648  }
649  };
650 
651  /**
652  * \brief Recursively generates the constructors and interface pointer updater for all the Interfaces.
653  *
654  * \tparam in_interfaceType The current interface being processed. They are processed recursively from max to 0
655  */
656  template <InterfaceType in_interfaceType = (InterfaceType)(AK_WWISE_PLUGIN_INTERFACE_TYPE_UNKNOWN + 1)>
658  {
659  static inline void UpdateCInterface(const InterfaceArrayItem in_original[k_interfaceCount], int in_count = 0)
660  {
661  if constexpr (in_interfaceType != AK_WWISE_PLUGIN_INTERFACE_TYPE_NUM)
662  {
664  {
666  GenerateConstructorArray<(InterfaceType)(in_interfaceType + 1)>::UpdateCInterface(in_original, in_count + 1);
667  }
668  else
669  {
670  GenerateConstructorArray<(InterfaceType)(in_interfaceType + 1)>::UpdateCInterface(in_original, in_count);
671  }
672  }
673  }
674 
675  static inline void Constructor(InterfaceArrayItem out_interfaces[k_interfaceCount], const InterfaceArrayItem in_original[k_interfaceCount], PluginT* in_instance, int in_count = 0)
676  {
677  if constexpr (in_interfaceType != AK_WWISE_PLUGIN_INTERFACE_TYPE_NUM)
678  {
680  {
681  GenerateConstructor<in_interfaceType>::Constructor(out_interfaces[in_count], in_original[in_count], in_instance);
682  GenerateConstructorArray<(InterfaceType)(in_interfaceType + 1)>::Constructor(out_interfaces, in_original, in_instance, in_count + 1);
683  }
684  else
685  {
686  GenerateConstructorArray<(InterfaceType)(in_interfaceType + 1)>::Constructor(out_interfaces, in_original, in_instance, in_count);
687  }
688  }
689  }
690  };
691 
692  /**
693  * \brief Array of all used interfaces for the plug-in.
694  *
695  * It is used as a template before instantiation to create a local temporary plug-in info.
696  * A copy of its content is made in which the host fills instances it provides.
697  * At instantiation, this local copy is merged with the instantiated plug-in's interface
698  * instances into a finalized array that is returned by the Instantiate method.
699  *
700  * Contained in the m_pluginInfo member variable.
701  */
703 
704  /**
705  * \brief Plug-in instance constructor, as shared with the host.
706  *
707  * It is currently assumed the in_pluginInfo parameter, as passed, is the same as the one provided in the
708  * ak_wwise_plugin_container structure. As such, in the current version of the SDK, this is not reentrant, as
709  * there is only one structure used to transfer data.
710  *
711  * \warning This function is not reentrant. See \ref m_interfaceArray for more information.
712  *
713  * \param in_pluginInfo Plug-in structure to instantiate.
714  * \return InterfaceArrayItem* The new instance: A copy of the structure, containing the instantiated pointers.
715  */
716  static InterfaceArrayItem* Instantiate(PluginInfo* in_pluginInfo)
717  {
719 
720  // Instantiate the user plug-in
721  auto prevPluginInfo = PluginInfoTLS<>::tls_pluginInfo;
722  PluginInfoTLS<>::tls_pluginInfo = in_pluginInfo;
723 
724  auto plugin = new PluginT;
725 
726  PluginInfoTLS<>::tls_pluginInfo = prevPluginInfo;
727 
728  // Create the resulting array and send it back to the host
730  GenerateConstructorArray<>::Constructor(result, in_pluginInfo->m_interfaces, plugin);
731  return result;
732  }
733 
734  /**
735  * \brief Plug-in instance destructor, as shared to the host.
736  *
737  * \param in_instance The copy of the structure (instance) to destroy.
738  */
739  static void Disembody(InterfaceArrayItem* in_instance)
740  {
741  // In CPP, our Disembody operation actually takes the first plug-in interface's instance,
742  // whatever that is, and casts it to our cpp base instance. They are all with a virtual dtor,
743  // so they are equivalent.
744  auto voidinstance = in_instance[0].m_instance;
745  auto cinstance = reinterpret_cast<ak_wwise_plugin_base_instance*>(voidinstance);
746  auto cppinstance = static_cast<ak_wwise_plugin_cpp_base_instance*>(cinstance);
747  delete cppinstance;
748  delete[] in_instance;
749  }
750 
751  /**
752  * \brief The unique m_pluginInfo used in the ak_wwise_plugin_container for that particular plug-in.
753  *
754  * Contains the m_interfaceArray member variable.
755  */
757 
758  PluginInfoGenerator(PluginRegistration* in_pluginRegistration, uint32_t in_pluginFlags = 0) :
759  m_pluginInfo(
760  &in_pluginRegistration->m_ulCompanyID,
761  &in_pluginRegistration->m_ulPluginID,
762  &in_pluginRegistration->m_eType,
763  in_pluginFlags,
764  in_pluginRegistration,
765  Instantiate,
766  Disembody,
769  ) {}
771  const AkUInt32* in_companyID,
772  const AkUInt32* in_pluginID,
773  const AkPluginType* in_pluginType,
774  uint32_t in_pluginFlags = 0) :
775  m_pluginInfo(
776  in_companyID,
777  in_pluginID,
778  in_pluginType,
779  in_pluginFlags,
780  nullptr,
781  Instantiate,
782  Disembody,
785  ) {}
786  ~PluginInfoGenerator() = default;
787  };
788 
789  template <bool _>
790 #ifndef _MANAGED
791  thread_local
792 #endif
794 } // of namespace AK::Wwise::Plugin
795 
796 /// \cond DOXYGEN_SKIP
797 #define AK_PLUGIN_USERGENERATEDPLUGININFO_NAMESPACE_NAME2(prefix,suffix) prefix##suffix
798 #define AK_PLUGIN_USERGENERATEDPLUGININFO_NAMESPACE_NAME1(prefix,suffix) AK_PLUGIN_USERGENERATEDPLUGININFO_NAMESPACE_NAME2(prefix, suffix)
799 /// \endcond
800 
801 #if defined(DOXYGEN_INCLUDE)
802 /**
803  * \brief Creates an unique PluginInfo instance for the plug-in registration
804  */
805 #define AK_PLUGIN_USERGENERATEDPLUGININFO_NAMESPACE_NAME AK_PLUGIN_USERGENERATEDPLUGININFO_NAMESPACE_NAME1(UserGeneratedPluginInfo, __COUNTER__)
806 #elif !defined(__COUNTER__)
807 #define AK_PLUGIN_USERGENERATEDPLUGININFO_NAMESPACE_NAME AK_PLUGIN_USERGENERATEDPLUGININFO_NAMESPACE_NAME1(UserGeneratedPluginInfo, __LINE__)
808 #elif __COUNTER__ == __COUNTER__
809 #define AK_PLUGIN_USERGENERATEDPLUGININFO_NAMESPACE_NAME AK_PLUGIN_USERGENERATEDPLUGININFO_NAMESPACE_NAME1(UserGeneratedPluginInfo, __LINE__)
810 #else
811 #define AK_PLUGIN_USERGENERATEDPLUGININFO_NAMESPACE_NAME AK_PLUGIN_USERGENERATEDPLUGININFO_NAMESPACE_NAME1(UserGeneratedPluginInfo, __COUNTER__)
812 #endif
813 
814 
815 
816 /**
817  * \brief (C++) Declares the plug-in container.
818  *
819  * The container name must be the plug-in file/xml name. For example, it should be AkCompressor for AkCompressor.dll/.xml.
820  *
821  * \param ContainerName Container name.
822  */
823 #ifdef AK_WIN
824 #define AK_DECLARE_PLUGIN_CONTAINER(ContainerName) \
825  extern "C" __declspec(dllexport) AK::Wwise::Plugin::PluginContainer* GetPluginContainer ## ContainerName()
826 #else
827 #define AK_DECLARE_PLUGIN_CONTAINER(ContainerName) \
828  extern "C" __attribute__ ((visibility ("default"))) AK::Wwise::Plugin::PluginContainer* GetPluginContainer ## ContainerName()
829 #endif
830 
831 /**
832  * \brief (C++) Defines the unique plug-in container.
833  *
834  * The container name must be the plug-in file/xml name. For example, it should be AkCompressor for AkCompressor.dll/.xml.
835  *
836  * \param ContainerName Container name.
837  */
838 #define AK_DEFINE_PLUGIN_CONTAINER(ContainerName) \
839  extern "C" \
840  AK::Wwise::Plugin::PluginContainer* GetPluginContainer ## ContainerName() \
841  { \
842  static AK::Wwise::Plugin::PluginContainer singleton; \
843  return &singleton; \
844  }
845 
846 /**
847  * \brief (C++) Exports the plug-in container for a shared library.
848  *
849  * The export name is ak_wwise_plugin_container_export_ContainerName, where ContainerName must be the
850  * plug-in file/xml name. For example, it should be AkCompressor for AkCompressor.dll/.xml.
851  *
852  * For non-Windows platforms, the export name is ak_wwise_plugin_container_export_libContainerName.
853  *
854  * \param ContainerName Container name.
855  */
856 #ifdef AK_WIN
857 #define AK_EXPORT_PLUGIN_CONTAINER(ContainerName) \
858  extern "C" __declspec(dllexport) AK::Wwise::Plugin::PluginContainer * ak_wwise_plugin_container_export_ ## ContainerName; \
859  AK::Wwise::Plugin::PluginContainer * ak_wwise_plugin_container_export_ ## ContainerName = GetPluginContainer ## ContainerName()
860 #else
861 #define AK_EXPORT_PLUGIN_CONTAINER(ContainerName) \
862  extern "C" __attribute__ ((visibility ("default"))) AK::Wwise::Plugin::PluginContainer * ak_wwise_plugin_container_export_lib ## ContainerName; \
863  AK::Wwise::Plugin::PluginContainer * ak_wwise_plugin_container_export_lib ## ContainerName = GetPluginContainer ## ContainerName()
864 #endif
865 
866 /**
867  * \brief (C++) Adds a Wwise Authoring plug-in and a Sound Engine plug-in to a plug-in container.
868  *
869  * Creates a custom namespace with custom plug-in info, that contains the generated plug-in info structure. Then,
870  * statically points it to the next pointer for the container.
871  *
872  * This uses the Sound Engine part to retrieve the plug-in information (Company id, Plug-in ID and Plug-in Type). It
873  * also adds up the Sound Engine's registration structure, so the host can initialize this part on first instantiation.
874  *
875  * \param ContainerName Container name.
876  * \param WwiseClassName Class name of the plug-in to add to the container.
877  * \param AudioEngineRegisteredName Sound Engine's class name.
878  *
879  * \sa
880  * - \ref AK_ADD_PLUGIN_CLASSID_TO_CONTAINER For a version without the Sound Engine part.
881  */
882 #define AK_ADD_PLUGIN_CLASS_TO_CONTAINER(ContainerName, WwiseClassName, AudioEngineRegisteredName) \
883  extern AK::PluginRegistration AudioEngineRegisteredName ## Registration; \
884  namespace { namespace AK_PLUGIN_USERGENERATEDPLUGININFO_NAMESPACE_NAME { \
885  static struct UserGeneratedPluginInfo : private AK::Wwise::Plugin::PluginInfoGenerator<WwiseClassName> \
886  { \
887  UserGeneratedPluginInfo() : \
888  PluginInfoGenerator(&AudioEngineRegisteredName ## Registration) \
889  { \
890  m_pluginInfo.m_next = GetPluginContainer ## ContainerName()->m_pluginInfos; \
891  GetPluginContainer ## ContainerName()->m_pluginInfos = &m_pluginInfo; \
892  } \
893  } g_singleton; \
894  } }
895 
896 /**
897  * \brief (C++) Adds a plug-in to a plug-in container.
898  *
899  * Creates a custom namespace with custom plug-in info, that contains the generated plug-in info structure. Then,
900  * statically points it to the next pointer for the container.
901  *
902  * \param ContainerName Container name.
903  * \param WwiseClassName Class name of the plug-in to add to the container.
904  * \param CompanyID Plug-in vendor's Company ID, as provided by Audiokinetic.
905  * \param PluginID Plug-in ID, as provided by Audiokinetic.
906  * \param Type Plug-in type.
907  *
908  * \sa
909  * - \ref AK_ADD_PLUGIN_CLASS_TO_CONTAINER For a version with the Sound Engine part.
910  */
911 #define AK_ADD_PLUGIN_CLASSID_TO_CONTAINER(ContainerName, WwiseClassName, CompanyID, PluginID, Type) \
912  namespace { namespace AK_PLUGIN_USERGENERATEDPLUGININFO_NAMESPACE_NAME { \
913  static struct UserGeneratedPluginInfo : private AK::Wwise::Plugin::PluginInfoGenerator<WwiseClassName> \
914  { \
915  const AkUInt32 m_companyID = CompanyID; \
916  const AkUInt32 m_pluginID = PluginID; \
917  const AkPluginType m_type = Type; \
918  UserGeneratedPluginInfo() : \
919  PluginInfoGenerator(&m_companyID, &m_pluginID, &m_type) \
920  { \
921  m_pluginInfo.m_next = GetPluginContainer ## ContainerName()->m_pluginInfos; \
922  GetPluginContainer ## ContainerName()->m_pluginInfos = &m_pluginInfo; \
923  } \
924  } g_singleton; \
925  } }
926 
927 /// \deprecated
928 #define AK_AUDIOPLUGIN_USERGENERATEDPLUGININFO_NAMESPACE_NAME AK_PLUGIN_USERGENERATEDPLUGININFO_NAMESPACE_NAME
929 
930 /// \deprecated
931 #define DECLARE_AUDIOPLUGIN_CONTAINER(x) AK_DECLARE_PLUGIN_CONTAINER(x)
932 
933 /// \deprecated
934 #define DEFINE_AUDIOPLUGIN_CONTAINER(x) AK_DEFINE_PLUGIN_CONTAINER(x)
935 
936 /// \deprecated
937 #define EXPORT_AUDIOPLUGIN_CONTAINER(x) AK_EXPORT_PLUGIN_CONTAINER(x)
938 
939 /// \deprecated
940 #define ADD_AUDIOPLUGIN_CLASS_TO_CONTAINER(x, y, z) AK_ADD_PLUGIN_CLASS_TO_CONTAINER(x, y, z)
941 
942 /// \deprecated
943 #define ADD_AUDIOPLUGIN_CLASSID_TO_CONTAINER(x, y, a, b, c) AK_ADD_PLUGIN_CLASSID_TO_CONTAINER(x, y, a, b, c)
944 
945 #endif // of __cplusplus
static void UpdateCInterface(const InterfaceArrayItem in_original[k_interfaceCount], int in_count=0)
PluginInfoGenerator: For each plug-in interface type, provides a single static instance used througho...
static void Constructor(InterfaceArrayItem &out_interface, const InterfaceArrayItem &in_original, PluginT *in_instance)
static void Constructor(InterfaceArrayItem out_interfaces[k_interfaceCount], const InterfaceArrayItem in_original[k_interfaceCount], PluginT *in_instance, int in_count=0)
decltype(BaseInterface::m_interface) InterfaceType
PluginInfoGenerator: Type for the m_interface value in BaseInterface.
Generic base for all plug-in instances. In C++, this is derived. In C, they are equivalent.
Definition: PluginDef.h:502
PluginInfoGenerator(const AkUInt32 *in_companyID, const AkUInt32 *in_pluginID, const AkPluginType *in_pluginType, uint32_t in_pluginFlags=0)
@ AK_WWISE_PLUGIN_INTERFACE_TYPE_PLUGIN_CONTAINER
2021.1 Plug-in container plug-in. Contains all the other plug-ins. ak_wwise_plugin_container
The interface information of the plug-in currently being instantiated.
static constexpr InterfaceArrayItem GenerateInterface()
Generates the InterfaceArrayItem for our particular type.
ak_wwise_plugin_interface_type m_interface
Interface type (see ak_wwise_plugin_interface_type)
typename UsedInterfaceVersions::first_type RequestedInterfaceVersions
VersionPack containing the requested versions of the interface by the plug-in.
static constexpr InterfaceArrayItem * GenerateInterfaceArray(InterfaceArrayItem out_interfaces[k_interfaceCount])
typename UsedInterfaceVersions::second_type ProvidedInterfaceVersions
VersionPack containing the provided versions of the interface by the plug-in.
static GluedInterface * g_cinterface
The unique instance of the CInterface interface. Defined at nullptr first, overridden by the Host onc...
Interface used to interact with the frontend model.
decltype(BaseInterface::m_version) InterfaceVersion
PluginInfoGenerator: Type for the m_version value in BaseInterface.
typename KnownInterfaceClass< in_interfaceType, k_interfaceVersion >::Type InterfaceClass
Interface class of the versioned interface type.
static GluedInterface g_cppinterface
The unique interface for this plug-in interface.
InterfaceArrayItem m_interfaceArray[k_interfaceCount]
Array of all used interfaces for the plug-in.
CInterfaceArrayItem InterfaceArrayItem
A single instantiatable plug-in interface.
Definition: PluginDef.h:1058
Casts the plug-in class to the requested interface class.
uint32_t m_version
Version of the interface.
PluginInfoGenerator: Compile-time dictionary of known interface-version.
static void UpdateCInterface(const InterfaceArrayItem &in_original)
#define AK_WWISESDK_VERSION_NATIVE_COMBINED
The specific version for native plug-in interfaces. Must be identical down to the build number.
Generates the constructor for our particular type.
PluginInfoGenerator: Requests a host-provided service, and optionally receives a variable containing ...
@ k_latestInterfaceVersion
Most up-to-date version of the interface in the current SDK.
Compile-time dictionary about a particular interface type.
PluginInfoGenerator: Defines a compile-time dictionary with the latest version known to the SDK for e...
Root interface allowing a logical unit (variable, library) to contain more than one interface.
static InterfaceArrayItem * Instantiate(PluginInfo *in_pluginInfo)
Plug-in instance constructor, as shared with the host.
static constexpr void GenerateInterfaceArray(InterfaceArrayItem out_interfaces[k_interfaceCount], int in_count, InterfaceArrayItem)
Recursively generates an interface array of all the Interfaces pointers.
static thread_local PluginInfo * tls_pluginInfo
static void Disembody(InterfaceArrayItem *in_instance)
Plug-in instance destructor, as shared to the host.
Generic base for all plug-in instances in C++.
Definition: PluginDef.h:521
PluginInfoGenerator: Associates an existing C Interface with a variable that can be used....
CPluginContainer PluginContainer
Root interface allowing a logical unit (variable, library) to contain more than one interface.
Definition: PluginDef.h:1060
PluginInfo m_pluginInfo
The unique m_pluginInfo used in the ak_wwise_plugin_container for that particular plug-in.
PluginInfoGenerator(PluginRegistration *in_pluginRegistration, uint32_t in_pluginFlags=0)
PluginInfoGenerator: Base class for every C++ instance that retrieves a service from the Wwise Author...
decltype(GetUsedInterfaceVersions()) UsedInterfaceVersions
Pair type containing a VersionPack of the requested versions and a VersionPack of the provided versio...
Recursively generates the constructors and interface pointer updater for all the Interfaces.
std::underlying_type< InterfaceType >::type InterfaceTypeValue
PluginInfoGenerator: Underlying storage type for the m_interface value in BaseInterface.
@ k_interfaceVersion
Version of the interface used by the plug-in or k_latestInterfaceVersion if unused.
typename CPPInstance::GluedInterface GluedInterface
AkPluginType
Definition: AkTypes.h:1186
static constexpr uint32_t GetLatest()
Get the latest version stored in the container. Assumes the container is sorted in ascending order.
static constexpr uint32_t GetInterfaceVersion()
Extract the version of the interface used by the plug-in.
static constexpr auto GetUsedInterfaceVersions(VersionPack< in_requestedVersions... >={}, VersionPack< in_providedVersions... >={})
Recursively accumulate each version of the interface requested or provided by the plug-in (there shou...
Interface description and base class for every Wwise Authoring plug-in interface.
static BaseInterface * GetPlaceholderPointer()
Get a Placeholder Pointer object.
Wwise Authoring Plug-ins - Root interface allowing a logical unit (variable, library) to contain more...
uint32_t AkUInt32
Unsigned 32-bit integer.
constexpr static InterfaceClass * Cast(PluginT *in_plugin)
A single instantiatable plug-in interface.
@ AK_WWISE_PLUGIN_INTERFACE_TYPE_UNKNOWN
2021.1 Unknown plug-in ID (0 - error, invalid, uninitialized)
CPPInstance * m_instance
The default instance for this plug-in interface.
@ AK_WWISE_PLUGIN_INTERFACE_TYPE_NUM
ak_wwise_plugin_instance_ptr m_instance
That particular instance.
struct ak_wwise_plugin_interface_array_item * m_interfaces
Definition: PluginInfo.h:57
ak_wwise_plugin_interface_ptr m_interface
The interface. Should be identical for every instance of this DLL.
@ k_interfaceCount
Number of interfaces we are currently using.
static constexpr size_t CountInterfaces()
Count the number of interfaces we are currently using.

Was this page helpful?

Need Support?

Questions? Problems? Need more info? Contact us, and we can help!

Visit our Support page

Tell us about your project. We're here to help.

Register your project and we'll help you get started with no strings attached!

Get started with Wwise