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