ReaWwise

REAPER extension
Log | Files | Refs | Submodules

Extension.cpp (23210B)


      1 /*----------------------------------------------------------------------------------------
      2 
      3 Copyright (c) 2023 AUDIOKINETIC Inc.
      4 
      5 This file is licensed to use under the license available at:
      6 https://github.com/audiokinetic/ReaWwise/blob/main/License.txt (the "License").
      7 You may not use this file except in compliance with the License.
      8 
      9 Unless required by applicable law or agreed to in writing, software distributed
     10 under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
     11 CONDITIONS OF ANY KIND, either express or implied.  See the License for the
     12 specific language governing permissions and limitations under the License.
     13 
     14 ----------------------------------------------------------------------------------------*/
     15 
     16 #define REAPERAPI_IMPLEMENT
     17 
     18 #include "Core/WaapiClient.h"
     19 #include "ReaperContext.h"
     20 #include "ReaperPlugin.h"
     21 #include "Theme/CustomLookAndFeel.h"
     22 #include "UI/MainWindow.h"
     23 
     24 #include <JSONHelpers.h>
     25 #include <juce_events/juce_events.h>
     26 #include <memory>
     27 #include <reaper_plugin_functions.h>
     28 #include <tuple>
     29 #include <variant>
     30 
     31 namespace AK::ReaWwise
     32 {
     33 	static bool guiInitialised = false;
     34 	static std::unique_ptr<WwiseTransfer::MainWindow> mainWindow;
     35 	static std::unique_ptr<ReaperContext> reaperContext;
     36 	static std::unique_ptr<IReaperPlugin> reaperPlugin;
     37 	static std::string returnString;
     38 	static std::string emptyReturnString;
     39 	static double returnDouble;
     40 	static int openReaperWwiseTransferCommandId = 0;
     41 
     42 	static void onHookCustomMenu(const char* menuName, HMENU menuHandle, int flag)
     43 	{
     44 		if(flag == 0 && juce::String(menuName) == "Main extensions" && openReaperWwiseTransferCommandId)
     45 		{
     46 			MENUITEMINFO mi = {sizeof(MENUITEMINFO)};
     47 			mi.fMask = MIIM_TYPE | MIIM_ID;
     48 			mi.fType = MFT_STRING;
     49 			mi.wID = openReaperWwiseTransferCommandId;
     50 			mi.dwTypeData = (char*)"ReaWwise";
     51 			InsertMenuItem(menuHandle, 0, true, &mi);
     52 		}
     53 	}
     54 
     55 	static void initialiseGui()
     56 	{
     57 		juce::initialiseJuce_GUI();
     58 		guiInitialised = true;
     59 	}
     60 
     61 	static void initialiseMainWindow()
     62 	{
     63 		mainWindow = std::make_unique<WwiseTransfer::MainWindow>(*reaperContext, JUCE_APPLICATION_NAME_STRING, false);
     64 #ifdef WIN32
     65 		mainWindow->addToDesktop(mainWindow->getDesktopWindowStyleFlags(), reaperPlugin->getMainHwnd());
     66 #else
     67 		mainWindow->addToDesktop(mainWindow->getDesktopWindowStyleFlags(), 0);
     68 #endif
     69 	}
     70 
     71 	static bool onHookCommand(int command, int flag)
     72 	{
     73 		if(command == openReaperWwiseTransferCommandId)
     74 		{
     75 			if(!guiInitialised)
     76 				initialiseGui();
     77 
     78 			if(mainWindow == nullptr)
     79 				initialiseMainWindow();
     80 
     81 			mainWindow->setVisible(!mainWindow->isVisible());
     82 
     83 			return true;
     84 		}
     85 
     86 		return false;
     87 	}
     88 
     89 	namespace Scripting
     90 	{
     91 		using namespace AK::WwiseAuthoringAPI;
     92 
     93 		static std::unique_ptr<WwiseTransfer::WaapiClient> waapiClient;
     94 
     95 		template <typename Type>
     96 		static bool isObjectValid(Type* object, const std::set<Type>& objectSet)
     97 		{
     98 			return object != nullptr && objectSet.find(*object) != objectSet.end();
     99 		}
    100 
    101 		static bool isWaapiClientConnected()
    102 		{
    103 			return waapiClient != nullptr && waapiClient->isConnected();
    104 		}
    105 
    106 		template <class T>
    107 		static T argCast(void* arg)
    108 		{
    109 			return (T)arg;
    110 		}
    111 
    112 		template <>
    113 		double argCast<double>(void* arg)
    114 		{
    115 			return *(double*)arg;
    116 		}
    117 
    118 		template <>
    119 		int argCast<int>(void* arg)
    120 		{
    121 			return (int)(intptr_t)arg;
    122 		}
    123 
    124 		template <class... Types>
    125 		struct Arguments : public std::tuple<Types...>
    126 		{
    127 			Arguments(void** args)
    128 			{
    129 				populate(args);
    130 			}
    131 
    132 			template <size_t I>
    133 			auto get()
    134 			{
    135 				return std::get<I>(*this);
    136 			}
    137 
    138 		private:
    139 			template <size_t I = 0>
    140 			constexpr void populate(void** args)
    141 			{
    142 				if constexpr(I == sizeof...(Types))
    143 				{
    144 					return;
    145 				}
    146 				else
    147 				{
    148 					using Type = typename std::tuple_element<I, std::tuple<Types...>>::type;
    149 
    150 					std::get<I, Types...>(*this) = argCast<Type>(args[I]);
    151 					populate<I + 1>(args);
    152 				}
    153 			}
    154 		};
    155 
    156 		struct AkJsonRef
    157 		{
    158 			typedef std::map<std::string, std::shared_ptr<AkJsonRef>> Map;
    159 			typedef std::vector<std::shared_ptr<AkJsonRef>> Array;
    160 
    161 			std::variant<AkVariant, Map, Array> data;
    162 
    163 			AkJsonRef() = default;
    164 
    165 			AkJsonRef(const std::variant<AkVariant, Map, Array>& data)
    166 				: data(data)
    167 			{
    168 			}
    169 
    170 			virtual ~AkJsonRef()
    171 			{
    172 			}
    173 
    174 			bool isMap() const
    175 			{
    176 				return std::holds_alternative<Map>(data);
    177 			}
    178 
    179 			bool isArray() const
    180 			{
    181 				return std::holds_alternative<Array>(data);
    182 			}
    183 
    184 			bool isVariant() const
    185 			{
    186 				return std::holds_alternative<AkVariant>(data);
    187 			}
    188 		};
    189 
    190 		static AkJsonRef AkJsonToAkJsonRef(const AkJson& akJson)
    191 		{
    192 			if(akJson.IsMap())
    193 			{
    194 				AkJsonRef::Map map{};
    195 
    196 				for(auto& [key, value] : akJson.GetMap())
    197 				{
    198 					map[key] = std::make_shared<AkJsonRef>(AkJsonToAkJsonRef(value));
    199 				}
    200 
    201 				return AkJsonRef{map};
    202 			}
    203 			else if(akJson.IsArray())
    204 			{
    205 				AkJsonRef::Array array{};
    206 
    207 				for(auto& value : akJson.GetArray())
    208 				{
    209 					array.emplace_back(std::make_shared<AkJsonRef>(AkJsonToAkJsonRef(value)));
    210 				}
    211 
    212 				return AkJsonRef{array};
    213 			}
    214 			else if(akJson.IsVariant())
    215 			{
    216 				return AkJsonRef{akJson.GetVariant()};
    217 			}
    218 
    219 			return AkJsonRef();
    220 		}
    221 
    222 		static AkJson AkJsonRefToAkJson(std::shared_ptr<AkJsonRef> akJsonRef)
    223 		{
    224 			if(akJsonRef->isMap())
    225 			{
    226 				AkJson::Map mapAsAkJson{};
    227 
    228 				AkJsonRef::Map& map = std::get<AkJsonRef::Map>(akJsonRef->data);
    229 				for(auto& [key, value] : map)
    230 				{
    231 					mapAsAkJson.emplace(key, AkJsonRefToAkJson(value));
    232 				}
    233 
    234 				return AkJson(mapAsAkJson);
    235 			}
    236 			else if(akJsonRef->isArray())
    237 			{
    238 				AkJson::Array arrayAsAkJson{};
    239 
    240 				AkJsonRef::Array& arr = std::get<AkJsonRef::Array>(akJsonRef->data);
    241 				for(auto& element : arr)
    242 				{
    243 					arrayAsAkJson.emplace_back(AkJsonRefToAkJson(element));
    244 				}
    245 
    246 				return AkJson(arrayAsAkJson);
    247 			}
    248 			else if(akJsonRef->isVariant())
    249 			{
    250 				return AkJson(std::get<AkVariant>(akJsonRef->data));
    251 			}
    252 
    253 			return AkJson();
    254 		}
    255 
    256 		struct AkJsonRefWithStatus : public AkJsonRef
    257 		{
    258 			bool status;
    259 		};
    260 
    261 		static std::set<std::shared_ptr<AkJsonRef>> objects;
    262 
    263 		///////// Waapi /////////
    264 
    265 		static bool Waapi_Connect(const char* ipAddress, intptr_t port)
    266 		{
    267 			if(waapiClient == nullptr)
    268 				waapiClient.reset(new WwiseTransfer::WaapiClient());
    269 
    270 			if(!waapiClient->isConnected())
    271 				return waapiClient->connect(ipAddress, port);
    272 
    273 			return true;
    274 		}
    275 
    276 		static void* Waapi_ConnectVarArg(void** argv, int argc)
    277 		{
    278 			juce::ignoreUnused(argc);
    279 
    280 			return (void*)Waapi_Connect((const char*)argv[0], (intptr_t)argv[1]);
    281 		}
    282 
    283 		static void Waapi_Disconnect()
    284 		{
    285 			if(waapiClient != nullptr)
    286 			{
    287 				if(waapiClient->isConnected())
    288 					waapiClient->disconnect();
    289 
    290 				waapiClient.reset(nullptr);
    291 			}
    292 		}
    293 
    294 		static void Waapi_DisconnectVarArg(void** argv, int argc)
    295 		{
    296 			Waapi_Disconnect();
    297 		}
    298 
    299 		static bool Waapi_IsConnected()
    300 		{
    301 			return waapiClient != nullptr && waapiClient->isConnected();
    302 		}
    303 
    304 		static void* Waapi_IsConnectedVarArg(void** argv, int argc)
    305 		{
    306 			juce::ignoreUnused(argc);
    307 
    308 			return (void*)Waapi_IsConnected();
    309 		}
    310 
    311 		static void* Waapi_Call(const char* uri, std::shared_ptr<AkJsonRef>* args, std::shared_ptr<AkJsonRef>* options)
    312 		{
    313 			if(isWaapiClientConnected() && isObjectValid(args, objects) && isObjectValid(options, objects))
    314 			{
    315 				AkJson result;
    316 
    317 				AkJsonRefWithStatus akJsonResult;
    318 				akJsonResult.status = waapiClient->call(uri, AkJsonRefToAkJson(*args), AkJsonRefToAkJson(*options), result);
    319 
    320 				akJsonResult.data = AkJsonToAkJsonRef(result).data;
    321 
    322 				auto insert = objects.insert(std::make_shared<AkJsonRefWithStatus>(akJsonResult));
    323 
    324 				if(insert.second)
    325 					return (void*)&(*insert.first);
    326 			}
    327 
    328 			return nullptr;
    329 		}
    330 
    331 		static void* Waapi_CallVarArg(void** argv, int argc)
    332 		{
    333 			juce::ignoreUnused(argc);
    334 
    335 			Arguments<const char*, std::shared_ptr<AkJsonRef>*, std::shared_ptr<AkJsonRef>*> arguments(argv);
    336 
    337 			return Waapi_Call(arguments.get<0>(), arguments.get<1>(), arguments.get<2>());
    338 		}
    339 
    340 		///////// AkJson_Any /////////
    341 
    342 		template <typename T>
    343 		static void* AkJson_Any()
    344 		{
    345 			auto result = objects.insert(std::make_shared<AkJsonRef>(T{}));
    346 
    347 			if(result.second)
    348 				return (void*)&(*result.first);
    349 
    350 			return nullptr;
    351 		}
    352 
    353 		///////// AkJson_Map /////////
    354 		static void* AkJson_Map()
    355 		{
    356 			return AkJson_Any<AkJsonRef::Map>();
    357 		}
    358 
    359 		static void* AkJson_MapVarArg(void** argv, int argc)
    360 		{
    361 			juce::ignoreUnused(argc);
    362 
    363 			return AkJson_Map();
    364 		}
    365 
    366 		static bool AkJson_Map_Set(std::shared_ptr<AkJsonRef>* akJsonRef, const char* key, std::shared_ptr<AkJsonRef>* value)
    367 		{
    368 			if(isObjectValid(akJsonRef, objects) && isObjectValid(value, objects) && (**akJsonRef).isMap())
    369 			{
    370 				AkJsonRef::Map& map = std::get<AkJsonRef::Map>((**akJsonRef).data);
    371 				map[key] = *value;
    372 
    373 				return true;
    374 			}
    375 
    376 			return false;
    377 		}
    378 
    379 		static void* AkJson_Map_SetVarArg(void** argv, int argc)
    380 		{
    381 			juce::ignoreUnused(argc);
    382 
    383 			Arguments<std::shared_ptr<AkJsonRef>*, const char*, std::shared_ptr<AkJsonRef>*> arguments(argv);
    384 
    385 			return (void*)AkJson_Map_Set(arguments.get<0>(), arguments.get<1>(), arguments.get<2>());
    386 		}
    387 
    388 		static void* AkJson_Map_Get(std::shared_ptr<AkJsonRef>* akJsonRef, const char* key)
    389 		{
    390 			if(isObjectValid(akJsonRef, objects) && (**akJsonRef).isMap())
    391 			{
    392 				AkJsonRef::Map& map = std::get<AkJsonRef::Map>((**akJsonRef).data);
    393 
    394 				if(map.find(key) != map.end())
    395 				{
    396 					if(objects.find(map[key]) == objects.end())
    397 						objects.insert(map[key]);
    398 
    399 					return (void*)&map[key];
    400 				}
    401 			}
    402 
    403 			return nullptr;
    404 		}
    405 
    406 		static void* AkJson_Map_GetVarArg(void** argv, int argc)
    407 		{
    408 			juce::ignoreUnused(argc);
    409 
    410 			Arguments<std::shared_ptr<AkJsonRef>*, const char*> arguments(argv);
    411 
    412 			return AkJson_Map_Get(arguments.get<0>(), arguments.get<1>());
    413 		}
    414 
    415 		///////// AkJson_Array /////////
    416 		static void* AkJson_Array()
    417 		{
    418 			return AkJson_Any<AkJsonRef::Array>();
    419 		}
    420 
    421 		static void* AkJson_ArrayVarArg(void** argv, int argc)
    422 		{
    423 			juce::ignoreUnused(argc);
    424 
    425 			return AkJson_Array();
    426 		}
    427 
    428 		static bool AkJson_Array_Add(std::shared_ptr<AkJsonRef>* akJsonRef, std::shared_ptr<AkJsonRef>* value)
    429 		{
    430 			if(isObjectValid(akJsonRef, objects) && isObjectValid(value, objects) && (**akJsonRef).isArray())
    431 			{
    432 				AkJsonRef::Array& array = std::get<AkJsonRef::Array>((**akJsonRef).data);
    433 				array.emplace_back(*value);
    434 
    435 				return true;
    436 			}
    437 
    438 			return false;
    439 		}
    440 
    441 		static void* AkJson_Array_AddVarArg(void** argv, int argc)
    442 		{
    443 			juce::ignoreUnused(argc);
    444 
    445 			Arguments<std::shared_ptr<AkJsonRef>*, std::shared_ptr<AkJsonRef>*> arguments(argv);
    446 
    447 			return (void*)AkJson_Array_Add(arguments.get<0>(), arguments.get<1>());
    448 		}
    449 
    450 		static void* AkJson_Array_Get(std::shared_ptr<AkJsonRef>* akJsonRef, int index)
    451 		{
    452 			if(isObjectValid(akJsonRef, objects) && (**akJsonRef).isArray())
    453 			{
    454 				AkJsonRef::Array& array = std::get<AkJsonRef::Array>((**akJsonRef).data);
    455 
    456 				if(index < array.size())
    457 				{
    458 					if(objects.find(array[index]) == objects.end())
    459 						objects.insert(array[index]);
    460 
    461 					return (void*)&array[index];
    462 				}
    463 			}
    464 
    465 			return nullptr;
    466 		}
    467 
    468 		static void* AkJson_Array_GetVarArg(void** argv, int argc)
    469 		{
    470 			juce::ignoreUnused(argc);
    471 
    472 			Arguments<std::shared_ptr<AkJsonRef>*, int> arguments(argv);
    473 
    474 			return AkJson_Array_Get(arguments.get<0>(), arguments.get<1>());
    475 		}
    476 
    477 		static int AkJson_Array_Size(std::shared_ptr<AkJsonRef>* akJsonRef)
    478 		{
    479 			if(isObjectValid(akJsonRef, objects) && (**akJsonRef).isArray())
    480 			{
    481 				AkJsonRef::Array& array = std::get<AkJsonRef::Array>((**akJsonRef).data);
    482 				return array.size();
    483 			}
    484 
    485 			return 0;
    486 		}
    487 
    488 		static void* AkJson_Array_SizeVarArg(void** argv, int argc)
    489 		{
    490 			juce::ignoreUnused(argc);
    491 
    492 			Arguments<std::shared_ptr<AkJsonRef>*> arguments(argv);
    493 
    494 			return (void*)(intptr_t)AkJson_Array_Size(arguments.get<0>());
    495 		}
    496 
    497 		///////// AkVariant /////////
    498 
    499 		template <typename T>
    500 		static void* AkVariant_Any(T value)
    501 		{
    502 			auto result = objects.insert(std::make_shared<AkJsonRef>(AkVariant(value)));
    503 
    504 			if(result.second)
    505 				return (void*)&(*result.first);
    506 
    507 			return nullptr;
    508 		}
    509 
    510 		static void* AkVariant_Bool(bool value)
    511 		{
    512 			return AkVariant_Any(value);
    513 		}
    514 
    515 		static void* AkVariant_BoolVarArg(void** argv, int argc)
    516 		{
    517 			juce::ignoreUnused(argc);
    518 
    519 			Arguments<bool> arguments(argv);
    520 
    521 			return AkVariant_Bool(arguments.get<0>());
    522 		}
    523 
    524 		static void* AkVariant_Int(int value)
    525 		{
    526 			return AkVariant_Any(value);
    527 		}
    528 
    529 		static void* AkVariant_IntVarArg(void** argv, int argc)
    530 		{
    531 			juce::ignoreUnused(argc);
    532 
    533 			Arguments<int> arguments(argv);
    534 
    535 			return AkVariant_Int(arguments.get<0>());
    536 		}
    537 
    538 		static void* AkVariant_Double(double value)
    539 		{
    540 			return AkVariant_Any(value);
    541 		}
    542 
    543 		static void* AkVariant_DoubleVarArg(void** argv, int argc)
    544 		{
    545 			juce::ignoreUnused(argc);
    546 
    547 			Arguments<double> arguments(argv);
    548 
    549 			return AkVariant_Double(arguments.get<0>());
    550 		}
    551 
    552 		static void* AkVariant_String(const char* value)
    553 		{
    554 			return AkVariant_Any(value);
    555 		}
    556 
    557 		static void* AkVariant_StringVarArg(void** argv, int argc)
    558 		{
    559 			juce::ignoreUnused(argc);
    560 
    561 			Arguments<const char*> arguments(argv);
    562 
    563 			return AkVariant_String(arguments.get<0>());
    564 		}
    565 
    566 		template <typename T>
    567 		static T AkVariant_GetAny(std::shared_ptr<AkJsonRef>* akJsonRef)
    568 		{
    569 			if(isObjectValid(akJsonRef, objects) && (**akJsonRef).isVariant())
    570 			{
    571 				AkVariant& variant = std::get<AkVariant>((**akJsonRef).data);
    572 				return (T)variant;
    573 			}
    574 
    575 			return 0;
    576 		}
    577 
    578 		template <>
    579 		const char* AkVariant_GetAny<const char*>(std::shared_ptr<AkJsonRef>* akJsonRef)
    580 		{
    581 			if(isObjectValid(akJsonRef, objects) && (**akJsonRef).isVariant())
    582 			{
    583 				AkVariant& variant = std::get<AkVariant>((**akJsonRef).data);
    584 				returnString = variant.GetString();
    585 
    586 				return returnString.c_str();
    587 			}
    588 
    589 			return emptyReturnString.c_str();
    590 		}
    591 
    592 		static bool AkVariant_GetBool(std::shared_ptr<AkJsonRef>* akJsonRef)
    593 		{
    594 			return AkVariant_GetAny<bool>(akJsonRef);
    595 		}
    596 
    597 		static void* AkVariant_GetBoolVarArg(void** argv, int argc)
    598 		{
    599 			Arguments<std::shared_ptr<AkJsonRef>*> arguments(argv);
    600 
    601 			return (void*)AkVariant_GetBool(arguments.get<0>());
    602 		}
    603 
    604 		static int AkVariant_GetInt(std::shared_ptr<AkJsonRef>* akJsonRef)
    605 		{
    606 			return AkVariant_GetAny<int>(akJsonRef);
    607 		}
    608 
    609 		static void* AkVariant_GetIntVarArg(void** argv, int argc)
    610 		{
    611 			juce::ignoreUnused(argc);
    612 
    613 			Arguments<std::shared_ptr<AkJsonRef>*> arguments(argv);
    614 
    615 			return (void*)(intptr_t)AkVariant_GetInt(arguments.get<0>());
    616 		}
    617 
    618 		static double AkVariant_GetDouble(std::shared_ptr<AkJsonRef>* akJsonRef)
    619 		{
    620 			return AkVariant_GetAny<double>(akJsonRef);
    621 		}
    622 
    623 		static void* AkVariant_GetDoubleVarArg(void** argv, int argc)
    624 		{
    625 			juce::ignoreUnused(argc);
    626 
    627 			Arguments<std::shared_ptr<AkJsonRef>*> arguments(argv);
    628 
    629 			returnDouble = AkVariant_GetDouble(arguments.get<0>());
    630 			return reinterpret_cast<void*>(&returnDouble);
    631 		}
    632 
    633 		static const char* AkVariant_GetString(std::shared_ptr<AkJsonRef>* akJsonRef)
    634 		{
    635 			return AkVariant_GetAny<const char*>(akJsonRef);
    636 		}
    637 
    638 		static void* AkVariant_GetStringVarArg(void** argv, int argc)
    639 		{
    640 			juce::ignoreUnused(argc);
    641 
    642 			Arguments<std::shared_ptr<AkJsonRef>*> arguments(argv);
    643 
    644 			return (void*)AkVariant_GetString(arguments.get<0>());
    645 		}
    646 
    647 		///////// AkJsonRefWithStatus /////////
    648 
    649 		static const bool AkJson_GetStatus(std::shared_ptr<AkJsonRef>* akJsonRef)
    650 		{
    651 			if(isObjectValid(akJsonRef, objects))
    652 			{
    653 				if(auto akJsonResult = std::dynamic_pointer_cast<AkJsonRefWithStatus>(*akJsonRef))
    654 				{
    655 					return akJsonResult->status;
    656 				};
    657 			}
    658 
    659 			return false;
    660 		}
    661 
    662 		static void* AkJson_GetStatusVarArg(void** argv, int argc)
    663 		{
    664 			juce::ignoreUnused(argc);
    665 
    666 			Arguments<std::shared_ptr<AkJsonRef>*> arguments(argv);
    667 
    668 			return (void*)AkJson_GetStatus(arguments.get<0>());
    669 		}
    670 
    671 		static const bool AkJson_Clear(std::shared_ptr<AkJsonRef>* akJsonRef)
    672 		{
    673 			if(isObjectValid(akJsonRef, objects))
    674 				return objects.erase(*akJsonRef) == 1;
    675 
    676 			return false;
    677 		}
    678 
    679 		static void* AkJson_ClearVarArg(void** argv, int argc)
    680 		{
    681 			juce::ignoreUnused(argc);
    682 
    683 			Arguments<std::shared_ptr<AkJsonRef>*> arguments(argv);
    684 
    685 			return (void*)AkJson_Clear(arguments.get<0>());
    686 		}
    687 
    688 		static const bool AkJson_ClearAll()
    689 		{
    690 			objects.clear();
    691 
    692 			return objects.size() == 0;
    693 		}
    694 
    695 		static void* AkJson_ClearAllVarArg(void** argv, int argc)
    696 		{
    697 			juce::ignoreUnused(argv, argc);
    698 
    699 			return (void*)AkJson_ClearAll();
    700 		}
    701 
    702 		static void ReaWwise_Open()
    703 		{
    704 			if(!guiInitialised)
    705 				initialiseGui();
    706 
    707 			if(mainWindow == nullptr)
    708 				initialiseMainWindow();
    709 
    710 			if(!mainWindow->isVisible())
    711 				mainWindow->setVisible(true);
    712 		}
    713 
    714 		static void ReaWwise_Close()
    715 		{
    716 			if(mainWindow && mainWindow->isVisible())
    717 				mainWindow->setVisible(false);
    718 		}
    719 
    720 		static void ReaWwise_TransferToWwise()
    721 		{
    722 			if(mainWindow)
    723 				mainWindow->transferToWwise();
    724 		}
    725 
    726 		struct ApiAction
    727 		{
    728 			int id;
    729 			custom_action_register_t definition;
    730 			void (*function)();
    731 		};
    732 
    733 		static ApiAction apiActions[] = {
    734 			ApiAction{0, {0, "AK_ReaWwise_Open", "ReaWwise: Open", nullptr}, &ReaWwise_Open},
    735 			ApiAction{0, {0, "AK_ReaWwise_Close", "ReaWwise: Close", nullptr}, &ReaWwise_Close},
    736 			ApiAction{0, {0, "AK_ReaWwise_TransferToWwise", "ReaWwise: Transfer To Wwise (Using current settings)", nullptr}, &ReaWwise_TransferToWwise},
    737 		};
    738 
    739 		struct ApiFunctionDefinition
    740 		{
    741 			const char* Api;
    742 			const char* ApiVarArg;
    743 			const char* ApiDef;
    744 			const char* FunctionSignature;
    745 			void* FunctionPointer;
    746 			void* FunctionPointerVarArg;
    747 		};
    748 
    749 #define AK_RWT_GENERATE_API_FUNC_DEF(functionName, output, inputs, inputNames, description) \
    750 	ApiFunctionDefinition                                                                   \
    751 	{                                                                                       \
    752 		"API_AK_" #functionName,                                                            \
    753 			"APIvararg_AK_" #functionName,                                                  \
    754 			"APIdef_AK_" #functionName,                                                     \
    755 			output "\0" inputs "\0" inputNames "\0" description,                            \
    756 			(void*)&functionName,                                                           \
    757 			(void*)&functionName##VarArg                                                    \
    758 	}
    759 
    760 		static auto apiFunctionDefinitions = {
    761 			AK_RWT_GENERATE_API_FUNC_DEF(Waapi_Connect, "bool", "const char*,int", "ipAddress,port", "Ak: Connect to waapi (Returns connection status as bool)"),
    762 			AK_RWT_GENERATE_API_FUNC_DEF(Waapi_Disconnect, "void", "", "", "Ak: Disconnect from waapi"),
    763 			AK_RWT_GENERATE_API_FUNC_DEF(Waapi_Call, "*", "const char*,*,*", "uri,*,*", "Ak: Make a call to Waapi"),
    764 
    765 			AK_RWT_GENERATE_API_FUNC_DEF(AkJson_Map, "*", "", "", "Ak: Create a map object"),
    766 			AK_RWT_GENERATE_API_FUNC_DEF(AkJson_Map_Get, "*", "*,const char*", "*,key", "Ak: Get a map object"),
    767 			AK_RWT_GENERATE_API_FUNC_DEF(AkJson_Map_Set, "bool", "*,const char*,*", "*,key,*", "Ak: Set a property on a map object"),
    768 
    769 			AK_RWT_GENERATE_API_FUNC_DEF(AkJson_Array, "*", "", "", "Ak: Create an array object"),
    770 			AK_RWT_GENERATE_API_FUNC_DEF(AkJson_Array_Add, "bool", "*,*", "*,*", "Ak: Add element to an array object"),
    771 			AK_RWT_GENERATE_API_FUNC_DEF(AkJson_Array_Get, "*", "*,int", "*,index", "Ak: Get element at index of array object"),
    772 			AK_RWT_GENERATE_API_FUNC_DEF(AkJson_Array_Size, "int", "*", "*", "Ak: Get count of elements in array object"),
    773 
    774 			AK_RWT_GENERATE_API_FUNC_DEF(AkJson_GetStatus, "bool", "*", "*", "Ak: Get the status of a result from a call to waapi"),
    775 
    776 			AK_RWT_GENERATE_API_FUNC_DEF(AkJson_Clear, "bool", "*", "*", "Ak: Clear object referenced by pointer"),
    777 			AK_RWT_GENERATE_API_FUNC_DEF(AkJson_ClearAll, "bool", "", "", "Ak: Clear all objects rederenced by pointers"),
    778 
    779 			AK_RWT_GENERATE_API_FUNC_DEF(AkVariant_Bool, "*", "bool", "bool", "Ak: Create a bool object"),
    780 			AK_RWT_GENERATE_API_FUNC_DEF(AkVariant_GetBool, "bool", "*", "*", "Ak: Extract raw boolean value from bool object"),
    781 
    782 			AK_RWT_GENERATE_API_FUNC_DEF(AkVariant_String, "*", "const char*", "string", "Ak: Create a string object"),
    783 			AK_RWT_GENERATE_API_FUNC_DEF(AkVariant_GetString, "const char*", "*", "*", "Ak: Extract raw string value from string object"),
    784 
    785 			AK_RWT_GENERATE_API_FUNC_DEF(AkVariant_Int, "*", "int", "int", "Ak: Create an int object"),
    786 			AK_RWT_GENERATE_API_FUNC_DEF(AkVariant_GetInt, "int", "*", "*", "Ak: Extract raw int value from int object"),
    787 
    788 			AK_RWT_GENERATE_API_FUNC_DEF(AkVariant_Double, "*", "double", "double", "Ak: Create a double object"),
    789 			AK_RWT_GENERATE_API_FUNC_DEF(AkVariant_GetDouble, "double", "*", "*", "Ak: Extract raw double value from double object"),
    790 		};
    791 
    792 #undef AK_RWT_GENERATE_API_FUNC_DEF
    793 	} // namespace Scripting
    794 
    795 	static bool onHookCommand2(KbdSectionInfo* sec, int command, int val, int val2, int relmode, HWND hwnd)
    796 	{
    797 		for(const auto& apiAction : Scripting::apiActions)
    798 		{
    799 			if(apiAction.id == command)
    800 			{
    801 				apiAction.function();
    802 				return true;
    803 			}
    804 		}
    805 
    806 		return false;
    807 	}
    808 
    809 	static int initialize(reaper_plugin_info_t* pluginInfo)
    810 	{
    811 		reaperPlugin = std::make_unique<ReaperPlugin>(pluginInfo);
    812 		reaperContext = std::make_unique<ReaperContext>(*reaperPlugin);
    813 
    814 		// Should actually report errors to the user somehow
    815 		if(reaperPlugin->getCallerVersion() != REAPER_PLUGIN_VERSION)
    816 		{
    817 			return 0;
    818 		}
    819 
    820 		// Checks that all function pointers needed from reaper are valid
    821 		if(!reaperPlugin->isValid())
    822 		{
    823 			return 0;
    824 		}
    825 
    826 		openReaperWwiseTransferCommandId = reaperPlugin->registerFunction("command_id", (void*)"openReaperWwiseTransferCommand");
    827 		if(!openReaperWwiseTransferCommandId)
    828 		{
    829 			return 0;
    830 		}
    831 
    832 		if(!reaperPlugin->registerFunction("hookcommand2", (void*)onHookCommand2))
    833 		{
    834 			return 0;
    835 		}
    836 
    837 		if(!reaperPlugin->registerFunction("hookcommand", (void*)onHookCommand))
    838 		{
    839 			return 0;
    840 		}
    841 
    842 		if(!reaperPlugin->registerFunction("hookcustommenu", (void*)onHookCustomMenu))
    843 		{
    844 			return 0;
    845 		}
    846 
    847 		reaperPlugin->addExtensionsMainMenu();
    848 
    849 		for(const auto& apiFunctionDefinition : Scripting::apiFunctionDefinitions)
    850 		{
    851 			reaperPlugin->registerFunction(apiFunctionDefinition.Api, (void*)apiFunctionDefinition.FunctionPointer);
    852 			reaperPlugin->registerFunction(apiFunctionDefinition.ApiVarArg, (void*)apiFunctionDefinition.FunctionPointerVarArg);
    853 			reaperPlugin->registerFunction(apiFunctionDefinition.ApiDef, (void*)apiFunctionDefinition.FunctionSignature);
    854 		}
    855 
    856 		for(auto& apiAction : Scripting::apiActions)
    857 		{
    858 			apiAction.id = reaperPlugin->registerFunction("custom_action", (void*)&apiAction.definition);
    859 		}
    860 
    861 		return 1;
    862 	}
    863 
    864 	static int cleanup()
    865 	{
    866 		if(mainWindow != nullptr)
    867 		{
    868 			mainWindow->removeFromDesktop();
    869 			mainWindow.reset(nullptr);
    870 		}
    871 
    872 		if(reaperContext != nullptr)
    873 			reaperContext.reset(nullptr);
    874 
    875 		if(Scripting::waapiClient != nullptr)
    876 			Scripting::waapiClient.reset(nullptr);
    877 
    878 		if(Scripting::objects.size() > 0)
    879 			Scripting::objects.clear();
    880 
    881 		if(guiInitialised)
    882 		{
    883 			juce::shutdownJuce_GUI();
    884 			guiInitialised = false;
    885 		}
    886 
    887 		return 0;
    888 	}
    889 } // namespace AK::ReaWwise
    890 
    891 extern "C" REAPER_PLUGIN_DLL_EXPORT int REAPER_PLUGIN_ENTRYPOINT(
    892 	REAPER_PLUGIN_HINSTANCE instance, reaper_plugin_info_t* pluginInfo)
    893 {
    894 	using namespace AK::ReaWwise;
    895 
    896 	return pluginInfo ? initialize(pluginInfo) : cleanup();
    897 }