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 }