ReaWwise

REAPER extension
Log | Files | Refs | Submodules

commit d20b67ada31c0c86be91c6f841980645fe933425
parent 358fdd8a26ce56536561b8c43b0dab1d3db7b9b7
Author: Andrew Costa <acosta@audiokinetic.com>
Date:   Wed, 24 Aug 2022 14:48:12 -0400

Initial Commit

Change-Id: I869b1f96c5f9475e51062acdfcd0da88aab1fdff

Diffstat:
A.clang-format | 25+++++++++++++++++++++++++
A.gitconfig | 5+++++
A.gitignore | 4++++
A.gitmodules | 16++++++++++++++++
A3rd/Catch2 | 1+
A3rd/JUCE | 1+
A3rd/WDL | 1+
A3rd/rapidjson | 1+
A3rd/reaper-sdk/README | 18++++++++++++++++++
A3rd/reaper-sdk/sdk/LICENSE | 15+++++++++++++++
A3rd/reaper-sdk/sdk/reaper_plugin.h | 1395+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A3rd/reaper-sdk/sdk/reaper_plugin_functions.h | 9594+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A3rd/trompeloeil | 1+
ACMakeLists.txt | 50++++++++++++++++++++++++++++++++++++++++++++++++++
ALicense.txt | 120+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
APackage.distribute | 38++++++++++++++++++++++++++++++++++++++
APackage.instrument | 108+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
AReadme.md | 18++++++++++++++++++
Acmake/FindAkAutobahn.cmake | 32++++++++++++++++++++++++++++++++
Acmake/FindRapidJSON.cmake | 4++++
Acmake/FindReaper.cmake | 4++++
Acmake/FindSwell.cmake | 21+++++++++++++++++++++
Acmake/FindWwise.cmake | 4++++
Acmake/Helpers.cmake | 11+++++++++++
Asrc/extension/CMakeLists.txt | 91+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/extension/Extension.cpp | 767+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/extension/ExtensionWindow.cpp | 50++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/extension/ExtensionWindow.h | 20++++++++++++++++++++
Asrc/extension/ReaperContext.cpp | 347+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/extension/ReaperContext.h | 62++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/shared/CMakeLists.txt | 84+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/shared/Core/AssertHook.cpp | 20++++++++++++++++++++
Asrc/shared/Core/DawContext.h | 21+++++++++++++++++++++
Asrc/shared/Core/DawWatcher.cpp | 245+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/shared/Core/DawWatcher.h | 53+++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/shared/Core/ImportTask.h | 212+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/shared/Core/Logger.cpp | 41+++++++++++++++++++++++++++++++++++++++++
Asrc/shared/Core/Logger.h | 29+++++++++++++++++++++++++++++
Asrc/shared/Core/WaapiClient.cpp | 950+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/shared/Core/WaapiClient.h | 224+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/shared/Helpers/ImportHelper.h | 221+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/shared/Helpers/PersistanceHelper.h | 57+++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/shared/Helpers/WaapiHelper.h | 38++++++++++++++++++++++++++++++++++++++
Asrc/shared/Helpers/WwiseHelper.h | 265+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/shared/Model/IDs.h | 78++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/shared/Model/Import.h | 242+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/shared/Model/Waapi.h | 70++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/shared/Model/Wwise.h | 98+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/shared/Persistance/ApplicationProperties.cpp | 117+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/shared/Persistance/ApplicationProperties.h | 25+++++++++++++++++++++++++
Asrc/shared/Persistance/ApplicationState.h | 77+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/shared/Persistance/ApplicationStateValidator.cpp | 203+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/shared/Persistance/ApplicationStateValidator.h | 31+++++++++++++++++++++++++++++++
Asrc/shared/Persistance/FeatureSupport.cpp | 51+++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/shared/Persistance/FeatureSupport.h | 42++++++++++++++++++++++++++++++++++++++++++
Asrc/shared/Persistance/PersistanceSupport.cpp | 151++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/shared/Persistance/PersistanceSupport.h | 29+++++++++++++++++++++++++++++
Asrc/shared/Persistance/WwiseProjectSupport.cpp | 172+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/shared/Persistance/WwiseProjectSupport.h | 40++++++++++++++++++++++++++++++++++++++++
Asrc/shared/Theme/CustomLookAndFeel.cpp | 305++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/shared/Theme/CustomLookAndFeel.h | 66++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/shared/Theme/Fonts/open_sans.ttf | 0
Asrc/shared/Theme/Fonts/open_sans_bold.ttf | 0
Asrc/shared/Theme/Icons/Dialog_Help_Active.png | 0
Asrc/shared/Theme/Icons/General_Browse_Normal.svg | 15+++++++++++++++
Asrc/shared/Theme/Icons/General_FolderWithTriangle_Normal.svg | 22++++++++++++++++++++++
Asrc/shared/Theme/Icons/General_GetFromWwise_Normal.svg | 24++++++++++++++++++++++++
Asrc/shared/Theme/Icons/General_ListMoveDown_Normal.svg | 41+++++++++++++++++++++++++++++++++++++++++
Asrc/shared/Theme/Icons/General_ListMoveUp_Normal.svg | 41+++++++++++++++++++++++++++++++++++++++++
Asrc/shared/Theme/Icons/General_SmallAdd_Normal.svg | 21+++++++++++++++++++++
Asrc/shared/Theme/Icons/General_SmallDelete_Normal.svg | 15+++++++++++++++
Asrc/shared/Theme/Icons/ObjectIcons_AudioObjectSound_nor.svg | 2++
Asrc/shared/Theme/Icons/ObjectIcons_AudioObjectUnknown_nor.svg | 2++
Asrc/shared/Theme/Icons/ObjectIcons_BlendContainer_nor.svg | 29+++++++++++++++++++++++++++++
Asrc/shared/Theme/Icons/ObjectIcons_Folder_nor.svg | 23+++++++++++++++++++++++
Asrc/shared/Theme/Icons/ObjectIcons_PhysicalFolder_nor.svg | 21+++++++++++++++++++++
Asrc/shared/Theme/Icons/ObjectIcons_RandomContainer_nor.svg | 41+++++++++++++++++++++++++++++++++++++++++
Asrc/shared/Theme/Icons/ObjectIcons_SequenceContainer_nor.svg | 27+++++++++++++++++++++++++++
Asrc/shared/Theme/Icons/ObjectIcons_SoundFX_nor.svg | 20++++++++++++++++++++
Asrc/shared/Theme/Icons/ObjectIcons_SoundVoice_nor.svg | 38++++++++++++++++++++++++++++++++++++++
Asrc/shared/Theme/Icons/ObjectIcons_SwitchContainer_nor.svg | 34++++++++++++++++++++++++++++++++++
Asrc/shared/Theme/Icons/ObjectIcons_Workunit_nor.svg | 18++++++++++++++++++
Asrc/shared/Theme/Icons/wwise_icon.svg | 10++++++++++
Asrc/shared/UI/AboutComponent.cpp | 111+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/shared/UI/AboutComponent.h | 32++++++++++++++++++++++++++++++++
Asrc/shared/UI/CustomDrawableButton.cpp | 21+++++++++++++++++++++
Asrc/shared/UI/CustomDrawableButton.h | 18++++++++++++++++++
Asrc/shared/UI/HierarchyMappingControls.cpp | 121+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/shared/UI/HierarchyMappingControls.h | 43+++++++++++++++++++++++++++++++++++++++++++
Asrc/shared/UI/HierarchyMappingTable.cpp | 230+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/shared/UI/HierarchyMappingTable.h | 52++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/shared/UI/ImportComponent.cpp | 52++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/shared/UI/ImportComponent.h | 33+++++++++++++++++++++++++++++++++
Asrc/shared/UI/ImportConflictsComponent.cpp | 116+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/shared/UI/ImportConflictsComponent.h | 44++++++++++++++++++++++++++++++++++++++++++++
Asrc/shared/UI/ImportControlsComponent.cpp | 297+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/shared/UI/ImportControlsComponent.h | 64++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/shared/UI/ImportDestinationComponent.cpp | 105+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/shared/UI/ImportDestinationComponent.h | 41+++++++++++++++++++++++++++++++++++++++++
Asrc/shared/UI/ImportPreviewComponent.cpp | 356+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/shared/UI/ImportPreviewComponent.h | 92+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/shared/UI/LoadingComponent.cpp | 47+++++++++++++++++++++++++++++++++++++++++++++++
Asrc/shared/UI/LoadingComponent.h | 22++++++++++++++++++++++
Asrc/shared/UI/MainComponent.cpp | 145+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/shared/UI/MainComponent.h | 73+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/shared/UI/OriginalsSubfolderComponent.cpp | 173+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/shared/UI/OriginalsSubfolderComponent.h | 53+++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/shared/UI/OutputLogComponent.cpp | 25+++++++++++++++++++++++++
Asrc/shared/UI/OutputLogComponent.h | 22++++++++++++++++++++++
Asrc/shared/UI/PresetMenuComponent.cpp | 124+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/shared/UI/PresetMenuComponent.h | 31+++++++++++++++++++++++++++++++
Asrc/shared/UI/SelectedRowPropertiesComponent.cpp | 333+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/shared/UI/SelectedRowPropertiesComponent.h | 74++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/shared/UI/SimpleListBox.cpp | 66++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/shared/UI/SimpleListBox.h | 41+++++++++++++++++++++++++++++++++++++++++
Asrc/shared/UI/Splitter.cpp | 33+++++++++++++++++++++++++++++++++
Asrc/shared/UI/Splitter.h | 17+++++++++++++++++
Asrc/shared/UI/TruncatableTextEditor.cpp | 60++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/shared/UI/TruncatableTextEditor.h | 26++++++++++++++++++++++++++
Asrc/shared/UI/ValidatableTextEditor.cpp | 69+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/shared/UI/ValidatableTextEditor.h | 32++++++++++++++++++++++++++++++++
Asrc/shared/UI/WildcardSelector.cpp | 70++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/shared/UI/WildcardSelector.h | 21+++++++++++++++++++++
Asrc/standalone/CMakeLists.txt | 25+++++++++++++++++++++++++
Asrc/standalone/Standalone.cpp | 34++++++++++++++++++++++++++++++++++
Asrc/standalone/Standalone.h | 22++++++++++++++++++++++
Asrc/standalone/StandaloneWindow.cpp | 43+++++++++++++++++++++++++++++++++++++++++++
Asrc/standalone/StandaloneWindow.h | 21+++++++++++++++++++++
Asrc/standalone/StubContext.cpp | 0
Asrc/standalone/StubContext.h | 38++++++++++++++++++++++++++++++++++++++
Asrc/test/CMakeLists.txt | 24++++++++++++++++++++++++
Asrc/test/ImportHelperTest.cpp | 216+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/test/ImportHelperTest.h | 186+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/test/Mock.cpp | 29+++++++++++++++++++++++++++++
Asrc/test/PersistanceHelperTest.cpp | 86+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/test/PersistanceHelperTest.h | 109+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/test/Test.cpp | 153+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/test/WwiseHelperTests.cpp | 274+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/test/WwiseHelperTests.h | 42++++++++++++++++++++++++++++++++++++++++++
139 files changed, 22212 insertions(+), 0 deletions(-)

diff --git a/.clang-format b/.clang-format @@ -0,0 +1,25 @@ +# Format Style Options - Created with Clang Power Tools +--- +BasedOnStyle: Microsoft +AccessModifierOffset: -4 +AlignAfterOpenBracket: DontAlign +AllowShortLambdasOnASingleLine: None +AlwaysBreakTemplateDeclarations: Yes +BinPackParameters: true +BreakBeforeBraces: Allman +BreakInheritanceList: BeforeComma +BreakConstructorInitializers: BeforeComma +ColumnLimit: 0 +EmptyLineBeforeAccessModifier: Always +FixNamespaceComments: true +IncludeBlocks: Regroup +IndentCaseLabels: false +KeepEmptyLinesAtTheStartOfBlocks: false +NamespaceIndentation: All +PointerAlignment: Left +ReferenceAlignment: Left +SpacesInAngles: Never +UseTab: AlignWithSpaces +UseCRLF: true +SpaceBeforeParens: Never +... diff --git a/.gitconfig b/.gitconfig @@ -0,0 +1,4 @@ +[gitreview] + remote = origin # Only use origin as remote, eliminates need for remote 'gerrit' + track = true # Uses the upstream branch tracked as target for the review + rebase = false # No rebase by default, you can still rebase manually on review with -r +\ No newline at end of file diff --git a/.gitignore b/.gitignore @@ -0,0 +1,4 @@ +build/ +.vs/ +.vscode/ +3rd/AkAutobahn/AkAutobahn diff --git a/.gitmodules b/.gitmodules @@ -0,0 +1,15 @@ +[submodule "3rd/JUCE"] + path = 3rd/JUCE + url = https://github.com/juce-framework/JUCE.git +[submodule "3rd/rapidjson"] + path = 3rd/rapidjson + url = https://github.com/Tencent/rapidjson.git +[submodule "3rd/WDL"] + path = 3rd/WDL + url = https://github.com/justinfrankel/WDL.git +[submodule "3rd/Catch2"] + path = 3rd/Catch2 + url = https://github.com/catchorg/Catch2.git +[submodule "3rd/trompeloeil"] + path = 3rd/trompeloeil + url = https://github.com/rollbear/trompeloeil.git +\ No newline at end of file diff --git a/3rd/Catch2 b/3rd/Catch2 @@ -0,0 +1 @@ +Subproject commit 47d56f28a9801911c048d011b375e5631dbb658f diff --git a/3rd/JUCE b/3rd/JUCE @@ -0,0 +1 @@ +Subproject commit 2f980209cc4091a4490bb1bafc5d530f16834e58 diff --git a/3rd/WDL b/3rd/WDL @@ -0,0 +1 @@ +Subproject commit 60a3c3d882c1d3a3f9f041b9708b4246f6294e65 diff --git a/3rd/rapidjson b/3rd/rapidjson @@ -0,0 +1 @@ +Subproject commit fd3dc29a5c2852df569e1ea81dbde2c412ac5051 diff --git a/3rd/reaper-sdk/README b/3rd/reaper-sdk/README @@ -0,0 +1,18 @@ +This is the REAPER C/C++ extension plug-in mini-SDK + +Paths: + +sdk/ -- contains headers to use +reaper-plugins/ -- contains source to some plug-ins which are included with REAPER + (these are not to be used as models for well-designed plug-ins, + but they may be useful and/or available for LGPL compliance ;) + +Paths that should be added in order to compile: + +WDL/ + +To compile most of this, merge or symlink in WDL: + +git remote add wdl https://github.com/justinfrankel/WDL.git +git fetch --all +git merge --allow-unrelated-histories wdl/master diff --git a/3rd/reaper-sdk/sdk/LICENSE b/3rd/reaper-sdk/sdk/LICENSE @@ -0,0 +1,15 @@ +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. diff --git a/3rd/reaper-sdk/sdk/reaper_plugin.h b/3rd/reaper-sdk/sdk/reaper_plugin.h @@ -0,0 +1,1395 @@ +/*************************************** +*** REAPER Plug-in API +** +** Copyright (C) 2006-2015, Cockos Incorporated +** +** This software is provided 'as-is', without any express or implied +** warranty. In no event will the authors be held liable for any damages +** arising from the use of this software. +** +** Permission is granted to anyone to use this software for any purpose, +** including commercial applications, and to alter it and redistribute it +** freely, subject to the following restrictions: +** +** 1. The origin of this software must not be misrepresented; you must not +** claim that you wrote the original software. If you use this software +** in a product, an acknowledgment in the product documentation would be +** appreciated but is not required. +** 2. Altered source versions must be plainly marked as such, and must not be +** misrepresented as being the original software. +** 3. This notice may not be removed or altered from any source distribution. +** +** Notes: the C++ interfaces used require MSVC on win32, or at least the MSVC-compatible C++ ABI. Sorry, mingw users :( +** +*/ + +#ifndef _REAPER_PLUGIN_H_ +#define _REAPER_PLUGIN_H_ + + +#ifndef REASAMPLE_SIZE +#define REASAMPLE_SIZE 8 // if we change this it will break everything! +#endif + +#if REASAMPLE_SIZE == 4 +typedef float ReaSample; +#else +typedef double ReaSample; +#endif + + + +#ifdef _WIN32 +#include <windows.h> + +#define REAPER_PLUGIN_DLL_EXPORT __declspec(dllexport) +#define REAPER_PLUGIN_HINSTANCE HINSTANCE + +#else +#include "../WDL/swell/swell.h" +#include <pthread.h> + +#define REAPER_PLUGIN_DLL_EXPORT __attribute__((visibility("default"))) +#define REAPER_PLUGIN_HINSTANCE void * +#endif + +#define REAPER_PLUGIN_ENTRYPOINT ReaperPluginEntry +#define REAPER_PLUGIN_ENTRYPOINT_NAME "ReaperPluginEntry" + +#ifdef _MSC_VER +#define INT64 __int64 +#define INT64_CONSTANT(x) (x##i64) +#else +#define INT64 long long +#define INT64_CONSTANT(x) (x##LL) +#endif + +#ifdef __GNUC__ + #define REAPER_STATICFUNC __attribute__((unused)) static +#else + #define REAPER_STATICFUNC static +#endif + +/* +** Endian-tools and defines (currently only __ppc__ and BIG_ENDIAN is recognized, for OS X -- all other platforms are assumed to be LE) +*/ + +REAPER_STATICFUNC int REAPER_BSWAPINT(int x) +{ + return ((((x))&0xff)<<24)|((((x))&0xff00)<<8)|((((x))&0xff0000)>>8)|(((x)>>24)&0xff); +} +REAPER_STATICFUNC void REAPER_BSWAPINTMEM(void *buf) +{ + char p[4],tmp; + memcpy(p,buf,4); + tmp=p[0]; p[0]=p[3]; p[3]=tmp; + tmp=p[1]; p[1]=p[2]; p[2]=tmp; + memcpy(buf,p,4); +} +REAPER_STATICFUNC void REAPER_BSWAPINTMEM8(void *buf) +{ + char p[8],tmp; + memcpy(p,buf,8); + tmp=p[0]; p[0]=p[7]; p[7]=tmp; + tmp=p[1]; p[1]=p[6]; p[6]=tmp; + tmp=p[2]; p[2]=p[5]; p[5]=tmp; + tmp=p[3]; p[3]=p[4]; p[4]=tmp; + memcpy(buf,p,8); +} + +#if defined(__ppc__) + +#define REAPER_BIG_ENDIAN +#define REAPER_FOURCC(d,c,b,a) (((unsigned int)(d)&0xff)|(((unsigned int)(c)&0xff)<<8)|(((unsigned int)(b)&0xff)<<16)|(((unsigned int)(a)&0xff)<<24)) + +#define REAPER_MAKEBEINT(x) (x) +#define REAPER_MAKEBEINTMEM(x) +#define REAPER_MAKEBEINTMEM8(x) +#define REAPER_MAKELEINT(x) REAPER_BSWAPINT(x) +#define REAPER_MAKELEINTMEM(x) REAPER_BSWAPINTMEM(x) +#define REAPER_MAKELEINTMEM8(x) REAPER_BSWAPINTMEM8(x) + +#else + +#define REAPER_FOURCC(a,b,c,d) (((unsigned int)(d)&0xff)|(((unsigned int)(c)&0xff)<<8)|(((unsigned int)(b)&0xff)<<16)|(((unsigned int)(a)&0xff)<<24)) + +#define REAPER_MAKELEINT(x) (x) +#define REAPER_MAKELEINTMEM(x) +#define REAPER_MAKELEINTMEM8(x) +#define REAPER_MAKEBEINT(x) REAPER_BSWAPINT(x) +#define REAPER_MAKEBEINTMEM(x) REAPER_BSWAPINTMEM(x) +#define REAPER_MAKEBEINTMEM8(x) REAPER_BSWAPINTMEM8(x) + +#endif + + +#if 1 +#define ADVANCE_TIME_BY_SAMPLES(t, spls, srate) ((t) += (spls)/(double)(srate)) // not completely accurate but still quite accurate. +#else +#define ADVANCE_TIME_BY_SAMPLES(t, spls, srate) ((t) = floor((t) * (srate) + spls + 0.5)/(double)(srate)) // good forever? may have other issues though if srate changes. disabled for now +#endif + + + +// int ReaperPluginEntry(HINSTANCE hInstance, reaper_plugin_info_t *rec); +// return 1 if you are compatible (anything else will result in plugin being unloaded) +// if rec == NULL, then time to unload + +#define REAPER_PLUGIN_VERSION 0x20E + +typedef struct reaper_plugin_info_t +{ + int caller_version; // REAPER_PLUGIN_VERSION + + HWND hwnd_main; + + /* + Register() is the API that plug-ins register most things, be it keyboard shortcuts, project importers, etc. + Register() is also available by using GetFunc("plugin_register") + + extensions typically register things on load of the DLL, for example: + + static pcmsink_register_t myreg={ ... }; + rec->Register("pcmsink",&myreg); + + on plug-in unload (or if the extension wishes to remove it for some reason): + rec->Register("-pcmsink",&myreg); + + the "-" prefix is supported for most registration types. + some types support the < prefix to register at the start of the list + + Registration types: + + API_*: + if you have a function called myfunction(..) that you want to expose to other extensions, use: + rec->Register("API_myfunction",funcaddress); + other extensions then use GetFunc("myfunction") to get the function pointer. + + APIdef_*: + To make a function registered with API_* available via ReaScript, follow the API_ registration with: + double myfunction(char* str, int flag); + const char *defstring = "double\0char*,int\0str,flag\0help text for myfunction" + rec->Register("APIdef_myfunction",(void*)defstring); + defstring is four null-separated fields: return type, argument types, argument names, and help. + + APIvararg_*: + Used to set the reascript vararg function pointer for an API_. todo document + + hookcommand: + Registers a hook which runs prior to every action in the main section: + bool runCommand(int command, int flag); + rec->Register("hookcommand",runCommand); + runCommand() should return true if it processed the command (prevent further hooks or the action from running) + It is OK to call Main_OnCommand() from runCommand(), but it must check for and handle any recursion. + + hookpostcommand: + Registers a hook which runs after each action in the main section: + void postCommand(int command, int flag); + rec->Register("hookpostcommand",postCommand); + + hookcommand2: + Registers a hook which runs prior to every action triggered by a key/MIDI event: + bool onAction(KbdSectionInfo *sec, int command, int val, int val2, int relmode, HWND hwnd); + rec->Register("hookcommand2",hook); \ + onAction returns true if it processed the command (preventing further hooks or actions from running) + val/val2 are used for actions triggered by MIDI/OSC/mousewheel + - val = [0..127] and val2 = -1 for MIDI CC, + - val2 >=0 for MIDI pitch or OSC with value = (val2|(val<<7))/16383.0 + - relmode absolute(0) or 1/2/3 for relative adjust modes + + hookpostcommand2: + void (*hook)(KbdSectionInfo *section, int actionCommandID, int val, int valhw, int relmode, HWND hwnd, ReaProject *proj); + rec->Register("hookpostcommand2",hook); + + command_id: + Registers/looks up a command ID for an action. Parameter is a unique string with only A-Z, a-z, 0-9. + int command = Register("command_id","MyCommandName"); + returns 0 if unsupported/out of actions + + command_id_lookup: + Like command_id but only looks up, does not create a new command ID. + + pcmsink_ext: + Registers an extended audio sink type: + (pcmsink_register_ext_t *) + + pcmsink: + Registers an audio sink type: + (pcmsink_register_t *) + + pcmsrc: + Registers an audio source: + (pcmsrc_register_t *) + + timer: + Runs a timer periodically: + void (*timer_function)(); + + hwnd_info: (6.29+) + query information about a hwnd + int (*callback)(HWND hwnd, INT_PTR info_type); + + return 0 if hwnd is not a known window, or if info_type is unknown + + info_type: + 0 = query if hwnd should be treated as a text-field for purposes of global hotkeys + return: 1 if text field + return: -1 if not text field + + + file_in_project_ex: + accel_section: + action_help: + custom_action: + gaccel: + hookcustommenu: + prefpage: + projectimport: + projectconfig: + editor: + accelerator: + csurf: + csurf_inst: + toggleaction: + on_update_hooks: + toolbar_icon_map: + open_file_reduce: + + */ + + int (*Register)(const char *name, void *infostruct); // returns 1 if registered successfully + + // get a generic API function, there many of these defined. see reaper_plugin_functions.h + void * (*GetFunc)(const char *name); // returns 0 if function not found + +} reaper_plugin_info_t; + + + + +/**************************************************************************************** +**** interface for plugin objects to save/load state. they should use ../WDL/LineParser.h too... +***************************************************************************************/ + +// ProjectStateContext tempflags meaning for &0xFFFF +enum +{ + PROJSTATECTX_UNDO_REDO=1, + PROJSTATECTX_SAVE_LOAD=2, // project, track template, etc + PROJSTATECTX_CUTCOPY_PASTE=3, +}; +// &0xFFFF0000 is for receiver use + +#ifndef _WDL_PROJECTSTATECONTEXT_DEFINED_ +#define _REAPER_PLUGIN_PROJECTSTATECONTEXT_DEFINED_ +class ProjectStateContext // this is also defined in WDL, need to keep these interfaces identical +{ +public: + virtual ~ProjectStateContext(){}; + +#ifdef __GNUC__ + virtual void __attribute__ ((format (printf,2,3))) AddLine(const char *fmt, ...) = 0; +#else + virtual void AddLine(const char *fmt, ...)=0; +#endif + virtual int GetLine(char *buf, int buflen)=0; // returns -1 on eof + + virtual INT64 GetOutputSize()=0; // output size written so far, only usable on REAPER 3.14+ + + virtual int GetTempFlag()=0; + virtual void SetTempFlag(int flag)=0; +}; +#endif + + + +/*************************************************************************************** +**** MIDI event definition and abstract list +***************************************************************************************/ + +struct MIDI_event_t +{ + int frame_offset; + int size; // bytes used by midi_message, can be >3, but should never be <3, even if a short 1 or 2 byte msg + unsigned char midi_message[4]; // size is number of bytes valid -- can be more than 4! + + // new helpers + bool is_note() const { return (midi_message[0]&0xe0)==0x80; } + bool is_note_on() const { + return (midi_message[0]&0xf0)==0x90 && midi_message[2]; + } + bool is_note_off() const { + switch (midi_message[0]&0xf0) + { + case 0x80: return true; + case 0x90: return midi_message[2]==0; + } + return false; + } + + enum { + CC_ALL_SOUND_OFF=120, + CC_ALL_NOTES_OFF=123, + CC_EOF_INDICATOR = CC_ALL_NOTES_OFF + }; +}; + +class MIDI_eventlist +{ +public: + virtual void AddItem(MIDI_event_t *evt)=0; + virtual MIDI_event_t *EnumItems(int *bpos)=0; + virtual void DeleteItem(int bpos)=0; + virtual int GetSize()=0; // size of block in bytes + virtual void Empty()=0; + +protected: + // this is only defined in REAPER 4.60+, for 4.591 and earlier you should delete only via the implementation pointer + virtual ~MIDI_eventlist() { } +}; + +typedef struct _MIDI_eventprops +{ + double ppqpos; + double ppqpos_end_or_bezier_tension; // only for note events or CC events + char flag; // &1=selected, &2=muted, >>4&0xF=cc shape + unsigned char msg[3]; // msg is not valid if varmsglen > 0 + char* varmsg; + int varmsglen; + int setflag; // &1:selected, &2:muted, &4:ppqpos, &8:endppqpos or bez tension, &16:msg1 high bits, &32:msg1 low bits, &64:msg2, &128:msg3, &256:varmsg, &1024:shape/tension fields used, &16384:no sort after set +} MIDI_eventprops; + + +/*************************************************************************************** +**** PCM source API +***************************************************************************************/ + + + +typedef struct _PCM_source_transfer_t +{ + double time_s; // start time of block + + double samplerate; // desired output samplerate and channels + int nch; + + int length; // desired length in sample(pair)s of output + + ReaSample *samples; // samples filled in (the caller allocates this) + int samples_out; // updated with number of sample(pair)s actually rendered + + MIDI_eventlist *midi_events; + + double approximate_playback_latency; // 0.0 if not supported + double absolute_time_s; + double force_bpm; +} PCM_source_transfer_t; + +class REAPER_PeakGet_Interface; + +typedef struct _PCM_source_peaktransfer_t +{ + double start_time; // start time of block + double peakrate; // peaks per second (see samplerate below) + + int numpeak_points; // desired number of points for data + + int nchpeaks; // number of channels of peaks data requested + + ReaSample *peaks; // peaks output (caller allocated) + int peaks_out; // number of points actually output (less than desired means at end) + + enum + { + PEAKTRANSFER_PEAKS_MODE=0, + PEAKTRANSFER_WAVEFORM_MODE=1, + PEAKTRANSFER_MIDI_NOTE_MODE=2, + PEAKTRANSFER_MIDI_DRUM_MODE=3, + PEAKTRANSFER_MIDI_DRUM_TRIANGLE_MODE=4, + }; + int output_mode; // see enum above + + double absolute_time_s; + + ReaSample *peaks_minvals; // can be NULL, otherwise receives minimum values + int peaks_minvals_used; + + double samplerate; // peakrate is peaks per second, samplerate is used only as a hint for what style of peaks to draw, OK to pass in zero + +#define PEAKINFO_EXTRADATA_SPECTRAL1 ((int)'s') +#define PEAKINFO_EXTRADATA_SPECTROGRAM1 ((int)'g') +#define PEAKINFO_EXTRADATA_MIDITEXT ((int)'m') + int extra_requested_data_type; // PEAKINFO_EXTRADATA_* for spectral information + int extra_requested_data_out; // output: number of samples returned (== peaks_out if successful) + void *extra_requested_data; + + REAPER_PeakGet_Interface *__peakgetter; +#ifdef __LP64__ + int *exp[27]; +#else + int *exp[26]; +#endif + + static inline int extra_blocksize(int extra_requested_data_type) + { + switch (extra_requested_data_type) + { + case PEAKINFO_EXTRADATA_SPECTRAL1: return sizeof(int); // one int per channel per sample spectral info: low 15 bits frequency, next 14 bits density (16383=tonal, 0=noise, 12288 = a bit noisy) + case PEAKINFO_EXTRADATA_SPECTROGRAM1: return SPECTROGRAM1_BLOCKSIZE_BYTES; + case PEAKINFO_EXTRADATA_MIDITEXT: return 1; // at most one character per pixel + } + return 0; + } + enum { SPECTROGRAM1_BLOCKSIZE_BYTES=128 * 3 / 2 }; // 128 bins, 12 bits each (MSB1, (LSN1<<4)|LSN2, MSB2) + +} PCM_source_peaktransfer_t; + + +// used to update MIDI sources with new events during recording +typedef struct +{ + double global_time; + double global_item_time; + double srate; + int length; // length in samples + int overwritemode; // 0=overdub, 1=replace, + // -1 = literal (do nothing just add) + // 65536+(16 bit mask) = replace notes on just these channels (touch-replace) + MIDI_eventlist *events; + double item_playrate; + + double latency; + + unsigned int *overwrite_actives; // [16(note)+16(CC)+16(poly AT)][4]; only used when overwritemode is >0 + // CC: 127=pitch, 126=program, 125=channel pressure + + double do_not_quantize_past_sec; // amount in future that quantizing should never move things past (or 0 for not used) +} midi_realtime_write_struct_t; + + +// abstract base class +class PCM_source +{ + public: + virtual ~PCM_source() { } + + virtual PCM_source *Duplicate()=0; + + virtual bool IsAvailable()=0; + virtual void SetAvailable(bool avail) { } // optional, if called with avail=false, close files/etc, and so on + virtual const char *GetType()=0; + virtual const char *GetFileName() { return NULL; } // return NULL if no filename (not purely a file) + virtual bool SetFileName(const char *newfn)=0; // return TRUE if supported, this will only be called when offline + + virtual PCM_source *GetSource() { return NULL; } + virtual void SetSource(PCM_source *src) { } + virtual int GetNumChannels()=0; // return number of channels + virtual double GetSampleRate()=0; // returns preferred sample rate. if < 1.0 then it is assumed to be silent (or MIDI) + virtual double GetLength()=0; // length in seconds + virtual double GetLengthBeats() { return -1.0; } // length in beats if supported + virtual int GetBitsPerSample() { return 0; } // returns bits/sample, if available. only used for metadata purposes, since everything returns as doubles anyway + virtual double GetPreferredPosition() { return -1.0; } // not supported returns -1 + + virtual int PropertiesWindow(HWND hwndParent)=0; + + virtual void GetSamples(PCM_source_transfer_t *block)=0; + virtual void GetPeakInfo(PCM_source_peaktransfer_t *block)=0; + + virtual void SaveState(ProjectStateContext *ctx)=0; + virtual int LoadState(const char *firstline, ProjectStateContext *ctx)=0; // -1 on error + + + // these are called by the peaks building UI to build peaks for files. + virtual void Peaks_Clear(bool deleteFile)=0; + virtual int PeaksBuild_Begin()=0; // returns nonzero if building is opened, otherwise it may mean building isn't necessary + virtual int PeaksBuild_Run()=0; // returns nonzero if building should continue + virtual void PeaksBuild_Finish()=0; // called when done + + virtual int Extended(int call, void *parm1, void *parm2, void *parm3) { return 0; } // return 0 if unsupported +}; + +typedef struct +{ + int m_id; // ignored for PCM_SINK_EXT_ADDCUE, populated for PCM_SOURCE_EXT_ENUMCUES + double m_time; + double m_endtime; + bool m_isregion; + char *m_name; // can be NULL if unnamed + int m_flags; // &1=DEPRECATED caller must call Extended(PCM_SOURCE_EXT_ENUMCUES, -1, &cue, 0) when finished, &2=time is QN, &0x10000=write cue regardless of sink settings, &4=is chapter + char resvd[124]; // future expansion -- should be 0 +} REAPER_cue; + +typedef struct +{ + PCM_source* m_sliceSrc; + double m_beatSnapOffset; + int flag; // &1=only return beatsnapoffset, not slicesrc + char resvd[124]; // future expansion -- should be 0 +} REAPER_slice; + +typedef struct +{ + double draw_start_time; // project time at pixel start of draw + int draw_start_y; // if y-scroll is partway into the item, positive pixel value + double pixels_per_second; + + int width, height; // width and height of view of the item. if doing a partial update this may be larger than the bitmap passed in + int mouse_x, mouse_y; // valid only on mouse/key/setcursor/etc messages + + void *extraParms[8]; + // WM_KEYDOWN handlers can use MSG *msg = (MSG *)extraParms[0] + // WM_SETCURSOR handlers should set *extraParms[0] = hcursor +} REAPER_inline_positioninfo; + + +typedef struct +{ + double timepos, qnpos, bpm; + int tsnum, tsdenom; + int flag; // &1=linear tempo change, &2=internal use +} REAPER_tempochg; + + +#define PCM_SOURCE_EXT_INLINEEDITOR 0x100 /* parm1 = (void *)(INT_PTR)message, parm2/parm3 = parms + + note: for the WM_* constants, you can use windows.h if on Windows, and SWELL's definitions if on other platforms + note: for LICE_IBitmap interface, you can use LICE's definition + for SWELL and LICE, see Cockos WDL -- https://www.cockos.com/wdl + + NOTE: fx-embed documentation is now in reaper_plugin_fx_embed.h + + messages: + 0 = query if editor is available/supported. returns <0 if supported but unavailable, >0 if available, 0=if not supported + WM_CREATE to create the editor instance + WM_DESTROY to destroy the editor instance (nonzero if success) + + WM_LBUTTON*, WM_RBUTTON*, WM_MOUSEMOVE, WM_MOUSEWHEEL -- parm2=rsvd, parm3= REAPER_inline_positioninfo) + these can return any combination of: + REAPER_INLINE_RETNOTIFY_INVALIDATE + REAPER_INLINE_RETNOTIFY_SETCAPTURE + REAPER_INLINE_RETNOTIFY_SETFOCUS + + WM_KEYDOWN -- parm3=REAPER_inline_positioninfo*, MSG *kbmsg = (MSG *)rec->extraParms[0] + return nonzero to eat the key. can return REAPER_INLINE_RETNOTIFY_INVALIDATE. + + WM_SETCURSOR -- parm3=REAPER_inline_positioninfo* + -- *rec->extraParms[0] = hcursor + + paint messages: parm2 = LICE_IBitmap *, parm3 = (REAPER_inline_positioninfo*). + WM_ERASEBKGND -- draw first pass -- should return 1 if supported + WM_PAINT -- draw second pass -- should return 1 if paint supported + WM_NCPAINT -- draw third pass + + Notes on Retina/HiDPI: + on macOS retina, (int)LICE_IBitmap::Extended(LICE_EXT_GET_SCALING,NULL) may return 512. in this case LICE will internally render things double-sized + on other platforms HiDPI, if (int)LICE_IBitmap::Extended(LICE_EXT_GET_ADVISORY_SCALING,NULL) returns nonzero, then it is a 24.8 scale factor which things + should be scaled by. + + */ + +#define REAPER_INLINE_RETNOTIFY_INVALIDATE 0x1000000 // want refresh of display +#define REAPER_INLINE_RETNOTIFY_SETCAPTURE 0x2000000 // setcapture +#define REAPER_INLINE_RETNOTIFY_SETFOCUS 0x4000000 // set focus to item +#define REAPER_INLINE_RETNOTIFY_NOAUTOSCROLL 0x8000000 // modifier only valid when setcapture set + +#define REAPER_INLINEFLAG_SHOWALLTAKES 0x1000 // only valid as a return value flag for message=0, display in inactive take lanes +#define REAPER_INLINEFLAG_WANTOVERLAYEDCONTROLS 0x4000 // only valid as a return value flag for message=0, to have fades/etc still drawn over like normal + + + + + +#define PCM_SOURCE_EXT_PROJCHANGENOTIFY 0x2000 // parm1 = nonzero if activated project, zero if deactivated project + +#define PCM_SOURCE_EXT_OPENEDITOR 0x10001 // parm1=hwnd, implementation dependent parm2/parm3 +#define PCM_SOURCE_EXT_GETEDITORSTRING 0x10002 // parm1=index (0 or 1), parm2=(const char**)desc, optional parm3=(int*)has_had_editor +#define PCM_SOURCE_EXT_DEPRECATED_1 0x10003 // was PCM_SOURCE_EXT_CLOSESECONDARYSRC +#define PCM_SOURCE_EXT_SETITEMCONTEXT 0x10004 // parm1=MediaItem*, parm2=MediaItem_Take* +#define PCM_SOURCE_EXT_ADDMIDIEVENTS 0x10005 // parm1=pointer to midi_realtime_write_struct_t, nch=1 for replace, =0 for overdub, parm2=midi_quantize_mode_t* (optional) +#define PCM_SOURCE_EXT_GETASSOCIATED_RPP 0x10006 // parm1=pointer to char* that will receive a pointer to the string +#define PCM_SOURCE_EXT_GETMETADATA 0x10007 // parm1=pointer to name string, parm2=pointer to buffer, parm3=(int)buffersizemax. returns length used. defined strings are "TITLE", "ARTIST", "ALBUM", "YEAR", "GENRE", "COMMENT", "DESC", "BPM", "KEY", "DB_CUSTOM" +#define PCM_SOURCE_EXT_SETASSECONDARYSOURCE 0x10008 // parm1=optional pointer to src (same subtype as receiver), if supplied, set the receiver as secondary src for parm1's editor, if not supplied, receiver has to figure out if there is an appropriate editor open to attach to, parm2/3 impl defined +#define PCM_SOURCE_EXT_SHOWMIDIPREVIEW 0x10009 // parm1=(MIDI_eventlist*), can be NULL for all-notes-off (also to check if this source supports showing preview at this moment) +#define PCM_SOURCE_EXT_SEND_EDITOR_MSG 0x1000A // impl defined parameters +#define PCM_SOURCE_EXT_SETSECONDARYSOURCELIST 0x1000B // parm1=(PCM_source**)sourcelist, parm2=list size, parm3=close any existing src not in the list +#define PCM_SOURCE_EXT_ISOPENEDITOR 0x1000C // returns 1 if this source is currently open in an editor, 2 if open in a secondary editor. parm1=1 to close. parm2=(int*)&flags to get extra flags (&1=editor is currently hidden) +#define PCM_SOURCE_EXT_SETEDITORGRID 0x1000D // parm1=(double*)griddiv: 0.25=quarter note, 1.0/3.0=half note triplet, etc. parm2=int* swingmode(1=swing), parm3=double*swingamt +#define PCM_SOURCE_EXT_GETITEMCONTEXT 0x10010 // parm1=MediaItem**, parm2=MediaItem_Take**, parm3=MediaTrack** +#define PCM_SOURCE_EXT_GETALLMETADATA_DEPRECATED 0x10011 // no longer supported +#define PCM_SOURCE_EXT_GETBITRATE 0x10012 // parm1=(double*)bitrate, if different from samplerate*channels*bitdepth/length +#define PCM_SOURCE_EXT_ENUMMETADATA 0x10013 // parm1=(int)index, parm2=(const char**)key, parm3=(const char**)value. enumerates all metadata, returns 0 when no more metadata exists +#define PCM_SOURCE_EXT_GETINFOSTRING 0x10014 // parm1=(char*)buffer, parm2=(int)buffer length, return the data that would be displayed in the properties window +#define PCM_SOURCE_EXT_CONFIGISFILENAME 0x20000 +#define PCM_SOURCE_EXT_WRITEMETADATA_DEPRECATED 0x20007 // no longer supported +#define PCM_SOURCE_EXT_WRITE_METADATA 0x20008 // parm1=char* new file name, parm2=(char**)NULL-terminated array of key,value,key2,value2,... pointers, parm3=flags (&1=merge, &2=do not allow update in-place). returns 1 if successfully generated a new file, 2 if original file was updated +#define PCM_SOURCE_EXT_GETBPMANDINFO 0x40000 // parm1=pointer to double for bpm. parm2=pointer to double for snap/downbeat offset (seconds). +#define PCM_SOURCE_EXT_GETNTRACKS 0x80000 // for midi data, returns number of tracks that would have been available +#define PCM_SOURCE_EXT_GETTITLE 0x80001 // parm1=(char**)title (string persists in plugin) +#define PCM_SOURCE_EXT_ENUMTEMPOMAP 0x80002 // parm1=index, parm2=pointer to REAPER_tempochg, returns 0 if no tempo map or enumeration complete +#define PCM_SOURCE_EXT_WANTOLDBEATSTYLE 0x80003 +#define PCM_SOURCE_EXT_GETNOTATIONSETTINGS 0x80004 // parm1=(int)what, (what==0) => parm2=(double*)keysigmap, parm3=(int*)keysigmapsize; (what==1) => parm2=(int*)display transpose semitones, (what==2) => parm2=(char*)clef1, parm3=(char*)clef2 +#define PCM_SOURCE_EXT_WANT_TRIM 0x90001 // parm1=(int64*)total number of decoded samples after trimming, parm2=(int*)number of samples to trim from start, parm3=(int*)number of samples to trim from end +#define PCM_SOURCE_EXT_WANTTRIM_DEPRECATED 0x90002 // no longer supported +#define PCM_SOURCE_EXT_TRIMITEM 0x90003 // parm1=lrflag, parm2=double *{position,length,startoffs,rate} +#define PCM_SOURCE_EXT_EXPORTTOFILE 0x90004 // parm1=output filename, only currently supported by MIDI but in theory any source could support this +#define PCM_SOURCE_EXT_ENUMCUES 0x90005 // DEPRECATED, use PCM_SOURCE_EXT_ENUMCUES_EX instead. parm1=(int) index of cue to get (-1 to free cue), parm2=(optional)REAPER_cue **. Returns 0 and sets parm2 to NULL when out of cues. return value otherwise is how much to advance parm2 (1, or 2 usually) +#define PCM_SOURCE_EXT_ENUMCUES_EX 0x90016 // parm1=(int) index of cue (source must provide persistent backing store for cue->m_name), parm2=(REAPER_cue*) optional. Returns 0 when out of cues, otherwise returns how much to advance index (1 or 2 usually). +// a PCM_source may be the parent of a number of beat-based slices, if so the parent should report length and nchannels only, handle ENUMSLICES, and be deleted after the slices are retrieved +#define PCM_SOURCE_EXT_ENUMSLICES 0x90006 // parm1=(int*) index of slice to get, parm2=REAPER_slice* (pointing to caller's existing slice struct), parm3=(double*)bpm. if parm2 passed in zero, returns the number of slices. returns 0 if no slices or out of slices. +#define PCM_SOURCE_EXT_ENDPLAYNOTIFY 0x90007 // notify a source that it can release any pooled resources +#define PCM_SOURCE_EXT_SETPREVIEWTEMPO 0x90008 // parm1=(double*)bpm, only meaningful for MIDI or slice-based source media + +enum { RAWMIDI_NOTESONLY=1, RAWMIDI_UNFILTERED=2 }; +#define PCM_SOURCE_EXT_GETRAWMIDIEVENTS 0x90009 // parm1 = (PCM_source_transfer_t *), parm2 = RAWMIDI flags + +#define PCM_SOURCE_EXT_SETRESAMPLEMODE 0x9000A // parm1= mode to pass to resampler->Extended(RESAMPLE_EXT_SETRSMODE,mode,0,0) +#define PCM_SOURCE_EXT_NOTIFYPREVIEWPLAYPOS 0x9000B // parm1 = ptr to double of play position, or NULL if stopped +#define PCM_SOURCE_EXT_SETSIZE 0x9000C // parm1=(double*)startpos, parm2=(double*)endpos, parm3=flags. Start can be negative. Receiver may adjust start/end to avoid erasing content, in which case the adjusted values are returned in parm1 and parm2. parm3/flags: 1 if start/end in QN (always the case now). 2=resize even pooled items +#define PCM_SOURCE_EXT_GETSOURCETEMPO 0x9000D // parm1=(double*)bpm, parm2=(int*)timesig_numerator<<8|timesig_denominator, parm3=(double*)current preview tempo if applicable. this is for reporting purposes only, does not necessarily mean the media should be adjusted (as PCM_SOURCE_EXT_GETBPMANDINFO means) +#define PCM_SOURCE_EXT_ISABNORMALAUDIO 0x9000E // return 1 if rex, video, etc (meaning file export will just copy file directly rather than trim/converting) +#define PCM_SOURCE_EXT_GETPOOLEDMIDIID 0x9000F // parm1=(char*)id, parm2=(int*)pool user count, parm3=(MediaItem_Take**)firstuser +#define PCM_SOURCE_EXT_REMOVEFROMMIDIPOOL 0x90010 +#define PCM_SOURCE_EXT_GETHASH 0x90011 // parm1=(WDL_UINT64*)hash (64-bit hash of the source data) +#define PCM_SOURCE_EXT_GETIMAGE 0x90012 // parm1=(LICE_IBitmap**)image. parm2 = NULL or pointer to int, which is (w<<16)|h desired approx +#define PCM_SOURCE_EXT_NOAUDIO 0x90013 +#define PCM_SOURCE_EXT_HASMIDI 0x90014 // returns 1 if contains any MIDI data, parm1=(double*)time offset of first event +#define PCM_SOURCE_EXT_DELETEMIDINOTES 0x90015 // parm1=(double*)minlen (0.125 for 1/8 notes, etc), parm2=1 if only trailing small notes should be deleted, parm3=(bool*)true if any notes were deleted (return) +#define PCM_SOURCE_EXT_GETGUID 0x90017 // parm1=(GUID*)guid +#define PCM_SOURCE_EXT_DOPASTEINITEM 0x90100 // no parms used, acts as a paste from clipboard +#define PCM_SOURCE_EXT_GETNOTERANGE 0x90018 // parm1=(int*)low note, parm2=(int*)high note +#define PCM_SOURCE_EXT_PPQCONVERT 0x90020 // parm1=(double*)pos, parm2=(int)flag 0=ppq to proj time, 1=proj time to ppq +#define PCM_SOURCE_EXT_COUNTMIDIEVTS 0x90021 // parm1=(int*)notecnt, parm2=(int*)ccevtcnt, parm3=(int*)metaevtcnt +#define PCM_SOURCE_EXT_GETSETMIDIEVT 0x90022 // parm1=(MIDI_eventprops*)event properties (NULL to delete); parm2=(int)event index (<0 to insert); parm2=(int)flag: 1=index counts notes only, 2=index counts CC only, 3=index counts meta-events only +#define PCM_SOURCE_EXT_GETSUGGESTEDTEXT 0x90023 // parm1=char ** which will receive pointer to suggested label text, if any +#define PCM_SOURCE_EXT_GETSCALE 0x90024 // parm1=unsigned int: &0xF=pitch (0=C), &0x10=root, &0x20=min2, &0x40=maj2, &0x80=min3, &0xF0=maj3, &0x100=4, etc) ; parm2=(char*)name (optional), parm3=int size of name buffer +#define PCM_SOURCE_EXT_SELECTCONTENT 0x90025 // parm1=1 to select, 0 to deselect +#define PCM_SOURCE_EXT_GETGRIDINFO 0x90026 // parm1=(double*)snap grid size, parm2=(double*)swing strength, parm3=(double*)note insert length, -1 if follows grid size +#define PCM_SOURCE_EXT_SORTMIDIEVTS 0x9027 +#define PCM_SOURCE_EXT_MIDI_COMPACTPHRASES 0x90028 // compact the notation phrase ID space +#define PCM_SOURCE_EXT_GETSETALLMIDI 0x90029 // parm1=(unsigned char*)data buffer, parm2=(int*)buffer length in bytes, parm2=(1:set, 0:get). Buffer is a list of { int offset, char flag, int msglen, unsigned char msg[] }. offset: MIDI ticks from previous event, flag: &1=selected &2=muted, msglen: byte length of msg (usually 3), msg: the MIDI message. +#define PCM_SOURCE_EXT_DISABLESORTMIDIEVTS 0x90030 // disable sorting for PCM_SOURCE_EXT_GETSETMIDIEVT until PCM_SOURCE_EXT_SORTMIDIEVTS is called +#define PCM_SOURCE_EXT_GETLAPPING 0xC0100 // parm1 = ReaSample buffer, parm2=(INT_PTR)maxlap, returns size of lapping returned. usually not supported. special purpose. + +// register with Register("pcmsrc",&struct ... and unregister with "-pcmsrc" +typedef struct { + PCM_source *(*CreateFromType)(const char *type, int priority); // priority is 0-7, 0 is highest + PCM_source *(*CreateFromFile)(const char *filename, int priority); // if priority is 5-7, and the file isn't found, open it in an offline state anyway, thanks + + // this is used for UI only, not so muc + const char *(*EnumFileExtensions)(int i, const char **descptr); // call increasing i until returns a string, if descptr's output is NULL, use last description +} pcmsrc_register_t; + + +/* +** OK so the pcm source class has a lot of responsibility, and people may not wish to +** have to implement them. So, for basic audio decoders, you can use this class instead: +** +** And you can use the PCM_Source_CreateFromSimple API to create a PCM_source from your ISimpleMediaDecoder derived class +*/ +class ISimpleMediaDecoder +{ +public: + virtual ~ISimpleMediaDecoder() { } + + virtual ISimpleMediaDecoder *Duplicate()=0; + + // filename can be NULL to use "last filename" + // diskread* are suggested values to pass to WDL_FileRead if you use it, otherwise can ignore + virtual void Open(const char *filename, int diskreadmode, int diskreadbs, int diskreadnb)=0; + + // if fullClose=0, close disk resources, but can leave decoders etc initialized (and subsequently check the file date on re-open) + virtual void Close(bool fullClose)=0; + + virtual const char *GetFileName()=0; + virtual const char *GetType()=0; + + // an info string suitable for a dialog, and a title for that dialog + virtual void GetInfoString(char *buf, int buflen, char *title, int titlelen)=0; + + virtual bool IsOpen()=0; + virtual int GetNumChannels()=0; + + virtual int GetBitsPerSample()=0; + virtual double GetSampleRate()=0; + + + // positions in sample frames + virtual INT64 GetLength()=0; + virtual INT64 GetPosition()=0; + virtual void SetPosition(INT64 pos)=0; + + // returns sample-frames read. buf will be at least length*GetNumChannels() ReaSamples long. + virtual int ReadSamples(ReaSample *buf, int length)=0; + + + // these extended messages may include PCM_source messages + virtual int Extended(int call, void *parm1, void *parm2, void *parm3) { return 0; } // return 0 if unsupported +}; + + + + + +/*************************************************************************************** +**** PCM sink API +***************************************************************************************/ + +typedef struct +{ + bool doquant; + char movemode; // 0=default(l/r), -1=left only, 1=right only + char sizemode; // 0=preserve length, 1=quantize end + char quantstrength; // 1-100 + double quantamt; // quantize to (in qn) + char swingamt; // 1-100 + char range_min; // 0-100 + char range_max; +} midi_quantize_mode_t; + +class PCM_sink +{ + public: + PCM_sink() { m_st=0.0; } + virtual ~PCM_sink() { } + + virtual void GetOutputInfoString(char *buf, int buflen)=0; + virtual double GetStartTime() { return m_st; } + virtual void SetStartTime(double st) { m_st=st; } + virtual const char *GetFileName()=0; // get filename, if applicable (otherwise "") + virtual int GetNumChannels()=0; // return number of channels + virtual double GetLength()=0; // length in seconds, so far + virtual INT64 GetFileSize()=0; + + virtual void WriteMIDI(MIDI_eventlist *events, int len, double samplerate)=0; + virtual void WriteDoubles(ReaSample **samples, int len, int nch, int offset, int spacing)=0; + virtual bool WantMIDI() { return 0; } + + virtual int GetLastSecondPeaks(int sz, ReaSample *buf) { return 0; } + virtual void GetPeakInfo(PCM_source_peaktransfer_t *block) { } // allow getting of peaks thus far + + virtual int Extended(int call, void *parm1, void *parm2, void *parm3) { return 0; } // return 0 if unsupported + + private: + double m_st; +}; + +#define PCM_SINK_EXT_CREATESOURCE 0x80000 // parm1 = PCM_source ** (will be created if supported) +#define PCM_SINK_EXT_DONE 0x80001 // parm1 = optional HWND of the render dialog in case the sink needs more user interaction, parm2 = optional (char**)NULL-terminated array of key,value,key2,value2,... pointers if the sink supports updating metadata after write (may require the caller to have set padded metadata via SetCurrentSinkMetadata before creating the sink) +#define PCM_SINK_EXT_VERIFYFMT 0x80002 // parm1=int *srate, parm2= int *nch. plugin can override (and return 1!!) +#define PCM_SINK_EXT_SETQUANT 0x80003 // parm1 = (midi_quantize_mode_t*), or NULL to disable +#define PCM_SINK_EXT_SETRATE 0x80004 // parm1 = (double *) rateadj +#define PCM_SINK_EXT_GETBITDEPTH 0x80005 // parm1 = (int*) bitdepth (return 1 if supported) +#define PCM_SINK_EXT_ADDCUE 0x80006 // parm1=(PCM_cue*)cue OR parm2=(double*)transient position +#define PCM_SINK_EXT_SETCURBLOCKTIME 0x80007 // parm1 = (double *) project position -- called before each WriteDoubles etc +#define PCM_SINK_EXT_IS_VIDEO 0x80008 + +typedef struct // register using "pcmsink" +{ + unsigned int (*GetFmt)(const char **desc); + + const char *(*GetExtension)(const void *cfg, int cfg_l); + HWND (*ShowConfig)(const void *cfg, int cfg_l, HWND parent); + PCM_sink *(*CreateSink)(const char *filename, void *cfg, int cfg_l, int nch, int srate, bool buildpeaks); + +} pcmsink_register_t; + +typedef struct // register using "pcmsink_ext" +{ + pcmsink_register_t sink; + + // for extended calls that refer to the generic type of sink, rather than a specific instance of a sink + int (*Extended)(int call, void* parm1, void* parm2, void* parm3); + + + char expand[256]; +} pcmsink_register_ext_t; + +// supported via pcmsink_register_ext_t::Extended: +#define PCMSINKEXT_GETFORMATDESC 0x80000 // parm1=(void*)cfg, parm2=(int)cfglen, parm3=(const char*)retstring +#define PCMSINKEXT_GETFORMATDATARATE 0x80001 // parm1=(void*)cfg, parm2=(int)cfglen, parm3 = int[] {channels, samplerate} +#define PCMSINKEXT_GETFORMATBITDEPTH 0x80002 // parm1=(void*)cfg, parm2=(int)cfglen, returns bit depth if supported (negative with effective size if FP) + +/*************************************************************************************** +**** Resampler API (plug-ins can use this for SRC) +** +** +** See API functions Resampler_Create() and Resample_EnumModes() +***************************************************************************************/ + +class REAPER_Resample_Interface +{ +public: + virtual ~REAPER_Resample_Interface(){} + virtual void SetRates(double rate_in, double rate_out)=0; + virtual void Reset()=0; + + virtual double GetCurrentLatency()=0; // latency in seconds buffered -- do not call between resampleprepare and resampleout, undefined if you do... + virtual int ResamplePrepare(int out_samples, int nch, ReaSample **inbuffer)=0; // sample ratio + virtual int ResampleOut(ReaSample *out, int nsamples_in, int nsamples_out, int nch)=0; // returns output samples + + virtual int Extended(int call, void *parm1, void *parm2, void *parm3) { return 0; } // return 0 if unsupported +}; +#define RESAMPLE_EXT_SETRSMODE 0x1000 // parm1 == (int)resamplemode, or -1 for project default +#define RESAMPLE_EXT_SETFEEDMODE 0x1001 // parm1 = nonzero to set ResamplePrepare's out_samples to refer to request a specific number of input samples +#define RESAMPLE_EXT_RESETWITHFRACPOS 0x6000 // parm1 = (double*)&fracpos + + +/*************************************************************************************** +**** Pitch shift API (plug-ins can use this for pitch shift/time stretch) +** +** See API calls ReaperGetPitchShiftAPI(), EnumPitchShiftModes(), EnumPitchShiftSubModes() +** +***************************************************************************************/ + +#define REAPER_PITCHSHIFT_API_VER 0x14 + +class IReaperPitchShift +{ + public: + virtual ~IReaperPitchShift() { }; + virtual void set_srate(double srate)=0; + virtual void set_nch(int nch)=0; + virtual void set_shift(double shift)=0; + virtual void set_formant_shift(double shift)=0; // shift can be <0 for "only shift when in formant preserve mode", so that you can use it for effective rate changes etc in that mode + virtual void set_tempo(double tempo)=0; + + virtual void Reset()=0; // reset all buffers/latency + virtual ReaSample *GetBuffer(int size)=0; + virtual void BufferDone(int input_filled)=0; + + virtual void FlushSamples()=0; // make sure all output is available + + virtual bool IsReset()=0; + + virtual int GetSamples(int requested_output, ReaSample *buffer)=0; // returns number of samplepairs returned + + virtual void SetQualityParameter(int parm)=0; // set to: (mode<<16)+(submode), or -1 for "project default" (default) + virtual int Extended(int call, void *parm1, void *parm2, void *parm3) { return 0; } // return 0 if unsupported +}; +#define REAPER_PITCHSHIFT_EXT_GETMINMAXPRODUCTS 0x1 + + +/*************************************************************************************** +**** Peak getting/building API +** +** These are really only needed if you implement a PCM_source or PCM_sink. +** +** See functions PeakGet_Create(), PeakBuild_Create(), GetPeakFileName(), ClearPeakCache() +** +***************************************************************************************/ + + +class REAPER_PeakGet_Interface +{ +public: + virtual ~REAPER_PeakGet_Interface() { } + + virtual double GetMaxPeakRes()=0; + virtual void GetPeakInfo(PCM_source_peaktransfer_t *block)=0; + + virtual int Extended(int call, void *parm1, void *parm2, void *parm3) { return 0; } // return 0 if unsupported +}; + +class REAPER_PeakBuild_Interface +{ +public: + virtual ~REAPER_PeakBuild_Interface() { } + + virtual void ProcessSamples(ReaSample **samples, int len, int nch, int offs, int spread)=0; // in case a sink wants to build its own peaks (make sure it was created with src=NULL) + virtual int Run()=0; // or let it do it automatically (created with source!=NULL) + + virtual int GetLastSecondPeaks(int sz, ReaSample *buf)=0; // returns number of peaks in the last second, sz is maxsize + virtual void GetPeakInfo(PCM_source_peaktransfer_t *block)=0; // allow getting of peaks thus far (won't hit the highest resolution mipmap, just the 10/sec one or so) + + virtual int Extended(int call, void *parm1, void *parm2, void *parm3) { return 0; } // return 0 if unsupported +}; + +// recommended settings for sources switching to peak caches +#define REAPER_PEAKRES_MAX_NOPKS 200.0 +#define REAPER_PEAKRES_MUL_MIN 0.00001 // recommended for plug-ins, when 1000peaks/pix, toss hires source +#define REAPER_PEAKRES_MUL_MAX 1.0 // recommended for plug-ins, when 1.5pix/peak, switch to hi res source. this may be configurable someday via some sneakiness + + + +/* +** accelerator_register_t allows you to register ("accelerator") a record which lets you get a place in the +** keyboard processing queue. +*/ + +typedef struct accelerator_register_t +{ + // translateAccel returns: + // 0 if not our window, + // 1 to eat the keystroke, + // -1 to pass it on to the window, + // -10 (macOS only) to process event raw + // -20 (Windows only) to passed to the window, even if it is WM_SYSKEY*/VK_MENU which would otherwise be dropped + // -666 to force it to the main window's accel table (with the exception of ESC) + // -667 to force it to the main window's accel table, even if in a text field (5.24+ or so) + int (*translateAccel)(MSG *msg, accelerator_register_t *ctx); + bool isLocal; // must be TRUE, now (false is no longer supported, heh) + void *user; +} accelerator_register_t; + + +/* +** custom_action_register_t allows you to register ("custom_action") an action or a reascript into a section of the action list +** register("custom_action",ca) will return the command ID (instance-dependent but unique across all sections), +** or 0 if failed (e.g dupe idStr for actions, or script not found/supported, etc) +** for actions, the related callback should be registered with "hookcommand2" +*/ + +typedef struct +{ + int uniqueSectionId; // 0/100=main/main alt, 32063=media explorer, 32060=midi editor, 32061=midi event list editor, 32062=midi inline editor, etc + const char* idStr; // must be unique across all sections for actions, NULL for reascripts (automatically generated) + const char* name; // name as it is displayed in the action list, or full path to a reascript file + void *extra; // reserved for future use +} custom_action_register_t; + + +/* +** gaccel_register_t allows you to register ("gaccel") an action into the main keyboard section action list, and at the same time +** a default binding for it (accel.cmd is the command ID, desc is the description, and accel's other parameters are the +** key to bind. +*/ + +typedef struct +{ + ACCEL accel; // key flags/etc represent default values (user may customize) + const char *desc; // description (for user customizability) +} gaccel_register_t; // use "gaccel" + +/* +** action_help_t lets you register help text ("action_help") for an action, mapped by action name +** (a "help" plugin could register help text for Reaper built-in actions) +*/ + +typedef struct +{ + const char* action_desc; + const char* action_help; +} action_help_t; + +/* +** register("toggleaction", toggleactioncallback) lets you register a callback function +** that is called to check if an action registered by an extension has an on/off state. + +callback function: + int toggleactioncallback(int command_id); + +return: + -1=action does not belong to this extension, or does not toggle + 0=action belongs to this extension and is currently set to "off" + 1=action belongs to this extension and is currently set to "on" +*/ + + +/* +** register("hookcustommenu", menuhook) lets you register a menu hook function that is called +** when a customizable Reaper menu is initialized or shown. + +hook (callback) function: + void menuhook(const char* menuidstr, void* menu, int flag); + +flag: + 0=default menu is being initialized + 1=menu is about to be shown + +Do not retrieve or modify any Reaper menus except when your menuhook is called. + +Reaper calls menuhook with flag=0 when first initializing the menu, before the first time the menu +is displayed. You can add menu items or submenus during this call, which then become part of the +default menu structure (which the user can modify). Do not set any menu checked/grayed state, +do not add menu icons, if you add submenus do not retain handles to the submenus. +Do not modify any menus that don't call menuhook. + +Reaper calls menuhook with flag=1 before each time the menu is displayed. You can do any +dynamic menu populating, setting check/grayed states, adding icons during this call. + +All handling should be done relative to menu commands, not menu item positions, +because these menus can be customized and item order can change. +*/ + + +/* +** editor_register_t lets you integrate editors for "open in external editor" for files directly. +*/ + +typedef struct // register with "editor" +{ + int (*editFile)(const char *filename, HWND parent, int trackidx); // return TRUE if handled for this file + const char *(*wouldHandle)(const char *filename); // return your editor's description string + +} editor_register_t; + + +/* +** Project import registration. +** +** Implemented as a your-format->RPP converter, allowing you to generate directly to a ProjectStateContext +*/ +typedef struct // register with "projectimport" +{ + bool (*WantProjectFile)(const char *fn); // is this our file? + const char *(*EnumFileExtensions)(int i, char **descptr); // call increasing i until returns NULL. if descptr's output is NULL, use last description + int (*LoadProject)(const char *fn, ProjectStateContext *genstate); // return 0=ok, Generate RPP compatible project info in genstate +} project_import_register_t; + + +typedef struct project_config_extension_t // register with "projectconfig" +{ + // plug-ins may or may not want to save their undo states (look at isUndo) + // undo states will be saved if UNDO_STATE_MISCCFG is set (for adding your own undo points) + bool (*ProcessExtensionLine)(const char *line, ProjectStateContext *ctx, bool isUndo, struct project_config_extension_t *reg); // returns BOOL if line (and optionally subsequent lines) processed (return false if not plug-ins line) + void (*SaveExtensionConfig)(ProjectStateContext *ctx, bool isUndo, struct project_config_extension_t *reg); + + // optional: called on project load/undo before any (possible) ProcessExtensionLine. NULL is OK too + // also called on "new project" (wont be followed by ProcessExtensionLine calls in that case) + void (*BeginLoadProjectState)(bool isUndo, struct project_config_extension_t *reg); + + void *userData; +} project_config_extension_t; + + +typedef struct prefs_page_register_t // register useing "prefpage" +{ + const char *idstr; // simple id str + const char *displayname; + HWND (*create)(HWND par); + int par_id; + const char *par_idstr; + + int childrenFlag; // 1 for will have children + + void *treeitem; + HWND hwndCache; + + char _extra[64]; // + +} prefs_page_register_t; + +typedef struct audio_hook_register_t +{ + void (*OnAudioBuffer)(bool isPost, int len, double srate, struct audio_hook_register_t *reg); // called twice per frame, isPost being false then true + void *userdata1; + void *userdata2; + + // plug-in should zero these and they will be set by host + // only call from OnAudioBuffer, nowhere else!!! + int input_nch, output_nch; + ReaSample *(*GetBuffer)(bool isOutput, int idx); + +} audio_hook_register_t; + +/* +** Allows you to get callback from the audio thread before and after REAPER's processing. +** register with Audio_RegHardwareHook() + + Note that you should be careful with this! :) + +*/ + + +/* +** Customizable keyboard section definition etc +** +** Plug-ins may register keyboard action sections in by registering a "accel_section" to a KbdSectionInfo*. +*/ + +struct KbdAccel; + +typedef struct +{ + DWORD cmd; // action command ID + const char *text; // description of action +} KbdCmd; + +typedef struct +{ + int key; // key identifier + int cmd; // action command ID + int flags; // key flags +} KbdKeyBindingInfo; + + + +typedef struct +{ + int uniqueID; // 0=main, < 0x10000000 for cockos use only plzkthx + const char *name; // section name + + KbdCmd *action_list; // list of assignable actions + int action_list_cnt; + + KbdKeyBindingInfo *def_keys; // list of default key bindings + int def_keys_cnt; + + // hwnd is 0 if MIDI etc. return false if ignoring + bool (*onAction)(int cmd, int val, int valhw, int relmode, HWND hwnd); + + // this is allocated by the host not by the plug-in using it + // the user can edit the list of actions/macros +#ifdef _WDL_PTRLIST_H_ + WDL_PtrList<struct KbdAccel> *accels; + WDL_TypedBuf<int>* recent_cmds; +#else + void* accels; + void *recent_cmds; +#endif + + void *extended_data[32]; // for internal use +} KbdSectionInfo; + + + +typedef struct +{ +/* +** Note: you must initialize/deinitialize the cs/mutex (depending on OS) manually, and use it if accessing most parameters while the preview is active. +*/ + +#ifdef _WIN32 + CRITICAL_SECTION cs; +#else + pthread_mutex_t mutex; +#endif + PCM_source *src; + int m_out_chan; // &1024 means mono, low 10 bits are index of first channel + double curpos; + bool loop; + double volume; + + double peakvol[2]; + void *preview_track; // used for track previews, but only if m_out_chan == -1 +} preview_register_t; + +/* +** preview_register_t is not used with the normal register system, instead it's used with PlayPreview(), StopPreview(), PlayTrackPreview(), StopTrackPreview() +*/ + + + +#ifdef REAPER_WANT_DEPRECATED_COLORTHEMESTUFF /* no longer used -- see icontheme.h and GetColorThemeStruct() */ + +/* +** ColorTheme API access, these are used with GetColorTheme() +*/ + +#define COLORTHEMEIDX_TIMELINEFG 0 +#define COLORTHEMEIDX_ITEMTEXT 1 +#define COLORTHEMEIDX_ITEMBG 2 +#define COLORTHEMEIDX_TIMELINEBG 4 +#define COLORTHEMEIDX_TIMELINESELBG 5 +#define COLORTHEMEIDX_ITEMCONTROLS 6 +#define COLORTHEMEIDX_TRACKBG1 24 +#define COLORTHEMEIDX_TRACKBG2 25 +#define COLORTHEMEIDX_PEAKS1 28 +#define COLORTHEMEIDX_PEAKS2 29 +#define COLORTHEMEIDX_EDITCURSOR 35 +#define COLORTHEMEIDX_GRID1 36 +#define COLORTHEMEIDX_GRID2 37 +#define COLORTHEMEIDX_MARKER 38 +#define COLORTHEMEIDX_REGION 40 +#define COLORTHEMEIDX_GRID3 61 +#define COLORTHEMEIDX_LOOPSELBG 100 + +#define COLORTHEMEIDX_ITEM_LOGFONT -2 // these return LOGFONT * as (int) +#define COLORTHEMEIDX_TL_LOGFONT -1 + + +#define COLORTHEMEIDX_MIDI_TIMELINEBG 66 +#define COLORTHEMEIDX_MIDI_TIMELINEFG 67 +#define COLORTHEMEIDX_MIDI_GRID1 68 +#define COLORTHEMEIDX_MIDI_GRID2 69 +#define COLORTHEMEIDX_MIDI_GRID3 70 +#define COLORTHEMEIDX_MIDI_TRACKBG1 71 +#define COLORTHEMEIDX_MIDI_TRACKBG2 72 +#define COLORTHEMEIDX_MIDI_ENDPT 73 +#define COLORTHEMEIDX_MIDI_NOTEBG 74 +#define COLORTHEMEIDX_MIDI_NOTEFG 75 +#define COLORTHEMEIDX_MIDI_ITEMCONTROLS 76 +#define COLORTHEMEIDX_MIDI_EDITCURSOR 77 +#define COLORTHEMEIDX_MIDI_PKEY1 78 +#define COLORTHEMEIDX_MIDI_PKEY2 79 +#define COLORTHEMEIDX_MIDI_PKEY3 80 +#define COLORTHEMEIDX_MIDI_PKEYTEXT 81 +#define COLORTHEMEIDX_MIDI_OFFSCREENNOTE 103 +#define COLORTHEMEIDX_MIDI_OFFSCREENNOTESEL 104 + +#endif // colortheme stuff deprecated + +/* +** Screenset API +** +*/ + +/* + Note that "id" is a unique identifying string (usually a GUID etc) that is valid across + program runs (stored in project etc). lParam is instance-specific parameter (i.e. "this" pointer etc). +*/ +enum +{ + SCREENSET_ACTION_GETHWND = 0, + + SCREENSET_ACTION_IS_DOCKED = 1, // returns 1 if docked + SCREENSET_ACTION_SWITCH_DOCK = 4, //dock if undocked and vice-versa + + SCREENSET_ACTION_LOAD_STATE=0x100, // load state from actionParm (of actionParmSize). if both are NULL, hide. + SCREENSET_ACTION_SAVE_STATE, // save state to actionParm, max length actionParmSize (will usually be 4k or greater), return length +}; +typedef LRESULT (*screensetNewCallbackFunc)(int action, const char *id, void *param, void *actionParm, int actionParmSize); + +// This is managed using screenset_registerNew(), screenset_unregister(), etc + + +/* +** MIDI hardware device access. +** +*/ + + +class midi_Output +{ +public: + virtual ~midi_Output() {} + + virtual void BeginBlock() { } // outputs can implement these if they wish to have timed block sends + virtual void EndBlock(int length, double srate, double curtempo) { } + virtual void SendMsg(MIDI_event_t *msg, int frame_offset)=0; // frame_offset can be <0 for "instant" if supported + virtual void Send(unsigned char status, unsigned char d1, unsigned char d2, int frame_offset)=0; // frame_offset can be <0 for "instant" if supported + + virtual void Destroy() { delete this; } // allows implementations to do asynchronous destroy (5.95+) + +}; + + +class midi_Input +{ +public: + virtual ~midi_Input() {} + + virtual void start()=0; + virtual void stop()=0; + + virtual void SwapBufs(unsigned int timestamp)=0; // DEPRECATED call SwapBufsPrecise() instead // timestamp=process ms + + virtual void RunPreNoteTracking(int isAccum) { } + + virtual MIDI_eventlist *GetReadBuf()=0; // note: the event list here has frame offsets that are in units of 1/1024000 of a second, NOT sample frames + + virtual void SwapBufsPrecise(unsigned int coarsetimestamp, double precisetimestamp) // coarse=process ms, precise=process sec, the target will know internally which to use + { + SwapBufs(coarsetimestamp); // default impl is for backward compatibility + } + + virtual void Destroy() { delete this; } // allows implementations to do asynchronous destroy (5.95+) +}; + + + +/* +** Control Surface API +*/ + +class ReaProject; +class MediaTrack; +class MediaItem; +class MediaItem_Take; +class TrackEnvelope; + +class IReaperControlSurface +{ + public: + IReaperControlSurface() { } + virtual ~IReaperControlSurface() { } + + virtual const char *GetTypeString()=0; // simple unique string with only A-Z, 0-9, no spaces or other chars + virtual const char *GetDescString()=0; // human readable description (can include instance specific info) + virtual const char *GetConfigString()=0; // string of configuration data + + virtual void CloseNoReset() { } // close without sending "reset" messages, prevent "reset" being sent on destructor + + + virtual void Run() { } // called 30x/sec or so. + + + // these will be called by the host when states change etc + virtual void SetTrackListChange() { } + virtual void SetSurfaceVolume(MediaTrack *trackid, double volume) { } + virtual void SetSurfacePan(MediaTrack *trackid, double pan) { } + virtual void SetSurfaceMute(MediaTrack *trackid, bool mute) { } + virtual void SetSurfaceSelected(MediaTrack *trackid, bool selected) { } + virtual void SetSurfaceSolo(MediaTrack *trackid, bool solo) { } // trackid==master means "any solo" + virtual void SetSurfaceRecArm(MediaTrack *trackid, bool recarm) { } + virtual void SetPlayState(bool play, bool pause, bool rec) { } + virtual void SetRepeatState(bool rep) { } + virtual void SetTrackTitle(MediaTrack *trackid, const char *title) { } + virtual bool GetTouchState(MediaTrack *trackid, int isPan) { return false; } + virtual void SetAutoMode(int mode) { } // automation mode for current track + + virtual void ResetCachedVolPanStates() { } // good to flush your control states here + + virtual void OnTrackSelection(MediaTrack *trackid) { } // track was selected + + virtual bool IsKeyDown(int key) { return false; } // VK_CONTROL, VK_MENU, VK_SHIFT, etc, whatever makes sense for your surface + + virtual int Extended(int call, void *parm1, void *parm2, void *parm3) { return 0; } // return 0 if unsupported +}; + +#define CSURF_EXT_RESET 0x0001FFFF // clear all surface state and reset (harder reset than SetTrackListChange) +#define CSURF_EXT_SETINPUTMONITOR 0x00010001 // parm1=(MediaTrack*)track, parm2=(int*)recmonitor +#define CSURF_EXT_SETMETRONOME 0x00010002 // parm1=0 to disable metronome, !0 to enable +#define CSURF_EXT_SETAUTORECARM 0x00010003 // parm1=0 to disable autorecarm, !0 to enable +#define CSURF_EXT_SETRECMODE 0x00010004 // parm1=(int*)record mode: 0=autosplit and create takes, 1=replace (tape) mode +#define CSURF_EXT_SETSENDVOLUME 0x00010005 // parm1=(MediaTrack*)track, parm2=(int*)sendidx, parm3=(double*)volume +#define CSURF_EXT_SETSENDPAN 0x00010006 // parm1=(MediaTrack*)track, parm2=(int*)sendidx, parm3=(double*)pan +#define CSURF_EXT_SETFXENABLED 0x00010007 // parm1=(MediaTrack*)track, parm2=(int*)fxidx, parm3=0 if bypassed, !0 if enabled +#define CSURF_EXT_SETFXPARAM 0x00010008 // parm1=(MediaTrack*)track, parm2=(int*)(fxidx<<16|paramidx), parm3=(double*)normalized value +#define CSURF_EXT_SETFXPARAM_RECFX 0x00010018 // parm1=(MediaTrack*)track, parm2=(int*)(fxidx<<16|paramidx), parm3=(double*)normalized value +#define CSURF_EXT_SETBPMANDPLAYRATE 0x00010009 // parm1=*(double*)bpm (may be NULL), parm2=*(double*)playrate (may be NULL) +#define CSURF_EXT_SETLASTTOUCHEDFX 0x0001000A // parm1=(MediaTrack*)track, parm2=(int*)mediaitemidx (may be NULL), parm3=(int*)fxidx. all parms NULL=clear last touched FX +#define CSURF_EXT_SETFOCUSEDFX 0x0001000B // parm1=(MediaTrack*)track, parm2=(int*)mediaitemidx (may be NULL), parm3=(int*)fxidx. all parms NULL=clear focused FX +#define CSURF_EXT_SETLASTTOUCHEDTRACK 0x0001000C // parm1=(MediaTrack*)track +#define CSURF_EXT_SETMIXERSCROLL 0x0001000D // parm1=(MediaTrack*)track, leftmost track visible in the mixer +#define CSURF_EXT_SETPAN_EX 0x0001000E // parm1=(MediaTrack*)track, parm2=(double*)pan, parm3=(int*)mode 0=v1-3 balance, 3=v4+ balance, 5=stereo pan, 6=dual pan. for modes 5 and 6, (double*)pan points to an array of two doubles. if a csurf supports CSURF_EXT_SETPAN_EX, it should ignore CSurf_SetSurfacePan. +#define CSURF_EXT_SETRECVVOLUME 0x00010010 // parm1=(MediaTrack*)track, parm2=(int*)recvidx, parm3=(double*)volume +#define CSURF_EXT_SETRECVPAN 0x00010011 // parm1=(MediaTrack*)track, parm2=(int*)recvidx, parm3=(double*)pan +#define CSURF_EXT_SETFXOPEN 0x00010012 // parm1=(MediaTrack*)track, parm2=(int*)fxidx, parm3=0 if UI closed, !0 if open +#define CSURF_EXT_SETFXCHANGE 0x00010013 // parm1=(MediaTrack*)track, whenever FX are added, deleted, or change order. flags=(INT_PTR)parm2, &1=rec fx +#define CSURF_EXT_SETPROJECTMARKERCHANGE 0x00010014 // whenever project markers are changed +#define CSURF_EXT_TRACKFX_PRESET_CHANGED 0x00010015 // parm1=(MediaTrack*)track, parm2=(int*)fxidx (6.13+ probably) +#define CSURF_EXT_SUPPORTS_EXTENDED_TOUCH 0x00080001 // returns nonzero if GetTouchState can take isPan=2 for width, etc +#define CSURF_EXT_MIDI_DEVICE_REMAP 0x00010099 // parm1 = isout, parm2 = old idx, parm3 = new idx + +typedef struct +{ + const char *type_string; // simple unique string with only A-Z, 0-9, no spaces or other chars + const char *desc_string; // human readable description + + IReaperControlSurface *(*create)(const char *type_string, const char *configString, int *errStats); // errstats gets |1 if input error, |2 if output error + HWND (*ShowConfig)(const char *type_string, HWND parent, const char *initConfigString); +} reaper_csurf_reg_t; // register using "csurf"/"-csurf" + +// note you can also add a control surface behind the scenes with "csurf_inst" (IReaperControlSurface*)instance + + + +#ifndef UNDO_STATE_ALL +#define UNDO_STATE_ALL 0xFFFFFFFF +#define UNDO_STATE_TRACKCFG 1 // has track/master vol/pan/routing, routing/hwout envelopes too +#define UNDO_STATE_FX 2 // track/master fx +#define UNDO_STATE_ITEMS 4 // track items +#define UNDO_STATE_MISCCFG 8 // loop selection, markers, regions, extensions! +#define UNDO_STATE_FREEZE 16 // freeze state -- note that isfreeze is used independently, this is only used for the undo system to serialize the already frozen state +#define UNDO_STATE_TRACKENV 32 // non-FX envelopes only +#define UNDO_STATE_FXENV 64 // FX envelopes, implied by UNDO_STATE_FX too +#define UNDO_STATE_POOLEDENVS 128 // contents of pooled envs -- not position, length, rate etc of pooled env instances, which is part of envelope state +#endif + + +#define WDL_FILEWRITE_ON_ERROR(is_full) update_disk_counters(0,-101010110 - ((is_full) ? 1 : 0)); + +#define REAPER_MAX_CHANNELS 64 + +#endif//_REAPER_PLUGIN_H_ diff --git a/3rd/reaper-sdk/sdk/reaper_plugin_functions.h b/3rd/reaper-sdk/sdk/reaper_plugin_functions.h @@ -0,0 +1,9594 @@ +#ifndef _REAPER_PLUGIN_FUNCTIONS_H_ +#define _REAPER_PLUGIN_FUNCTIONS_H_ + +// REAPER API functions +// Generated by REAPER v6.45/win64 + +/* +* Copyright 2006 and later, Cockos Incorporated +* +* This software is provided 'as-is', without any express or implied +* warranty. In no event will the authors be held liable for any damages +* arising from the use of this software. +* +* Permission is granted to anyone to use this software for any purpose, +* including commercial applications, and to alter it and redistribute it +* freely, subject to the following restrictions: +* +* 1. The origin of this software must not be misrepresented; you must not +* claim that you wrote the original software. If you use this software +* in a product, an acknowledgment in the product documentation would be +* appreciated but is not required. +* 2. Altered source versions must be plainly marked as such, and must not be +* misrepresented as being the original software. +* 3. This notice may not be removed or altered from any source distribution. +*/ + +// Note: the C++ pure virtual interfaces used require the MSVC-compatible C++ ABI on Win32. Sorry, mingw users. +// +// Reaper extensions: see http://www.cockos.com/reaper/sdk/plugin/plugin.php and reaper_plugin.h. +// The API functions in this header can be retrieved using reaper_plugin_info_t.GetFunc(). +// +// VST plugins: see http://www.cockos.com/reaper/sdk/vst/vst_ext.php +// The API functions in this header can be retrieved using audioMasterCallback. +// +// Because the API is dynamic, callers should never assume a function exists. +// Check that a non-NULL function pointer was returned before using it (unless +// loaded functions are verified using REAPERAPI_LoadAPI(), see note below). + +// New (4.76+) usage of this file: +// 1) most source files should just #include "reaper_plugin_functions.h" as is. +// 2) one file should #define REAPERAPI_IMPLEMENT before including this file. +// 3) the plug-in should call REAPERAPI_LoadAPI(rec->GetFunc) from REAPER_PLUGIN_ENTRYPOINT +// and check the return value for errors (REAPERAPI_LoadAPI will return 0 on success). + +// By default, all functions listed in this file are loaded. This means that an older version +// of REAPER may not succeed in loading, and also it may bloat your plug-in. If you wish to only load +// needed functions, #define REAPERAPI_MINIMAL and various #define REAPERAPI_WANT_<functionname> lines +// before including this file. You must put these definitions where REAPERAPI_IMPLEMENT is defined +// and you can optionally put them elsewhere (to detect needed REAPERAPI_WANT_xxx lines at compile- +// time rather than link-time). +// +#if !defined(_LICE_H) && !defined(REAPERAPI_NO_LICE) +typedef unsigned int LICE_pixel; +typedef unsigned char LICE_pixel_chan; +class LICE_IBitmap; +class LICE_IFont; +#endif + +class WDL_VirtualWnd_BGCfg; +class AudioAccessor; +class joystick_device; + +// easiest to include reaper_plugin.h before reaper_plugin_functions.h in your application code. +// if not, you may need to edit this path. +#ifndef _REAPER_PLUGIN_H_ +#include "reaper_plugin.h" +#endif + +#ifdef REAPERAPI_DEF +#undef REAPERAPI_DEF +#endif +#ifdef REAPERAPI_IMPLEMENT + #define REAPERAPI_DEF +#else + #define REAPERAPI_DEF extern +#endif + + +#if defined(REAPERAPI_WANT___mergesort) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// __mergesort +// __mergesort is a stable sorting function with an API similar to qsort(). +// HOWEVER, it requires some temporary space, equal to the size of the data being sorted, so you can pass it as the last parameter, +// or NULL and it will allocate and free space internally. + + void (*__mergesort)(void* base, size_t nmemb, size_t size, int (*cmpfunc)(const void*,const void*), void* tmpspace); +#endif + +#if defined(REAPERAPI_WANT_AddCustomizableMenu) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// AddCustomizableMenu +// menuidstr is some unique identifying string +// menuname is for main menus only (displayed in a menu bar somewhere), NULL otherwise +// kbdsecname is the name of the KbdSectionInfo registered by this plugin, or NULL for the main actions section + + bool (*AddCustomizableMenu)(const char* menuidstr, const char* menuname, const char* kbdsecname, bool addtomainmenu); +#endif + +#if defined(REAPERAPI_WANT_AddExtensionsMainMenu) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// AddExtensionsMainMenu +// Add an Extensions main menu, which the extension can populate/modify with plugin_register("hookcustommenu") + + bool (*AddExtensionsMainMenu)(); +#endif + +#if defined(REAPERAPI_WANT_AddMediaItemToTrack) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// AddMediaItemToTrack +// creates a new media item. + + MediaItem* (*AddMediaItemToTrack)(MediaTrack* tr); +#endif + +#if defined(REAPERAPI_WANT_AddProjectMarker) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// AddProjectMarker +// Returns the index of the created marker/region, or -1 on failure. Supply wantidx>=0 if you want a particular index number, but you'll get a different index number a region and wantidx is already in use. + + int (*AddProjectMarker)(ReaProject* proj, bool isrgn, double pos, double rgnend, const char* name, int wantidx); +#endif + +#if defined(REAPERAPI_WANT_AddProjectMarker2) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// AddProjectMarker2 +// Returns the index of the created marker/region, or -1 on failure. Supply wantidx>=0 if you want a particular index number, but you'll get a different index number a region and wantidx is already in use. color should be 0 (default color), or ColorToNative(r,g,b)|0x1000000 + + int (*AddProjectMarker2)(ReaProject* proj, bool isrgn, double pos, double rgnend, const char* name, int wantidx, int color); +#endif + +#if defined(REAPERAPI_WANT_AddRemoveReaScript) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// AddRemoveReaScript +// Add a ReaScript (return the new command ID, or 0 if failed) or remove a ReaScript (return >0 on success). Use commit==true when adding/removing a single script. When bulk adding/removing n scripts, you can optimize the n-1 first calls with commit==false and commit==true for the last call. + + int (*AddRemoveReaScript)(bool add, int sectionID, const char* scriptfn, bool commit); +#endif + +#if defined(REAPERAPI_WANT_AddTakeToMediaItem) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// AddTakeToMediaItem +// creates a new take in an item + + MediaItem_Take* (*AddTakeToMediaItem)(MediaItem* item); +#endif + +#if defined(REAPERAPI_WANT_AddTempoTimeSigMarker) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// AddTempoTimeSigMarker +// Deprecated. Use SetTempoTimeSigMarker with ptidx=-1. + + bool (*AddTempoTimeSigMarker)(ReaProject* proj, double timepos, double bpm, int timesig_num, int timesig_denom, bool lineartempochange); +#endif + +#if defined(REAPERAPI_WANT_adjustZoom) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// adjustZoom +// forceset=0,doupd=true,centermode=-1 for default + + void (*adjustZoom)(double amt, int forceset, bool doupd, int centermode); +#endif + +#if defined(REAPERAPI_WANT_AnyTrackSolo) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// AnyTrackSolo + + bool (*AnyTrackSolo)(ReaProject* proj); +#endif + +#if defined(REAPERAPI_WANT_APIExists) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// APIExists +// Returns true if function_name exists in the REAPER API + + bool (*APIExists)(const char* function_name); +#endif + +#if defined(REAPERAPI_WANT_APITest) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// APITest +// Displays a message window if the API was successfully called. + + void (*APITest)(); +#endif + +#if defined(REAPERAPI_WANT_ApplyNudge) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// ApplyNudge +// nudgeflag: &1=set to value (otherwise nudge by value), &2=snap +// nudgewhat: 0=position, 1=left trim, 2=left edge, 3=right edge, 4=contents, 5=duplicate, 6=edit cursor +// nudgeunit: 0=ms, 1=seconds, 2=grid, 3=256th notes, ..., 15=whole notes, 16=measures.beats (1.15 = 1 measure + 1.5 beats), 17=samples, 18=frames, 19=pixels, 20=item lengths, 21=item selections +// value: amount to nudge by, or value to set to +// reverse: in nudge mode, nudges left (otherwise ignored) +// copies: in nudge duplicate mode, number of copies (otherwise ignored) + + bool (*ApplyNudge)(ReaProject* project, int nudgeflag, int nudgewhat, int nudgeunits, double value, bool reverse, int copies); +#endif + +#if defined(REAPERAPI_WANT_ArmCommand) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// ArmCommand +// arms a command (or disarms if 0 passed) in section sectionname (empty string for main) + + void (*ArmCommand)(int cmd, const char* sectionname); +#endif + +#if defined(REAPERAPI_WANT_Audio_Init) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// Audio_Init +// open all audio and MIDI devices, if not open + + void (*Audio_Init)(); +#endif + +#if defined(REAPERAPI_WANT_Audio_IsPreBuffer) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// Audio_IsPreBuffer +// is in pre-buffer? threadsafe + + int (*Audio_IsPreBuffer)(); +#endif + +#if defined(REAPERAPI_WANT_Audio_IsRunning) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// Audio_IsRunning +// is audio running at all? threadsafe + + int (*Audio_IsRunning)(); +#endif + +#if defined(REAPERAPI_WANT_Audio_Quit) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// Audio_Quit +// close all audio and MIDI devices, if open + + void (*Audio_Quit)(); +#endif + +#if defined(REAPERAPI_WANT_Audio_RegHardwareHook) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// Audio_RegHardwareHook +// return >0 on success + + int (*Audio_RegHardwareHook)(bool isAdd, audio_hook_register_t* reg); +#endif + +#if defined(REAPERAPI_WANT_AudioAccessorStateChanged) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// AudioAccessorStateChanged +// Returns true if the underlying samples (track or media item take) have changed, but does not update the audio accessor, so the user can selectively call AudioAccessorValidateState only when needed. See CreateTakeAudioAccessor, CreateTrackAudioAccessor, DestroyAudioAccessor, GetAudioAccessorEndTime, GetAudioAccessorSamples. + + bool (*AudioAccessorStateChanged)(AudioAccessor* accessor); +#endif + +#if defined(REAPERAPI_WANT_AudioAccessorUpdate) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// AudioAccessorUpdate +// Force the accessor to reload its state from the underlying track or media item take. See CreateTakeAudioAccessor, CreateTrackAudioAccessor, DestroyAudioAccessor, AudioAccessorStateChanged, GetAudioAccessorStartTime, GetAudioAccessorEndTime, GetAudioAccessorSamples. + + void (*AudioAccessorUpdate)(AudioAccessor* accessor); +#endif + +#if defined(REAPERAPI_WANT_AudioAccessorValidateState) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// AudioAccessorValidateState +// Validates the current state of the audio accessor -- must ONLY call this from the main thread. Returns true if the state changed. + + bool (*AudioAccessorValidateState)(AudioAccessor* accessor); +#endif + +#if defined(REAPERAPI_WANT_BypassFxAllTracks) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// BypassFxAllTracks +// -1 = bypass all if not all bypassed,otherwise unbypass all + + void (*BypassFxAllTracks)(int bypass); +#endif + +#if defined(REAPERAPI_WANT_CalculateNormalization) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// CalculateNormalization +// Calculate normalize adjustment for source media. normalizeTo: 0=LUFS-I, 1=RMS-I, 2=peak, 3=true peak, 4=LUFS-M max, 5=LUFS-S max. normalizeTarget: dBFS or LUFS value. normalizeStart, normalizeEnd: time bounds within source media for normalization calculation. If normalizationStart=0 and normalizationEnd=0, the full duration of the media will be used for the calculation. + + double (*CalculateNormalization)(PCM_source* source, int normalizeTo, double normalizeTarget, double normalizeStart, double normalizeEnd); +#endif + +#if defined(REAPERAPI_WANT_CalculatePeaks) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// CalculatePeaks + + int (*CalculatePeaks)(PCM_source_transfer_t* srcBlock, PCM_source_peaktransfer_t* pksBlock); +#endif + +#if defined(REAPERAPI_WANT_CalculatePeaksFloatSrcPtr) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// CalculatePeaksFloatSrcPtr +// NOTE: source samples field is a pointer to floats instead + + int (*CalculatePeaksFloatSrcPtr)(PCM_source_transfer_t* srcBlock, PCM_source_peaktransfer_t* pksBlock); +#endif + +#if defined(REAPERAPI_WANT_ClearAllRecArmed) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// ClearAllRecArmed + + void (*ClearAllRecArmed)(); +#endif + +#if defined(REAPERAPI_WANT_ClearConsole) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// ClearConsole +// Clear the ReaScript console. See ShowConsoleMsg + + void (*ClearConsole)(); +#endif + +#if defined(REAPERAPI_WANT_ClearPeakCache) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// ClearPeakCache +// resets the global peak caches + + void (*ClearPeakCache)(); +#endif + +#if defined(REAPERAPI_WANT_ColorFromNative) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// ColorFromNative +// Extract RGB values from an OS dependent color. See ColorToNative. + + void (*ColorFromNative)(int col, int* rOut, int* gOut, int* bOut); +#endif + +#if defined(REAPERAPI_WANT_ColorToNative) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// ColorToNative +// Make an OS dependent color from RGB values (e.g. RGB() macro on Windows). r,g and b are in [0..255]. See ColorFromNative. + + int (*ColorToNative)(int r, int g, int b); +#endif + +#if defined(REAPERAPI_WANT_CountActionShortcuts) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// CountActionShortcuts +// Returns the number of shortcuts that exist for the given command ID. +// see GetActionShortcutDesc, DeleteActionShortcut, DoActionShortcutDialog. + + int (*CountActionShortcuts)(KbdSectionInfo* section, int cmdID); +#endif + +#if defined(REAPERAPI_WANT_CountAutomationItems) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// CountAutomationItems +// Returns the number of automation items on this envelope. See GetSetAutomationItemInfo + + int (*CountAutomationItems)(TrackEnvelope* env); +#endif + +#if defined(REAPERAPI_WANT_CountEnvelopePoints) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// CountEnvelopePoints +// Returns the number of points in the envelope. See CountEnvelopePointsEx. + + int (*CountEnvelopePoints)(TrackEnvelope* envelope); +#endif + +#if defined(REAPERAPI_WANT_CountEnvelopePointsEx) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// CountEnvelopePointsEx +// Returns the number of points in the envelope. +// autoitem_idx=-1 for the underlying envelope, 0 for the first automation item on the envelope, etc. +// For automation items, pass autoitem_idx|0x10000000 to base ptidx on the number of points in one full loop iteration, +// even if the automation item is trimmed so that not all points are visible. +// Otherwise, ptidx will be based on the number of visible points in the automation item, including all loop iterations. +// See GetEnvelopePointEx, SetEnvelopePointEx, InsertEnvelopePointEx, DeleteEnvelopePointEx. + + int (*CountEnvelopePointsEx)(TrackEnvelope* envelope, int autoitem_idx); +#endif + +#if defined(REAPERAPI_WANT_CountMediaItems) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// CountMediaItems +// count the number of items in the project (proj=0 for active project) + + int (*CountMediaItems)(ReaProject* proj); +#endif + +#if defined(REAPERAPI_WANT_CountProjectMarkers) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// CountProjectMarkers +// num_markersOut and num_regionsOut may be NULL. + + int (*CountProjectMarkers)(ReaProject* proj, int* num_markersOut, int* num_regionsOut); +#endif + +#if defined(REAPERAPI_WANT_CountSelectedMediaItems) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// CountSelectedMediaItems +// count the number of selected items in the project (proj=0 for active project) + + int (*CountSelectedMediaItems)(ReaProject* proj); +#endif + +#if defined(REAPERAPI_WANT_CountSelectedTracks) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// CountSelectedTracks +// Count the number of selected tracks in the project (proj=0 for active project). This function ignores the master track, see CountSelectedTracks2. + + int (*CountSelectedTracks)(ReaProject* proj); +#endif + +#if defined(REAPERAPI_WANT_CountSelectedTracks2) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// CountSelectedTracks2 +// Count the number of selected tracks in the project (proj=0 for active project). + + int (*CountSelectedTracks2)(ReaProject* proj, bool wantmaster); +#endif + +#if defined(REAPERAPI_WANT_CountTakeEnvelopes) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// CountTakeEnvelopes +// See GetTakeEnvelope + + int (*CountTakeEnvelopes)(MediaItem_Take* take); +#endif + +#if defined(REAPERAPI_WANT_CountTakes) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// CountTakes +// count the number of takes in the item + + int (*CountTakes)(MediaItem* item); +#endif + +#if defined(REAPERAPI_WANT_CountTCPFXParms) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// CountTCPFXParms +// Count the number of FX parameter knobs displayed on the track control panel. + + int (*CountTCPFXParms)(ReaProject* project, MediaTrack* track); +#endif + +#if defined(REAPERAPI_WANT_CountTempoTimeSigMarkers) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// CountTempoTimeSigMarkers +// Count the number of tempo/time signature markers in the project. See GetTempoTimeSigMarker, SetTempoTimeSigMarker, AddTempoTimeSigMarker. + + int (*CountTempoTimeSigMarkers)(ReaProject* proj); +#endif + +#if defined(REAPERAPI_WANT_CountTrackEnvelopes) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// CountTrackEnvelopes +// see GetTrackEnvelope + + int (*CountTrackEnvelopes)(MediaTrack* track); +#endif + +#if defined(REAPERAPI_WANT_CountTrackMediaItems) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// CountTrackMediaItems +// count the number of items in the track + + int (*CountTrackMediaItems)(MediaTrack* track); +#endif + +#if defined(REAPERAPI_WANT_CountTracks) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// CountTracks +// count the number of tracks in the project (proj=0 for active project) + + int (*CountTracks)(ReaProject* projOptional); +#endif + +#if defined(REAPERAPI_WANT_CreateLocalOscHandler) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// CreateLocalOscHandler +// callback is a function pointer: void (*callback)(void* obj, const char* msg, int msglen), which handles OSC messages sent from REAPER. The function return is a local osc handler. See SendLocalOscMessage, DestroyOscHandler. + + void* (*CreateLocalOscHandler)(void* obj, void* callback); +#endif + +#if defined(REAPERAPI_WANT_CreateMIDIInput) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// CreateMIDIInput +// Can only reliably create midi access for devices not already opened in prefs/MIDI, suitable for control surfaces etc. + + midi_Input* (*CreateMIDIInput)(int dev); +#endif + +#if defined(REAPERAPI_WANT_CreateMIDIOutput) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// CreateMIDIOutput +// Can only reliably create midi access for devices not already opened in prefs/MIDI, suitable for control surfaces etc. If streamMode is set, msoffset100 points to a persistent variable that can change and reflects added delay to output in 100ths of a millisecond. + + midi_Output* (*CreateMIDIOutput)(int dev, bool streamMode, int* msoffset100); +#endif + +#if defined(REAPERAPI_WANT_CreateNewMIDIItemInProj) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// CreateNewMIDIItemInProj +// Create a new MIDI media item, containing no MIDI events. Time is in seconds unless qn is set. + + MediaItem* (*CreateNewMIDIItemInProj)(MediaTrack* track, double starttime, double endtime, const bool* qnInOptional); +#endif + +#if defined(REAPERAPI_WANT_CreateTakeAudioAccessor) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// CreateTakeAudioAccessor +// Create an audio accessor object for this take. Must only call from the main thread. See CreateTrackAudioAccessor, DestroyAudioAccessor, AudioAccessorStateChanged, GetAudioAccessorStartTime, GetAudioAccessorEndTime, GetAudioAccessorSamples. + + AudioAccessor* (*CreateTakeAudioAccessor)(MediaItem_Take* take); +#endif + +#if defined(REAPERAPI_WANT_CreateTrackAudioAccessor) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// CreateTrackAudioAccessor +// Create an audio accessor object for this track. Must only call from the main thread. See CreateTakeAudioAccessor, DestroyAudioAccessor, AudioAccessorStateChanged, GetAudioAccessorStartTime, GetAudioAccessorEndTime, GetAudioAccessorSamples. + + AudioAccessor* (*CreateTrackAudioAccessor)(MediaTrack* track); +#endif + +#if defined(REAPERAPI_WANT_CreateTrackSend) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// CreateTrackSend +// Create a send/receive (desttrInOptional!=NULL), or a hardware output (desttrInOptional==NULL) with default properties, return >=0 on success (== new send/receive index). See RemoveTrackSend, GetSetTrackSendInfo, GetTrackSendInfo_Value, SetTrackSendInfo_Value. + + int (*CreateTrackSend)(MediaTrack* tr, MediaTrack* desttrInOptional); +#endif + +#if defined(REAPERAPI_WANT_CSurf_FlushUndo) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// CSurf_FlushUndo +// call this to force flushing of the undo states after using CSurf_On*Change() + + void (*CSurf_FlushUndo)(bool force); +#endif + +#if defined(REAPERAPI_WANT_CSurf_GetTouchState) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// CSurf_GetTouchState + + bool (*CSurf_GetTouchState)(MediaTrack* trackid, int isPan); +#endif + +#if defined(REAPERAPI_WANT_CSurf_GoEnd) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// CSurf_GoEnd + + void (*CSurf_GoEnd)(); +#endif + +#if defined(REAPERAPI_WANT_CSurf_GoStart) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// CSurf_GoStart + + void (*CSurf_GoStart)(); +#endif + +#if defined(REAPERAPI_WANT_CSurf_NumTracks) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// CSurf_NumTracks + + int (*CSurf_NumTracks)(bool mcpView); +#endif + +#if defined(REAPERAPI_WANT_CSurf_OnArrow) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// CSurf_OnArrow + + void (*CSurf_OnArrow)(int whichdir, bool wantzoom); +#endif + +#if defined(REAPERAPI_WANT_CSurf_OnFwd) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// CSurf_OnFwd + + void (*CSurf_OnFwd)(int seekplay); +#endif + +#if defined(REAPERAPI_WANT_CSurf_OnFXChange) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// CSurf_OnFXChange + + bool (*CSurf_OnFXChange)(MediaTrack* trackid, int en); +#endif + +#if defined(REAPERAPI_WANT_CSurf_OnInputMonitorChange) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// CSurf_OnInputMonitorChange + + int (*CSurf_OnInputMonitorChange)(MediaTrack* trackid, int monitor); +#endif + +#if defined(REAPERAPI_WANT_CSurf_OnInputMonitorChangeEx) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// CSurf_OnInputMonitorChangeEx + + int (*CSurf_OnInputMonitorChangeEx)(MediaTrack* trackid, int monitor, bool allowgang); +#endif + +#if defined(REAPERAPI_WANT_CSurf_OnMuteChange) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// CSurf_OnMuteChange + + bool (*CSurf_OnMuteChange)(MediaTrack* trackid, int mute); +#endif + +#if defined(REAPERAPI_WANT_CSurf_OnMuteChangeEx) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// CSurf_OnMuteChangeEx + + bool (*CSurf_OnMuteChangeEx)(MediaTrack* trackid, int mute, bool allowgang); +#endif + +#if defined(REAPERAPI_WANT_CSurf_OnOscControlMessage) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// CSurf_OnOscControlMessage + + void (*CSurf_OnOscControlMessage)(const char* msg, const float* arg); +#endif + +#if defined(REAPERAPI_WANT_CSurf_OnPanChange) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// CSurf_OnPanChange + + double (*CSurf_OnPanChange)(MediaTrack* trackid, double pan, bool relative); +#endif + +#if defined(REAPERAPI_WANT_CSurf_OnPanChangeEx) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// CSurf_OnPanChangeEx + + double (*CSurf_OnPanChangeEx)(MediaTrack* trackid, double pan, bool relative, bool allowGang); +#endif + +#if defined(REAPERAPI_WANT_CSurf_OnPause) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// CSurf_OnPause + + void (*CSurf_OnPause)(); +#endif + +#if defined(REAPERAPI_WANT_CSurf_OnPlay) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// CSurf_OnPlay + + void (*CSurf_OnPlay)(); +#endif + +#if defined(REAPERAPI_WANT_CSurf_OnPlayRateChange) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// CSurf_OnPlayRateChange + + void (*CSurf_OnPlayRateChange)(double playrate); +#endif + +#if defined(REAPERAPI_WANT_CSurf_OnRecArmChange) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// CSurf_OnRecArmChange + + bool (*CSurf_OnRecArmChange)(MediaTrack* trackid, int recarm); +#endif + +#if defined(REAPERAPI_WANT_CSurf_OnRecArmChangeEx) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// CSurf_OnRecArmChangeEx + + bool (*CSurf_OnRecArmChangeEx)(MediaTrack* trackid, int recarm, bool allowgang); +#endif + +#if defined(REAPERAPI_WANT_CSurf_OnRecord) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// CSurf_OnRecord + + void (*CSurf_OnRecord)(); +#endif + +#if defined(REAPERAPI_WANT_CSurf_OnRecvPanChange) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// CSurf_OnRecvPanChange + + double (*CSurf_OnRecvPanChange)(MediaTrack* trackid, int recv_index, double pan, bool relative); +#endif + +#if defined(REAPERAPI_WANT_CSurf_OnRecvVolumeChange) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// CSurf_OnRecvVolumeChange + + double (*CSurf_OnRecvVolumeChange)(MediaTrack* trackid, int recv_index, double volume, bool relative); +#endif + +#if defined(REAPERAPI_WANT_CSurf_OnRew) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// CSurf_OnRew + + void (*CSurf_OnRew)(int seekplay); +#endif + +#if defined(REAPERAPI_WANT_CSurf_OnRewFwd) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// CSurf_OnRewFwd + + void (*CSurf_OnRewFwd)(int seekplay, int dir); +#endif + +#if defined(REAPERAPI_WANT_CSurf_OnScroll) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// CSurf_OnScroll + + void (*CSurf_OnScroll)(int xdir, int ydir); +#endif + +#if defined(REAPERAPI_WANT_CSurf_OnSelectedChange) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// CSurf_OnSelectedChange + + bool (*CSurf_OnSelectedChange)(MediaTrack* trackid, int selected); +#endif + +#if defined(REAPERAPI_WANT_CSurf_OnSendPanChange) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// CSurf_OnSendPanChange + + double (*CSurf_OnSendPanChange)(MediaTrack* trackid, int send_index, double pan, bool relative); +#endif + +#if defined(REAPERAPI_WANT_CSurf_OnSendVolumeChange) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// CSurf_OnSendVolumeChange + + double (*CSurf_OnSendVolumeChange)(MediaTrack* trackid, int send_index, double volume, bool relative); +#endif + +#if defined(REAPERAPI_WANT_CSurf_OnSoloChange) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// CSurf_OnSoloChange + + bool (*CSurf_OnSoloChange)(MediaTrack* trackid, int solo); +#endif + +#if defined(REAPERAPI_WANT_CSurf_OnSoloChangeEx) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// CSurf_OnSoloChangeEx + + bool (*CSurf_OnSoloChangeEx)(MediaTrack* trackid, int solo, bool allowgang); +#endif + +#if defined(REAPERAPI_WANT_CSurf_OnStop) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// CSurf_OnStop + + void (*CSurf_OnStop)(); +#endif + +#if defined(REAPERAPI_WANT_CSurf_OnTempoChange) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// CSurf_OnTempoChange + + void (*CSurf_OnTempoChange)(double bpm); +#endif + +#if defined(REAPERAPI_WANT_CSurf_OnTrackSelection) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// CSurf_OnTrackSelection + + void (*CSurf_OnTrackSelection)(MediaTrack* trackid); +#endif + +#if defined(REAPERAPI_WANT_CSurf_OnVolumeChange) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// CSurf_OnVolumeChange + + double (*CSurf_OnVolumeChange)(MediaTrack* trackid, double volume, bool relative); +#endif + +#if defined(REAPERAPI_WANT_CSurf_OnVolumeChangeEx) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// CSurf_OnVolumeChangeEx + + double (*CSurf_OnVolumeChangeEx)(MediaTrack* trackid, double volume, bool relative, bool allowGang); +#endif + +#if defined(REAPERAPI_WANT_CSurf_OnWidthChange) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// CSurf_OnWidthChange + + double (*CSurf_OnWidthChange)(MediaTrack* trackid, double width, bool relative); +#endif + +#if defined(REAPERAPI_WANT_CSurf_OnWidthChangeEx) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// CSurf_OnWidthChangeEx + + double (*CSurf_OnWidthChangeEx)(MediaTrack* trackid, double width, bool relative, bool allowGang); +#endif + +#if defined(REAPERAPI_WANT_CSurf_OnZoom) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// CSurf_OnZoom + + void (*CSurf_OnZoom)(int xdir, int ydir); +#endif + +#if defined(REAPERAPI_WANT_CSurf_ResetAllCachedVolPanStates) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// CSurf_ResetAllCachedVolPanStates + + void (*CSurf_ResetAllCachedVolPanStates)(); +#endif + +#if defined(REAPERAPI_WANT_CSurf_ScrubAmt) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// CSurf_ScrubAmt + + void (*CSurf_ScrubAmt)(double amt); +#endif + +#if defined(REAPERAPI_WANT_CSurf_SetAutoMode) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// CSurf_SetAutoMode + + void (*CSurf_SetAutoMode)(int mode, IReaperControlSurface* ignoresurf); +#endif + +#if defined(REAPERAPI_WANT_CSurf_SetPlayState) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// CSurf_SetPlayState + + void (*CSurf_SetPlayState)(bool play, bool pause, bool rec, IReaperControlSurface* ignoresurf); +#endif + +#if defined(REAPERAPI_WANT_CSurf_SetRepeatState) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// CSurf_SetRepeatState + + void (*CSurf_SetRepeatState)(bool rep, IReaperControlSurface* ignoresurf); +#endif + +#if defined(REAPERAPI_WANT_CSurf_SetSurfaceMute) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// CSurf_SetSurfaceMute + + void (*CSurf_SetSurfaceMute)(MediaTrack* trackid, bool mute, IReaperControlSurface* ignoresurf); +#endif + +#if defined(REAPERAPI_WANT_CSurf_SetSurfacePan) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// CSurf_SetSurfacePan + + void (*CSurf_SetSurfacePan)(MediaTrack* trackid, double pan, IReaperControlSurface* ignoresurf); +#endif + +#if defined(REAPERAPI_WANT_CSurf_SetSurfaceRecArm) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// CSurf_SetSurfaceRecArm + + void (*CSurf_SetSurfaceRecArm)(MediaTrack* trackid, bool recarm, IReaperControlSurface* ignoresurf); +#endif + +#if defined(REAPERAPI_WANT_CSurf_SetSurfaceSelected) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// CSurf_SetSurfaceSelected + + void (*CSurf_SetSurfaceSelected)(MediaTrack* trackid, bool selected, IReaperControlSurface* ignoresurf); +#endif + +#if defined(REAPERAPI_WANT_CSurf_SetSurfaceSolo) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// CSurf_SetSurfaceSolo + + void (*CSurf_SetSurfaceSolo)(MediaTrack* trackid, bool solo, IReaperControlSurface* ignoresurf); +#endif + +#if defined(REAPERAPI_WANT_CSurf_SetSurfaceVolume) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// CSurf_SetSurfaceVolume + + void (*CSurf_SetSurfaceVolume)(MediaTrack* trackid, double volume, IReaperControlSurface* ignoresurf); +#endif + +#if defined(REAPERAPI_WANT_CSurf_SetTrackListChange) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// CSurf_SetTrackListChange + + void (*CSurf_SetTrackListChange)(); +#endif + +#if defined(REAPERAPI_WANT_CSurf_TrackFromID) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// CSurf_TrackFromID + + MediaTrack* (*CSurf_TrackFromID)(int idx, bool mcpView); +#endif + +#if defined(REAPERAPI_WANT_CSurf_TrackToID) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// CSurf_TrackToID + + int (*CSurf_TrackToID)(MediaTrack* track, bool mcpView); +#endif + +#if defined(REAPERAPI_WANT_DB2SLIDER) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// DB2SLIDER + + double (*DB2SLIDER)(double x); +#endif + +#if defined(REAPERAPI_WANT_DeleteActionShortcut) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// DeleteActionShortcut +// Delete the specific shortcut for the given command ID. +// See CountActionShortcuts, GetActionShortcutDesc, DoActionShortcutDialog. + + bool (*DeleteActionShortcut)(KbdSectionInfo* section, int cmdID, int shortcutidx); +#endif + +#if defined(REAPERAPI_WANT_DeleteEnvelopePointEx) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// DeleteEnvelopePointEx +// Delete an envelope point. If setting multiple points at once, set noSort=true, and call Envelope_SortPoints when done. +// autoitem_idx=-1 for the underlying envelope, 0 for the first automation item on the envelope, etc. +// For automation items, pass autoitem_idx|0x10000000 to base ptidx on the number of points in one full loop iteration, +// even if the automation item is trimmed so that not all points are visible. +// Otherwise, ptidx will be based on the number of visible points in the automation item, including all loop iterations. +// See CountEnvelopePointsEx, GetEnvelopePointEx, SetEnvelopePointEx, InsertEnvelopePointEx. + + bool (*DeleteEnvelopePointEx)(TrackEnvelope* envelope, int autoitem_idx, int ptidx); +#endif + +#if defined(REAPERAPI_WANT_DeleteEnvelopePointRange) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// DeleteEnvelopePointRange +// Delete a range of envelope points. See DeleteEnvelopePointRangeEx, DeleteEnvelopePointEx. + + bool (*DeleteEnvelopePointRange)(TrackEnvelope* envelope, double time_start, double time_end); +#endif + +#if defined(REAPERAPI_WANT_DeleteEnvelopePointRangeEx) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// DeleteEnvelopePointRangeEx +// Delete a range of envelope points. autoitem_idx=-1 for the underlying envelope, 0 for the first automation item on the envelope, etc. + + bool (*DeleteEnvelopePointRangeEx)(TrackEnvelope* envelope, int autoitem_idx, double time_start, double time_end); +#endif + +#if defined(REAPERAPI_WANT_DeleteExtState) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// DeleteExtState +// Delete the extended state value for a specific section and key. persist=true means the value should remain deleted the next time REAPER is opened. See SetExtState, GetExtState, HasExtState. + + void (*DeleteExtState)(const char* section, const char* key, bool persist); +#endif + +#if defined(REAPERAPI_WANT_DeleteProjectMarker) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// DeleteProjectMarker +// Delete a marker. proj==NULL for the active project. + + bool (*DeleteProjectMarker)(ReaProject* proj, int markrgnindexnumber, bool isrgn); +#endif + +#if defined(REAPERAPI_WANT_DeleteProjectMarkerByIndex) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// DeleteProjectMarkerByIndex +// Differs from DeleteProjectMarker only in that markrgnidx is 0 for the first marker/region, 1 for the next, etc (see EnumProjectMarkers3), rather than representing the displayed marker/region ID number (see SetProjectMarker4). + + bool (*DeleteProjectMarkerByIndex)(ReaProject* proj, int markrgnidx); +#endif + +#if defined(REAPERAPI_WANT_DeleteTakeMarker) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// DeleteTakeMarker +// Delete a take marker. Note that idx will change for all following take markers. See GetNumTakeMarkers, GetTakeMarker, SetTakeMarker + + bool (*DeleteTakeMarker)(MediaItem_Take* take, int idx); +#endif + +#if defined(REAPERAPI_WANT_DeleteTakeStretchMarkers) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// DeleteTakeStretchMarkers +// Deletes one or more stretch markers. Returns number of stretch markers deleted. + + int (*DeleteTakeStretchMarkers)(MediaItem_Take* take, int idx, const int* countInOptional); +#endif + +#if defined(REAPERAPI_WANT_DeleteTempoTimeSigMarker) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// DeleteTempoTimeSigMarker +// Delete a tempo/time signature marker. + + bool (*DeleteTempoTimeSigMarker)(ReaProject* project, int markerindex); +#endif + +#if defined(REAPERAPI_WANT_DeleteTrack) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// DeleteTrack +// deletes a track + + void (*DeleteTrack)(MediaTrack* tr); +#endif + +#if defined(REAPERAPI_WANT_DeleteTrackMediaItem) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// DeleteTrackMediaItem + + bool (*DeleteTrackMediaItem)(MediaTrack* tr, MediaItem* it); +#endif + +#if defined(REAPERAPI_WANT_DestroyAudioAccessor) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// DestroyAudioAccessor +// Destroy an audio accessor. Must only call from the main thread. See CreateTakeAudioAccessor, CreateTrackAudioAccessor, AudioAccessorStateChanged, GetAudioAccessorStartTime, GetAudioAccessorEndTime, GetAudioAccessorSamples. + + void (*DestroyAudioAccessor)(AudioAccessor* accessor); +#endif + +#if defined(REAPERAPI_WANT_DestroyLocalOscHandler) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// DestroyLocalOscHandler +// See CreateLocalOscHandler, SendLocalOscMessage. + + void (*DestroyLocalOscHandler)(void* local_osc_handler); +#endif + +#if defined(REAPERAPI_WANT_DoActionShortcutDialog) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// DoActionShortcutDialog +// Open the action shortcut dialog to edit or add a shortcut for the given command ID. If (shortcutidx >= 0 && shortcutidx < CountActionShortcuts()), that specific shortcut will be replaced, otherwise a new shortcut will be added. +// See CountActionShortcuts, GetActionShortcutDesc, DeleteActionShortcut. + + bool (*DoActionShortcutDialog)(HWND hwnd, KbdSectionInfo* section, int cmdID, int shortcutidx); +#endif + +#if defined(REAPERAPI_WANT_Dock_UpdateDockID) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// Dock_UpdateDockID +// updates preference for docker window ident_str to be in dock whichDock on next open + + void (*Dock_UpdateDockID)(const char* ident_str, int whichDock); +#endif + +#if defined(REAPERAPI_WANT_DockGetPosition) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// DockGetPosition +// -1=not found, 0=bottom, 1=left, 2=top, 3=right, 4=floating + + int (*DockGetPosition)(int whichDock); +#endif + +#if defined(REAPERAPI_WANT_DockIsChildOfDock) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// DockIsChildOfDock +// returns dock index that contains hwnd, or -1 + + int (*DockIsChildOfDock)(HWND hwnd, bool* isFloatingDockerOut); +#endif + +#if defined(REAPERAPI_WANT_DockWindowActivate) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// DockWindowActivate + + void (*DockWindowActivate)(HWND hwnd); +#endif + +#if defined(REAPERAPI_WANT_DockWindowAdd) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// DockWindowAdd + + void (*DockWindowAdd)(HWND hwnd, const char* name, int pos, bool allowShow); +#endif + +#if defined(REAPERAPI_WANT_DockWindowAddEx) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// DockWindowAddEx + + void (*DockWindowAddEx)(HWND hwnd, const char* name, const char* identstr, bool allowShow); +#endif + +#if defined(REAPERAPI_WANT_DockWindowRefresh) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// DockWindowRefresh + + void (*DockWindowRefresh)(); +#endif + +#if defined(REAPERAPI_WANT_DockWindowRefreshForHWND) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// DockWindowRefreshForHWND + + void (*DockWindowRefreshForHWND)(HWND hwnd); +#endif + +#if defined(REAPERAPI_WANT_DockWindowRemove) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// DockWindowRemove + + void (*DockWindowRemove)(HWND hwnd); +#endif + +#if defined(REAPERAPI_WANT_DuplicateCustomizableMenu) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// DuplicateCustomizableMenu +// Populate destmenu with all the entries and submenus found in srcmenu + + bool (*DuplicateCustomizableMenu)(void* srcmenu, void* destmenu); +#endif + +#if defined(REAPERAPI_WANT_EditTempoTimeSigMarker) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// EditTempoTimeSigMarker +// Open the tempo/time signature marker editor dialog. + + bool (*EditTempoTimeSigMarker)(ReaProject* project, int markerindex); +#endif + +#if defined(REAPERAPI_WANT_EnsureNotCompletelyOffscreen) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// EnsureNotCompletelyOffscreen +// call with a saved window rect for your window and it'll correct any positioning info. + + void (*EnsureNotCompletelyOffscreen)(RECT* rInOut); +#endif + +#if defined(REAPERAPI_WANT_EnumerateFiles) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// EnumerateFiles +// List the files in the "path" directory. Returns NULL/nil when all files have been listed. Use fileindex = -1 to force re-read of directory (invalidate cache). See EnumerateSubdirectories + + const char* (*EnumerateFiles)(const char* path, int fileindex); +#endif + +#if defined(REAPERAPI_WANT_EnumerateSubdirectories) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// EnumerateSubdirectories +// List the subdirectories in the "path" directory. Use subdirindex = -1 to force re-read of directory (invalidate cache). Returns NULL/nil when all subdirectories have been listed. See EnumerateFiles + + const char* (*EnumerateSubdirectories)(const char* path, int subdirindex); +#endif + +#if defined(REAPERAPI_WANT_EnumPitchShiftModes) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// EnumPitchShiftModes +// Start querying modes at 0, returns FALSE when no more modes possible, sets strOut to NULL if a mode is currently unsupported + + bool (*EnumPitchShiftModes)(int mode, const char** strOut); +#endif + +#if defined(REAPERAPI_WANT_EnumPitchShiftSubModes) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// EnumPitchShiftSubModes +// Returns submode name, or NULL + + const char* (*EnumPitchShiftSubModes)(int mode, int submode); +#endif + +#if defined(REAPERAPI_WANT_EnumProjectMarkers) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// EnumProjectMarkers + + int (*EnumProjectMarkers)(int idx, bool* isrgnOut, double* posOut, double* rgnendOut, const char** nameOut, int* markrgnindexnumberOut); +#endif + +#if defined(REAPERAPI_WANT_EnumProjectMarkers2) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// EnumProjectMarkers2 + + int (*EnumProjectMarkers2)(ReaProject* proj, int idx, bool* isrgnOut, double* posOut, double* rgnendOut, const char** nameOut, int* markrgnindexnumberOut); +#endif + +#if defined(REAPERAPI_WANT_EnumProjectMarkers3) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// EnumProjectMarkers3 + + int (*EnumProjectMarkers3)(ReaProject* proj, int idx, bool* isrgnOut, double* posOut, double* rgnendOut, const char** nameOut, int* markrgnindexnumberOut, int* colorOut); +#endif + +#if defined(REAPERAPI_WANT_EnumProjects) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// EnumProjects +// idx=-1 for current project,projfn can be NULL if not interested in filename. use idx 0x40000000 for currently rendering project, if any. + + ReaProject* (*EnumProjects)(int idx, char* projfnOutOptional, int projfnOutOptional_sz); +#endif + +#if defined(REAPERAPI_WANT_EnumProjExtState) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// EnumProjExtState +// Enumerate the data stored with the project for a specific extname. Returns false when there is no more data. See SetProjExtState, GetProjExtState. + + bool (*EnumProjExtState)(ReaProject* proj, const char* extname, int idx, char* keyOutOptional, int keyOutOptional_sz, char* valOutOptional, int valOutOptional_sz); +#endif + +#if defined(REAPERAPI_WANT_EnumRegionRenderMatrix) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// EnumRegionRenderMatrix +// Enumerate which tracks will be rendered within this region when using the region render matrix. When called with rendertrack==0, the function returns the first track that will be rendered (which may be the master track); rendertrack==1 will return the next track rendered, and so on. The function returns NULL when there are no more tracks that will be rendered within this region. + + MediaTrack* (*EnumRegionRenderMatrix)(ReaProject* proj, int regionindex, int rendertrack); +#endif + +#if defined(REAPERAPI_WANT_EnumTrackMIDIProgramNames) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// EnumTrackMIDIProgramNames +// returns false if there are no plugins on the track that support MIDI programs,or if all programs have been enumerated + + bool (*EnumTrackMIDIProgramNames)(int track, int programNumber, char* programName, int programName_sz); +#endif + +#if defined(REAPERAPI_WANT_EnumTrackMIDIProgramNamesEx) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// EnumTrackMIDIProgramNamesEx +// returns false if there are no plugins on the track that support MIDI programs,or if all programs have been enumerated + + bool (*EnumTrackMIDIProgramNamesEx)(ReaProject* proj, MediaTrack* track, int programNumber, char* programName, int programName_sz); +#endif + +#if defined(REAPERAPI_WANT_Envelope_Evaluate) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// Envelope_Evaluate +// Get the effective envelope value at a given time position. samplesRequested is how long the caller expects until the next call to Envelope_Evaluate (often, the buffer block size). The return value is how many samples beyond that time position that the returned values are valid. dVdS is the change in value per sample (first derivative), ddVdS is the second derivative, dddVdS is the third derivative. See GetEnvelopeScalingMode. + + int (*Envelope_Evaluate)(TrackEnvelope* envelope, double time, double samplerate, int samplesRequested, double* valueOut, double* dVdSOut, double* ddVdSOut, double* dddVdSOut); +#endif + +#if defined(REAPERAPI_WANT_Envelope_FormatValue) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// Envelope_FormatValue +// Formats the value of an envelope to a user-readable form + + void (*Envelope_FormatValue)(TrackEnvelope* env, double value, char* bufOut, int bufOut_sz); +#endif + +#if defined(REAPERAPI_WANT_Envelope_GetParentTake) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// Envelope_GetParentTake +// If take envelope, gets the take from the envelope. If FX, indexOut set to FX index, index2Out set to parameter index, otherwise -1. + + MediaItem_Take* (*Envelope_GetParentTake)(TrackEnvelope* env, int* indexOut, int* index2Out); +#endif + +#if defined(REAPERAPI_WANT_Envelope_GetParentTrack) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// Envelope_GetParentTrack +// If track envelope, gets the track from the envelope. If FX, indexOut set to FX index, index2Out set to parameter index, otherwise -1. + + MediaTrack* (*Envelope_GetParentTrack)(TrackEnvelope* env, int* indexOut, int* index2Out); +#endif + +#if defined(REAPERAPI_WANT_Envelope_SortPoints) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// Envelope_SortPoints +// Sort envelope points by time. See SetEnvelopePoint, InsertEnvelopePoint. + + bool (*Envelope_SortPoints)(TrackEnvelope* envelope); +#endif + +#if defined(REAPERAPI_WANT_Envelope_SortPointsEx) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// Envelope_SortPointsEx +// Sort envelope points by time. autoitem_idx=-1 for the underlying envelope, 0 for the first automation item on the envelope, etc. See SetEnvelopePoint, InsertEnvelopePoint. + + bool (*Envelope_SortPointsEx)(TrackEnvelope* envelope, int autoitem_idx); +#endif + +#if defined(REAPERAPI_WANT_ExecProcess) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// ExecProcess +// Executes command line, returns NULL on total failure, otherwise the return value, a newline, and then the output of the command. If timeoutmsec is 0, command will be allowed to run indefinitely (recommended for large amounts of returned output). timeoutmsec is -1 for no wait/terminate, -2 for no wait and minimize + + const char* (*ExecProcess)(const char* cmdline, int timeoutmsec); +#endif + +#if defined(REAPERAPI_WANT_file_exists) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// file_exists +// returns true if path points to a valid, readable file + + bool (*file_exists)(const char* path); +#endif + +#if defined(REAPERAPI_WANT_FindTempoTimeSigMarker) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// FindTempoTimeSigMarker +// Find the tempo/time signature marker that falls at or before this time position (the marker that is in effect as of this time position). + + int (*FindTempoTimeSigMarker)(ReaProject* project, double time); +#endif + +#if defined(REAPERAPI_WANT_format_timestr) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// format_timestr +// Format tpos (which is time in seconds) as hh:mm:ss.sss. See format_timestr_pos, format_timestr_len. + + void (*format_timestr)(double tpos, char* buf, int buf_sz); +#endif + +#if defined(REAPERAPI_WANT_format_timestr_len) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// format_timestr_len +// time formatting mode overrides: -1=proj default. +// 0=time +// 1=measures.beats + time +// 2=measures.beats +// 3=seconds +// 4=samples +// 5=h:m:s:f +// offset is start of where the length will be calculated from + + void (*format_timestr_len)(double tpos, char* buf, int buf_sz, double offset, int modeoverride); +#endif + +#if defined(REAPERAPI_WANT_format_timestr_pos) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// format_timestr_pos +// time formatting mode overrides: -1=proj default. +// 0=time +// 1=measures.beats + time +// 2=measures.beats +// 3=seconds +// 4=samples +// 5=h:m:s:f +// + + void (*format_timestr_pos)(double tpos, char* buf, int buf_sz, int modeoverride); +#endif + +#if defined(REAPERAPI_WANT_FreeHeapPtr) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// FreeHeapPtr +// free heap memory returned from a Reaper API function + + void (*FreeHeapPtr)(void* ptr); +#endif + +#if defined(REAPERAPI_WANT_genGuid) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// genGuid + + void (*genGuid)(GUID* g); +#endif + +#if defined(REAPERAPI_WANT_get_config_var) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// get_config_var + + void* (*get_config_var)(const char* name, int* szOut); +#endif + +#if defined(REAPERAPI_WANT_get_config_var_string) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// get_config_var_string +// gets ini configuration variable value as string + + bool (*get_config_var_string)(const char* name, char* bufOut, int bufOut_sz); +#endif + +#if defined(REAPERAPI_WANT_get_ini_file) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// get_ini_file +// Get reaper.ini full filename. + + const char* (*get_ini_file)(); +#endif + +#if defined(REAPERAPI_WANT_get_midi_config_var) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// get_midi_config_var +// Deprecated. + + void* (*get_midi_config_var)(const char* name, int* szOut); +#endif + +#if defined(REAPERAPI_WANT_GetActionShortcutDesc) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetActionShortcutDesc +// Get the text description of a specific shortcut for the given command ID. +// See CountActionShortcuts,DeleteActionShortcut,DoActionShortcutDialog. + + bool (*GetActionShortcutDesc)(KbdSectionInfo* section, int cmdID, int shortcutidx, char* desc, int desclen); +#endif + +#if defined(REAPERAPI_WANT_GetActiveTake) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetActiveTake +// get the active take in this item + + MediaItem_Take* (*GetActiveTake)(MediaItem* item); +#endif + +#if defined(REAPERAPI_WANT_GetAllProjectPlayStates) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetAllProjectPlayStates +// returns the bitwise OR of all project play states (1=playing, 2=pause, 4=recording) + + int (*GetAllProjectPlayStates)(ReaProject* ignoreProject); +#endif + +#if defined(REAPERAPI_WANT_GetAppVersion) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetAppVersion +// Returns app version which may include an OS/arch signifier, such as: "6.17" (windows 32-bit), "6.17/x64" (windows 64-bit), "6.17/OSX64" (macOS 64-bit Intel), "6.17/OSX" (macOS 32-bit), "6.17/macOS-arm64", "6.17/linux-x86_64", "6.17/linux-i686", "6.17/linux-aarch64", "6.17/linux-armv7l", etc + + const char* (*GetAppVersion)(); +#endif + +#if defined(REAPERAPI_WANT_GetArmedCommand) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetArmedCommand +// gets the currently armed command and section name (returns 0 if nothing armed). section name is empty-string for main section. + + int (*GetArmedCommand)(char* secOut, int secOut_sz); +#endif + +#if defined(REAPERAPI_WANT_GetAudioAccessorEndTime) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetAudioAccessorEndTime +// Get the end time of the audio that can be returned from this accessor. See CreateTakeAudioAccessor, CreateTrackAudioAccessor, DestroyAudioAccessor, AudioAccessorStateChanged, GetAudioAccessorStartTime, GetAudioAccessorSamples. + + double (*GetAudioAccessorEndTime)(AudioAccessor* accessor); +#endif + +#if defined(REAPERAPI_WANT_GetAudioAccessorHash) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetAudioAccessorHash +// Deprecated. See AudioAccessorStateChanged instead. + + void (*GetAudioAccessorHash)(AudioAccessor* accessor, char* hashNeed128); +#endif + +#if defined(REAPERAPI_WANT_GetAudioAccessorSamples) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetAudioAccessorSamples +// Get a block of samples from the audio accessor. Samples are extracted immediately pre-FX, and returned interleaved (first sample of first channel, first sample of second channel...). Returns 0 if no audio, 1 if audio, -1 on error. See CreateTakeAudioAccessor, CreateTrackAudioAccessor, DestroyAudioAccessor, AudioAccessorStateChanged, GetAudioAccessorStartTime, GetAudioAccessorEndTime.// +// +// This function has special handling in Python, and only returns two objects, the API function return value, and the sample buffer. Example usage: +// +// <code>tr = RPR_GetTrack(0, 0) +// aa = RPR_CreateTrackAudioAccessor(tr) +// buf = list([0]*2*1024) # 2 channels, 1024 samples each, initialized to zero +// pos = 0.0 +// (ret, buf) = GetAudioAccessorSamples(aa, 44100, 2, pos, 1024, buf) +// # buf now holds the first 2*1024 audio samples from the track. +// # typically GetAudioAccessorSamples() would be called within a loop, increasing pos each time. +// </code> + + int (*GetAudioAccessorSamples)(AudioAccessor* accessor, int samplerate, int numchannels, double starttime_sec, int numsamplesperchannel, double* samplebuffer); +#endif + +#if defined(REAPERAPI_WANT_GetAudioAccessorStartTime) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetAudioAccessorStartTime +// Get the start time of the audio that can be returned from this accessor. See CreateTakeAudioAccessor, CreateTrackAudioAccessor, DestroyAudioAccessor, AudioAccessorStateChanged, GetAudioAccessorEndTime, GetAudioAccessorSamples. + + double (*GetAudioAccessorStartTime)(AudioAccessor* accessor); +#endif + +#if defined(REAPERAPI_WANT_GetAudioDeviceInfo) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetAudioDeviceInfo +// get information about the currently open audio device. attribute can be MODE, IDENT_IN, IDENT_OUT, BSIZE, SRATE, BPS. returns false if unknown attribute or device not open. + + bool (*GetAudioDeviceInfo)(const char* attribute, char* descOut, int descOut_sz); +#endif + +#if defined(REAPERAPI_WANT_GetColorTheme) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetColorTheme +// Deprecated, see GetColorThemeStruct. + + INT_PTR (*GetColorTheme)(int idx, int defval); +#endif + +#if defined(REAPERAPI_WANT_GetColorThemeStruct) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetColorThemeStruct +// returns the whole color theme (icontheme.h) and the size + + void* (*GetColorThemeStruct)(int* szOut); +#endif + +#if defined(REAPERAPI_WANT_GetConfigWantsDock) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetConfigWantsDock +// gets the dock ID desired by ident_str, if any + + int (*GetConfigWantsDock)(const char* ident_str); +#endif + +#if defined(REAPERAPI_WANT_GetContextMenu) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetContextMenu +// gets context menus. submenu 0:trackctl, 1:mediaitems, 2:ruler, 3:empty track area + + HMENU (*GetContextMenu)(int idx); +#endif + +#if defined(REAPERAPI_WANT_GetCurrentProjectInLoadSave) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetCurrentProjectInLoadSave +// returns current project if in load/save (usually only used from project_config_extension_t) + + ReaProject* (*GetCurrentProjectInLoadSave)(); +#endif + +#if defined(REAPERAPI_WANT_GetCursorContext) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetCursorContext +// return the current cursor context: 0 if track panels, 1 if items, 2 if envelopes, otherwise unknown + + int (*GetCursorContext)(); +#endif + +#if defined(REAPERAPI_WANT_GetCursorContext2) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetCursorContext2 +// 0 if track panels, 1 if items, 2 if envelopes, otherwise unknown (unlikely when want_last_valid is true) + + int (*GetCursorContext2)(bool want_last_valid); +#endif + +#if defined(REAPERAPI_WANT_GetCursorPosition) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetCursorPosition +// edit cursor position + + double (*GetCursorPosition)(); +#endif + +#if defined(REAPERAPI_WANT_GetCursorPositionEx) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetCursorPositionEx +// edit cursor position + + double (*GetCursorPositionEx)(ReaProject* proj); +#endif + +#if defined(REAPERAPI_WANT_GetDisplayedMediaItemColor) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetDisplayedMediaItemColor +// see GetDisplayedMediaItemColor2. + + int (*GetDisplayedMediaItemColor)(MediaItem* item); +#endif + +#if defined(REAPERAPI_WANT_GetDisplayedMediaItemColor2) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetDisplayedMediaItemColor2 +// Returns the custom take, item, or track color that is used (according to the user preference) to color the media item. The returned color is OS dependent|0x01000000 (i.e. ColorToNative(r,g,b)|0x01000000), so a return of zero means "no color", not black. + + int (*GetDisplayedMediaItemColor2)(MediaItem* item, MediaItem_Take* take); +#endif + +#if defined(REAPERAPI_WANT_GetEnvelopeInfo_Value) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetEnvelopeInfo_Value +// Gets an envelope numerical-value attribute: +// I_TCPY : int : Y offset of envelope relative to parent track (may be separate lane or overlap with track contents) +// I_TCPH : int : visible height of envelope +// I_TCPY_USED : int : Y offset of envelope relative to parent track, exclusive of padding +// I_TCPH_USED : int : visible height of envelope, exclusive of padding +// P_TRACK : MediaTrack * : parent track pointer (if any) +// P_DESTTRACK : MediaTrack * : destination track pointer, if on a send +// P_ITEM : MediaItem * : parent item pointer (if any) +// P_TAKE : MediaItem_Take * : parent take pointer (if any) +// I_SEND_IDX : int : 1-based index of send in P_TRACK, or 0 if not a send +// I_HWOUT_IDX : int : 1-based index of hardware output in P_TRACK or 0 if not a hardware output +// I_RECV_IDX : int : 1-based index of receive in P_DESTTRACK or 0 if not a send/receive +// + + double (*GetEnvelopeInfo_Value)(TrackEnvelope* env, const char* parmname); +#endif + +#if defined(REAPERAPI_WANT_GetEnvelopeName) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetEnvelopeName + + bool (*GetEnvelopeName)(TrackEnvelope* env, char* bufOut, int bufOut_sz); +#endif + +#if defined(REAPERAPI_WANT_GetEnvelopePoint) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetEnvelopePoint +// Get the attributes of an envelope point. See GetEnvelopePointEx. + + bool (*GetEnvelopePoint)(TrackEnvelope* envelope, int ptidx, double* timeOut, double* valueOut, int* shapeOut, double* tensionOut, bool* selectedOut); +#endif + +#if defined(REAPERAPI_WANT_GetEnvelopePointByTime) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetEnvelopePointByTime +// Returns the envelope point at or immediately prior to the given time position. See GetEnvelopePointByTimeEx. + + int (*GetEnvelopePointByTime)(TrackEnvelope* envelope, double time); +#endif + +#if defined(REAPERAPI_WANT_GetEnvelopePointByTimeEx) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetEnvelopePointByTimeEx +// Returns the envelope point at or immediately prior to the given time position. +// autoitem_idx=-1 for the underlying envelope, 0 for the first automation item on the envelope, etc. +// For automation items, pass autoitem_idx|0x10000000 to base ptidx on the number of points in one full loop iteration, +// even if the automation item is trimmed so that not all points are visible. +// Otherwise, ptidx will be based on the number of visible points in the automation item, including all loop iterations. +// See GetEnvelopePointEx, SetEnvelopePointEx, InsertEnvelopePointEx, DeleteEnvelopePointEx. + + int (*GetEnvelopePointByTimeEx)(TrackEnvelope* envelope, int autoitem_idx, double time); +#endif + +#if defined(REAPERAPI_WANT_GetEnvelopePointEx) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetEnvelopePointEx +// Get the attributes of an envelope point. +// autoitem_idx=-1 for the underlying envelope, 0 for the first automation item on the envelope, etc. +// For automation items, pass autoitem_idx|0x10000000 to base ptidx on the number of points in one full loop iteration, +// even if the automation item is trimmed so that not all points are visible. +// Otherwise, ptidx will be based on the number of visible points in the automation item, including all loop iterations. +// See CountEnvelopePointsEx, SetEnvelopePointEx, InsertEnvelopePointEx, DeleteEnvelopePointEx. + + bool (*GetEnvelopePointEx)(TrackEnvelope* envelope, int autoitem_idx, int ptidx, double* timeOut, double* valueOut, int* shapeOut, double* tensionOut, bool* selectedOut); +#endif + +#if defined(REAPERAPI_WANT_GetEnvelopeScalingMode) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetEnvelopeScalingMode +// Returns the envelope scaling mode: 0=no scaling, 1=fader scaling. All API functions deal with raw envelope point values, to convert raw from/to scaled values see ScaleFromEnvelopeMode, ScaleToEnvelopeMode. + + int (*GetEnvelopeScalingMode)(TrackEnvelope* env); +#endif + +#if defined(REAPERAPI_WANT_GetEnvelopeStateChunk) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetEnvelopeStateChunk +// Gets the RPPXML state of an envelope, returns true if successful. Undo flag is a performance/caching hint. + + bool (*GetEnvelopeStateChunk)(TrackEnvelope* env, char* strNeedBig, int strNeedBig_sz, bool isundoOptional); +#endif + +#if defined(REAPERAPI_WANT_GetExePath) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetExePath +// returns path of REAPER.exe (not including EXE), i.e. C:\Program Files\REAPER + + const char* (*GetExePath)(); +#endif + +#if defined(REAPERAPI_WANT_GetExtState) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetExtState +// Get the extended state value for a specific section and key. See SetExtState, DeleteExtState, HasExtState. + + const char* (*GetExtState)(const char* section, const char* key); +#endif + +#if defined(REAPERAPI_WANT_GetFocusedFX) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetFocusedFX +// This function is deprecated (returns GetFocusedFX2()&3), see GetFocusedFX2. + + int (*GetFocusedFX)(int* tracknumberOut, int* itemnumberOut, int* fxnumberOut); +#endif + +#if defined(REAPERAPI_WANT_GetFocusedFX2) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetFocusedFX2 +// Return value has 1 set if track FX, 2 if take/item FX, 4 set if FX is no longer focused but still open. tracknumber==0 means the master track, 1 means track 1, etc. itemnumber is zero-based (or -1 if not an item). For interpretation of fxnumber, see GetLastTouchedFX. + + int (*GetFocusedFX2)(int* tracknumberOut, int* itemnumberOut, int* fxnumberOut); +#endif + +#if defined(REAPERAPI_WANT_GetFreeDiskSpaceForRecordPath) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetFreeDiskSpaceForRecordPath +// returns free disk space in megabytes, pathIdx 0 for normal, 1 for alternate. + + int (*GetFreeDiskSpaceForRecordPath)(ReaProject* proj, int pathidx); +#endif + +#if defined(REAPERAPI_WANT_GetFXEnvelope) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetFXEnvelope +// Returns the FX parameter envelope. If the envelope does not exist and create=true, the envelope will be created. + + TrackEnvelope* (*GetFXEnvelope)(MediaTrack* track, int fxindex, int parameterindex, bool create); +#endif + +#if defined(REAPERAPI_WANT_GetGlobalAutomationOverride) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetGlobalAutomationOverride +// return -1=no override, 0=trim/read, 1=read, 2=touch, 3=write, 4=latch, 5=bypass + + int (*GetGlobalAutomationOverride)(); +#endif + +#if defined(REAPERAPI_WANT_GetHZoomLevel) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetHZoomLevel +// returns pixels/second + + double (*GetHZoomLevel)(); +#endif + +#if defined(REAPERAPI_WANT_GetIconThemePointer) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetIconThemePointer +// returns a named icontheme entry + + void* (*GetIconThemePointer)(const char* name); +#endif + +#if defined(REAPERAPI_WANT_GetIconThemePointerForDPI) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetIconThemePointerForDPI +// returns a named icontheme entry for a given DPI-scaling (256=1:1). Note: the return value should not be stored, it should be queried at each paint! Querying name=NULL returns the start of the structure + + void* (*GetIconThemePointerForDPI)(const char* name, int dpisc); +#endif + +#if defined(REAPERAPI_WANT_GetIconThemeStruct) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetIconThemeStruct +// returns a pointer to the icon theme (icontheme.h) and the size of that struct + + void* (*GetIconThemeStruct)(int* szOut); +#endif + +#if defined(REAPERAPI_WANT_GetInputChannelName) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetInputChannelName + + const char* (*GetInputChannelName)(int channelIndex); +#endif + +#if defined(REAPERAPI_WANT_GetInputOutputLatency) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetInputOutputLatency +// Gets the audio device input/output latency in samples + + void (*GetInputOutputLatency)(int* inputlatencyOut, int* outputLatencyOut); +#endif + +#if defined(REAPERAPI_WANT_GetItemEditingTime2) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetItemEditingTime2 +// returns time of relevant edit, set which_item to the pcm_source (if applicable), flags (if specified) will be set to 1 for edge resizing, 2 for fade change, 4 for item move, 8 for item slip edit (edit cursor time or start of item) + + double (*GetItemEditingTime2)(PCM_source** which_itemOut, int* flagsOut); +#endif + +#if defined(REAPERAPI_WANT_GetItemFromPoint) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetItemFromPoint +// Returns the first item at the screen coordinates specified. If allow_locked is false, locked items are ignored. If takeOutOptional specified, returns the take hit. See GetThingFromPoint. + + MediaItem* (*GetItemFromPoint)(int screen_x, int screen_y, bool allow_locked, MediaItem_Take** takeOutOptional); +#endif + +#if defined(REAPERAPI_WANT_GetItemProjectContext) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetItemProjectContext + + ReaProject* (*GetItemProjectContext)(MediaItem* item); +#endif + +#if defined(REAPERAPI_WANT_GetItemStateChunk) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetItemStateChunk +// Gets the RPPXML state of an item, returns true if successful. Undo flag is a performance/caching hint. + + bool (*GetItemStateChunk)(MediaItem* item, char* strNeedBig, int strNeedBig_sz, bool isundoOptional); +#endif + +#if defined(REAPERAPI_WANT_GetLastColorThemeFile) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetLastColorThemeFile + + const char* (*GetLastColorThemeFile)(); +#endif + +#if defined(REAPERAPI_WANT_GetLastMarkerAndCurRegion) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetLastMarkerAndCurRegion +// Get the last project marker before time, and/or the project region that includes time. markeridx and regionidx are returned not necessarily as the displayed marker/region index, but as the index that can be passed to EnumProjectMarkers. Either or both of markeridx and regionidx may be NULL. See EnumProjectMarkers. + + void (*GetLastMarkerAndCurRegion)(ReaProject* proj, double time, int* markeridxOut, int* regionidxOut); +#endif + +#if defined(REAPERAPI_WANT_GetLastTouchedFX) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetLastTouchedFX +// Returns true if the last touched FX parameter is valid, false otherwise. The low word of tracknumber is the 1-based track index -- 0 means the master track, 1 means track 1, etc. If the high word of tracknumber is nonzero, it refers to the 1-based item index (1 is the first item on the track, etc). For track FX, the low 24 bits of fxnumber refer to the FX index in the chain, and if the next 8 bits are 01, then the FX is record FX. For item FX, the low word defines the FX index in the chain, and the high word defines the take number. + + bool (*GetLastTouchedFX)(int* tracknumberOut, int* fxnumberOut, int* paramnumberOut); +#endif + +#if defined(REAPERAPI_WANT_GetLastTouchedTrack) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetLastTouchedTrack + + MediaTrack* (*GetLastTouchedTrack)(); +#endif + +#if defined(REAPERAPI_WANT_GetMainHwnd) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetMainHwnd + + HWND (*GetMainHwnd)(); +#endif + +#if defined(REAPERAPI_WANT_GetMasterMuteSoloFlags) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetMasterMuteSoloFlags +// &1=master mute,&2=master solo. This is deprecated as you can just query the master track as well. + + int (*GetMasterMuteSoloFlags)(); +#endif + +#if defined(REAPERAPI_WANT_GetMasterTrack) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetMasterTrack + + MediaTrack* (*GetMasterTrack)(ReaProject* proj); +#endif + +#if defined(REAPERAPI_WANT_GetMasterTrackVisibility) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetMasterTrackVisibility +// returns &1 if the master track is visible in the TCP, &2 if NOT visible in the mixer. See SetMasterTrackVisibility. + + int (*GetMasterTrackVisibility)(); +#endif + +#if defined(REAPERAPI_WANT_GetMaxMidiInputs) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetMaxMidiInputs +// returns max dev for midi inputs/outputs + + int (*GetMaxMidiInputs)(); +#endif + +#if defined(REAPERAPI_WANT_GetMaxMidiOutputs) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetMaxMidiOutputs + + int (*GetMaxMidiOutputs)(); +#endif + +#if defined(REAPERAPI_WANT_GetMediaFileMetadata) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetMediaFileMetadata +// Get text-based metadata from a media file for a given identifier. Call with identifier="" to list all identifiers contained in the file, separated by newlines. May return "[Binary data]" for metadata that REAPER doesn't handle. + + int (*GetMediaFileMetadata)(PCM_source* mediaSource, const char* identifier, char* bufOutNeedBig, int bufOutNeedBig_sz); +#endif + +#if defined(REAPERAPI_WANT_GetMediaItem) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetMediaItem +// get an item from a project by item count (zero-based) (proj=0 for active project) + + MediaItem* (*GetMediaItem)(ReaProject* proj, int itemidx); +#endif + +#if defined(REAPERAPI_WANT_GetMediaItem_Track) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetMediaItem_Track +// Get parent track of media item + + MediaTrack* (*GetMediaItem_Track)(MediaItem* item); +#endif + +#if defined(REAPERAPI_WANT_GetMediaItemInfo_Value) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetMediaItemInfo_Value +// Get media item numerical-value attributes. +// B_MUTE : bool * : muted (item solo overrides). setting this value will clear C_MUTE_SOLO. +// B_MUTE_ACTUAL : bool * : muted (ignores solo). setting this value will not affect C_MUTE_SOLO. +// C_MUTE_SOLO : char * : solo override (-1=soloed, 0=no override, 1=unsoloed). note that this API does not automatically unsolo other items when soloing (nor clear the unsolos when clearing the last soloed item), it must be done by the caller via action or via this API. +// B_LOOPSRC : bool * : loop source +// B_ALLTAKESPLAY : bool * : all takes play +// B_UISEL : bool * : selected in arrange view +// C_BEATATTACHMODE : char * : item timebase, -1=track or project default, 1=beats (position, length, rate), 2=beats (position only). for auto-stretch timebase: C_BEATATTACHMODE=1, C_AUTOSTRETCH=1 +// C_AUTOSTRETCH: : char * : auto-stretch at project tempo changes, 1=enabled, requires C_BEATATTACHMODE=1 +// C_LOCK : char * : locked, &1=locked +// D_VOL : double * : item volume, 0=-inf, 0.5=-6dB, 1=+0dB, 2=+6dB, etc +// D_POSITION : double * : item position in seconds +// D_LENGTH : double * : item length in seconds +// D_SNAPOFFSET : double * : item snap offset in seconds +// D_FADEINLEN : double * : item manual fadein length in seconds +// D_FADEOUTLEN : double * : item manual fadeout length in seconds +// D_FADEINDIR : double * : item fadein curvature, -1..1 +// D_FADEOUTDIR : double * : item fadeout curvature, -1..1 +// D_FADEINLEN_AUTO : double * : item auto-fadein length in seconds, -1=no auto-fadein +// D_FADEOUTLEN_AUTO : double * : item auto-fadeout length in seconds, -1=no auto-fadeout +// C_FADEINSHAPE : int * : fadein shape, 0..6, 0=linear +// C_FADEOUTSHAPE : int * : fadeout shape, 0..6, 0=linear +// I_GROUPID : int * : group ID, 0=no group +// I_LASTY : int * : Y-position (relative to top of track) in pixels (read-only) +// I_LASTH : int * : height in pixels (read-only) +// I_CUSTOMCOLOR : int * : custom color, OS dependent color|0x1000000 (i.e. ColorToNative(r,g,b)|0x1000000). If you do not |0x1000000, then it will not be used, but will store the color +// I_CURTAKE : int * : active take number +// IP_ITEMNUMBER : int : item number on this track (read-only, returns the item number directly) +// F_FREEMODE_Y : float * : free item positioning Y-position, 0=top of track, 1=bottom of track (will never be 1) +// F_FREEMODE_H : float * : free item positioning height, 0=no height, 1=full height of track (will never be 0) +// P_TRACK : MediaTrack * : (read-only) +// + + double (*GetMediaItemInfo_Value)(MediaItem* item, const char* parmname); +#endif + +#if defined(REAPERAPI_WANT_GetMediaItemNumTakes) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetMediaItemNumTakes + + int (*GetMediaItemNumTakes)(MediaItem* item); +#endif + +#if defined(REAPERAPI_WANT_GetMediaItemTake) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetMediaItemTake + + MediaItem_Take* (*GetMediaItemTake)(MediaItem* item, int tk); +#endif + +#if defined(REAPERAPI_WANT_GetMediaItemTake_Item) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetMediaItemTake_Item +// Get parent item of media item take + + MediaItem* (*GetMediaItemTake_Item)(MediaItem_Take* take); +#endif + +#if defined(REAPERAPI_WANT_GetMediaItemTake_Peaks) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetMediaItemTake_Peaks +// Gets block of peak samples to buf. Note that the peak samples are interleaved, but in two or three blocks (maximums, then minimums, then extra). Return value has 20 bits of returned sample count, then 4 bits of output_mode (0xf00000), then a bit to signify whether extra_type was available (0x1000000). extra_type can be 115 ('s') for spectral information, which will return peak samples as integers with the low 15 bits frequency, next 14 bits tonality. + + int (*GetMediaItemTake_Peaks)(MediaItem_Take* take, double peakrate, double starttime, int numchannels, int numsamplesperchannel, int want_extra_type, double* buf); +#endif + +#if defined(REAPERAPI_WANT_GetMediaItemTake_Source) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetMediaItemTake_Source +// Get media source of media item take + + PCM_source* (*GetMediaItemTake_Source)(MediaItem_Take* take); +#endif + +#if defined(REAPERAPI_WANT_GetMediaItemTake_Track) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetMediaItemTake_Track +// Get parent track of media item take + + MediaTrack* (*GetMediaItemTake_Track)(MediaItem_Take* take); +#endif + +#if defined(REAPERAPI_WANT_GetMediaItemTakeByGUID) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetMediaItemTakeByGUID + + MediaItem_Take* (*GetMediaItemTakeByGUID)(ReaProject* project, const GUID* guid); +#endif + +#if defined(REAPERAPI_WANT_GetMediaItemTakeInfo_Value) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetMediaItemTakeInfo_Value +// Get media item take numerical-value attributes. +// D_STARTOFFS : double * : start offset in source media, in seconds +// D_VOL : double * : take volume, 0=-inf, 0.5=-6dB, 1=+0dB, 2=+6dB, etc, negative if take polarity is flipped +// D_PAN : double * : take pan, -1..1 +// D_PANLAW : double * : take pan law, -1=default, 0.5=-6dB, 1.0=+0dB, etc +// D_PLAYRATE : double * : take playback rate, 0.5=half speed, 1=normal, 2=double speed, etc +// D_PITCH : double * : take pitch adjustment in semitones, -12=one octave down, 0=normal, +12=one octave up, etc +// B_PPITCH : bool * : preserve pitch when changing playback rate +// I_LASTY : int * : Y-position (relative to top of track) in pixels (read-only) +// I_LASTH : int * : height in pixels (read-only) +// I_CHANMODE : int * : channel mode, 0=normal, 1=reverse stereo, 2=downmix, 3=left, 4=right +// I_PITCHMODE : int * : pitch shifter mode, -1=projext default, otherwise high 2 bytes=shifter, low 2 bytes=parameter +// I_CUSTOMCOLOR : int * : custom color, OS dependent color|0x1000000 (i.e. ColorToNative(r,g,b)|0x1000000). If you do not |0x1000000, then it will not be used, but will store the color +// IP_TAKENUMBER : int : take number (read-only, returns the take number directly) +// P_TRACK : pointer to MediaTrack (read-only) +// P_ITEM : pointer to MediaItem (read-only) +// P_SOURCE : PCM_source *. Note that if setting this, you should first retrieve the old source, set the new, THEN delete the old. +// + + double (*GetMediaItemTakeInfo_Value)(MediaItem_Take* take, const char* parmname); +#endif + +#if defined(REAPERAPI_WANT_GetMediaItemTrack) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetMediaItemTrack + + MediaTrack* (*GetMediaItemTrack)(MediaItem* item); +#endif + +#if defined(REAPERAPI_WANT_GetMediaSourceFileName) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetMediaSourceFileName +// Copies the media source filename to filenamebuf. Note that in-project MIDI media sources have no associated filename. See GetMediaSourceParent. + + void (*GetMediaSourceFileName)(PCM_source* source, char* filenamebufOut, int filenamebufOut_sz); +#endif + +#if defined(REAPERAPI_WANT_GetMediaSourceLength) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetMediaSourceLength +// Returns the length of the source media. If the media source is beat-based, the length will be in quarter notes, otherwise it will be in seconds. + + double (*GetMediaSourceLength)(PCM_source* source, bool* lengthIsQNOut); +#endif + +#if defined(REAPERAPI_WANT_GetMediaSourceNumChannels) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetMediaSourceNumChannels +// Returns the number of channels in the source media. + + int (*GetMediaSourceNumChannels)(PCM_source* source); +#endif + +#if defined(REAPERAPI_WANT_GetMediaSourceParent) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetMediaSourceParent +// Returns the parent source, or NULL if src is the root source. This can be used to retrieve the parent properties of sections or reversed sources for example. + + PCM_source* (*GetMediaSourceParent)(PCM_source* src); +#endif + +#if defined(REAPERAPI_WANT_GetMediaSourceSampleRate) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetMediaSourceSampleRate +// Returns the sample rate. MIDI source media will return zero. + + int (*GetMediaSourceSampleRate)(PCM_source* source); +#endif + +#if defined(REAPERAPI_WANT_GetMediaSourceType) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetMediaSourceType +// copies the media source type ("WAV", "MIDI", etc) to typebuf + + void (*GetMediaSourceType)(PCM_source* source, char* typebufOut, int typebufOut_sz); +#endif + +#if defined(REAPERAPI_WANT_GetMediaTrackInfo_Value) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetMediaTrackInfo_Value +// Get track numerical-value attributes. +// B_MUTE : bool * : muted +// B_PHASE : bool * : track phase inverted +// B_RECMON_IN_EFFECT : bool * : record monitoring in effect (current audio-thread playback state, read-only) +// IP_TRACKNUMBER : int : track number 1-based, 0=not found, -1=master track (read-only, returns the int directly) +// I_SOLO : int * : soloed, 0=not soloed, 1=soloed, 2=soloed in place, 5=safe soloed, 6=safe soloed in place +// B_SOLO_DEFEAT : bool * : when set, if anything else is soloed and this track is not muted, this track acts soloed +// I_FXEN : int * : fx enabled, 0=bypassed, !0=fx active +// I_RECARM : int * : record armed, 0=not record armed, 1=record armed +// I_RECINPUT : int * : record input, <0=no input. if 4096 set, input is MIDI and low 5 bits represent channel (0=all, 1-16=only chan), next 6 bits represent physical input (63=all, 62=VKB). If 4096 is not set, low 10 bits (0..1023) are input start channel (ReaRoute/Loopback start at 512). If 2048 is set, input is multichannel input (using track channel count), or if 1024 is set, input is stereo input, otherwise input is mono. +// I_RECMODE : int * : record mode, 0=input, 1=stereo out, 2=none, 3=stereo out w/latency compensation, 4=midi output, 5=mono out, 6=mono out w/ latency compensation, 7=midi overdub, 8=midi replace +// I_RECMON : int * : record monitoring, 0=off, 1=normal, 2=not when playing (tape style) +// I_RECMONITEMS : int * : monitor items while recording, 0=off, 1=on +// B_AUTO_RECARM : bool * : automatically set record arm when selected (does not immediately affect recarm state, script should set directly if desired) +// I_VUMODE : int * : track vu mode, &1:disabled, &30==0:stereo peaks, &30==2:multichannel peaks, &30==4:stereo RMS, &30==8:combined RMS, &30==12:LUFS-M, &30==16:LUFS-S (readout=max), &30==20:LUFS-S (readout=current), &32:LUFS calculation on channels 1+2 only +// I_AUTOMODE : int * : track automation mode, 0=trim/off, 1=read, 2=touch, 3=write, 4=latch +// I_NCHAN : int * : number of track channels, 2-64, even numbers only +// I_SELECTED : int * : track selected, 0=unselected, 1=selected +// I_WNDH : int * : current TCP window height in pixels including envelopes (read-only) +// I_TCPH : int * : current TCP window height in pixels not including envelopes (read-only) +// I_TCPY : int * : current TCP window Y-position in pixels relative to top of arrange view (read-only) +// I_MCPX : int * : current MCP X-position in pixels relative to mixer container (read-only) +// I_MCPY : int * : current MCP Y-position in pixels relative to mixer container (read-only) +// I_MCPW : int * : current MCP width in pixels (read-only) +// I_MCPH : int * : current MCP height in pixels (read-only) +// I_FOLDERDEPTH : int * : folder depth change, 0=normal, 1=track is a folder parent, -1=track is the last in the innermost folder, -2=track is the last in the innermost and next-innermost folders, etc +// I_FOLDERCOMPACT : int * : folder compacted state (only valid on folders), 0=normal, 1=small, 2=tiny children +// I_MIDIHWOUT : int * : track midi hardware output index, <0=disabled, low 5 bits are which channels (0=all, 1-16), next 5 bits are output device index (0-31) +// I_PERFFLAGS : int * : track performance flags, &1=no media buffering, &2=no anticipative FX +// I_CUSTOMCOLOR : int * : custom color, OS dependent color|0x1000000 (i.e. ColorToNative(r,g,b)|0x1000000). If you do not |0x1000000, then it will not be used, but will store the color +// I_HEIGHTOVERRIDE : int * : custom height override for TCP window, 0 for none, otherwise size in pixels +// B_HEIGHTLOCK : bool * : track height lock (must set I_HEIGHTOVERRIDE before locking) +// D_VOL : double * : trim volume of track, 0=-inf, 0.5=-6dB, 1=+0dB, 2=+6dB, etc +// D_PAN : double * : trim pan of track, -1..1 +// D_WIDTH : double * : width of track, -1..1 +// D_DUALPANL : double * : dualpan position 1, -1..1, only if I_PANMODE==6 +// D_DUALPANR : double * : dualpan position 2, -1..1, only if I_PANMODE==6 +// I_PANMODE : int * : pan mode, 0=classic 3.x, 3=new balance, 5=stereo pan, 6=dual pan +// D_PANLAW : double * : pan law of track, <0=project default, 1=+0dB, etc +// P_ENV:<envchunkname or P_ENV:{GUID... : TrackEnvelope * : (read-only) chunkname can be <VOLENV, <PANENV, etc; GUID is the stringified envelope GUID. +// B_SHOWINMIXER : bool * : track control panel visible in mixer (do not use on master track) +// B_SHOWINTCP : bool * : track control panel visible in arrange view (do not use on master track) +// B_MAINSEND : bool * : track sends audio to parent +// C_MAINSEND_OFFS : char * : channel offset of track send to parent +// C_MAINSEND_NCH : char * : channel count of track send to parent (0=use all child track channels, 1=use one channel only) +// B_FREEMODE : bool * : track free item positioning enabled (call UpdateTimeline() after changing) +// C_BEATATTACHMODE : char * : track timebase, -1=project default, 0=time, 1=beats (position, length, rate), 2=beats (position only) +// F_MCP_FXSEND_SCALE : float * : scale of fx+send area in MCP (0=minimum allowed, 1=maximum allowed) +// F_MCP_FXPARM_SCALE : float * : scale of fx parameter area in MCP (0=minimum allowed, 1=maximum allowed) +// F_MCP_SENDRGN_SCALE : float * : scale of send area as proportion of the fx+send total area (0=minimum allowed, 1=maximum allowed) +// F_TCP_FXPARM_SCALE : float * : scale of TCP parameter area when TCP FX are embedded (0=min allowed, default, 1=max allowed) +// I_PLAY_OFFSET_FLAG : int * : track media playback offset state, &1=bypassed, &2=offset value is measured in samples (otherwise measured in seconds) +// D_PLAY_OFFSET : double * : track media playback offset, units depend on I_PLAY_OFFSET_FLAG +// P_PARTRACK : MediaTrack * : parent track (read-only) +// P_PROJECT : ReaProject * : parent project (read-only) +// + + double (*GetMediaTrackInfo_Value)(MediaTrack* tr, const char* parmname); +#endif + +#if defined(REAPERAPI_WANT_GetMIDIInputName) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetMIDIInputName +// returns true if device present + + bool (*GetMIDIInputName)(int dev, char* nameout, int nameout_sz); +#endif + +#if defined(REAPERAPI_WANT_GetMIDIOutputName) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetMIDIOutputName +// returns true if device present + + bool (*GetMIDIOutputName)(int dev, char* nameout, int nameout_sz); +#endif + +#if defined(REAPERAPI_WANT_GetMixerScroll) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetMixerScroll +// Get the leftmost track visible in the mixer + + MediaTrack* (*GetMixerScroll)(); +#endif + +#if defined(REAPERAPI_WANT_GetMouseModifier) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetMouseModifier +// Get the current mouse modifier assignment for a specific modifier key assignment, in a specific context. +// action will be filled in with the command ID number for a built-in mouse modifier +// or built-in REAPER command ID, or the custom action ID string. +// See SetMouseModifier for more information. +// + + void (*GetMouseModifier)(const char* context, int modifier_flag, char* actionOut, int actionOut_sz); +#endif + +#if defined(REAPERAPI_WANT_GetMousePosition) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetMousePosition +// get mouse position in screen coordinates + + void (*GetMousePosition)(int* xOut, int* yOut); +#endif + +#if defined(REAPERAPI_WANT_GetNumAudioInputs) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetNumAudioInputs +// Return number of normal audio hardware inputs available + + int (*GetNumAudioInputs)(); +#endif + +#if defined(REAPERAPI_WANT_GetNumAudioOutputs) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetNumAudioOutputs +// Return number of normal audio hardware outputs available + + int (*GetNumAudioOutputs)(); +#endif + +#if defined(REAPERAPI_WANT_GetNumMIDIInputs) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetNumMIDIInputs +// returns max number of real midi hardware inputs + + int (*GetNumMIDIInputs)(); +#endif + +#if defined(REAPERAPI_WANT_GetNumMIDIOutputs) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetNumMIDIOutputs +// returns max number of real midi hardware outputs + + int (*GetNumMIDIOutputs)(); +#endif + +#if defined(REAPERAPI_WANT_GetNumTakeMarkers) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetNumTakeMarkers +// Returns number of take markers. See GetTakeMarker, SetTakeMarker, DeleteTakeMarker + + int (*GetNumTakeMarkers)(MediaItem_Take* take); +#endif + +#if defined(REAPERAPI_WANT_GetNumTracks) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetNumTracks + + int (*GetNumTracks)(); +#endif + +#if defined(REAPERAPI_WANT_GetOS) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetOS +// Returns "Win32", "Win64", "OSX32", "OSX64", "macOS-arm64", or "Other". + + const char* (*GetOS)(); +#endif + +#if defined(REAPERAPI_WANT_GetOutputChannelName) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetOutputChannelName + + const char* (*GetOutputChannelName)(int channelIndex); +#endif + +#if defined(REAPERAPI_WANT_GetOutputLatency) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetOutputLatency +// returns output latency in seconds + + double (*GetOutputLatency)(); +#endif + +#if defined(REAPERAPI_WANT_GetParentTrack) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetParentTrack + + MediaTrack* (*GetParentTrack)(MediaTrack* track); +#endif + +#if defined(REAPERAPI_WANT_GetPeakFileName) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetPeakFileName +// get the peak file name for a given file (can be either filename.reapeaks,or a hashed filename in another path) + + void (*GetPeakFileName)(const char* fn, char* bufOut, int bufOut_sz); +#endif + +#if defined(REAPERAPI_WANT_GetPeakFileNameEx) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetPeakFileNameEx +// get the peak file name for a given file (can be either filename.reapeaks,or a hashed filename in another path) + + void (*GetPeakFileNameEx)(const char* fn, char* buf, int buf_sz, bool forWrite); +#endif + +#if defined(REAPERAPI_WANT_GetPeakFileNameEx2) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetPeakFileNameEx2 +// Like GetPeakFileNameEx, but you can specify peaksfileextension such as ".reapeaks" + + void (*GetPeakFileNameEx2)(const char* fn, char* buf, int buf_sz, bool forWrite, const char* peaksfileextension); +#endif + +#if defined(REAPERAPI_WANT_GetPeaksBitmap) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetPeaksBitmap +// see note in reaper_plugin.h about PCM_source_peaktransfer_t::samplerate + + void* (*GetPeaksBitmap)(PCM_source_peaktransfer_t* pks, double maxamp, int w, int h, LICE_IBitmap* bmp); +#endif + +#if defined(REAPERAPI_WANT_GetPlayPosition) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetPlayPosition +// returns latency-compensated actual-what-you-hear position + + double (*GetPlayPosition)(); +#endif + +#if defined(REAPERAPI_WANT_GetPlayPosition2) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetPlayPosition2 +// returns position of next audio block being processed + + double (*GetPlayPosition2)(); +#endif + +#if defined(REAPERAPI_WANT_GetPlayPosition2Ex) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetPlayPosition2Ex +// returns position of next audio block being processed + + double (*GetPlayPosition2Ex)(ReaProject* proj); +#endif + +#if defined(REAPERAPI_WANT_GetPlayPositionEx) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetPlayPositionEx +// returns latency-compensated actual-what-you-hear position + + double (*GetPlayPositionEx)(ReaProject* proj); +#endif + +#if defined(REAPERAPI_WANT_GetPlayState) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetPlayState +// &1=playing,&2=pause,&=4 is recording + + int (*GetPlayState)(); +#endif + +#if defined(REAPERAPI_WANT_GetPlayStateEx) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetPlayStateEx +// &1=playing,&2=pause,&=4 is recording + + int (*GetPlayStateEx)(ReaProject* proj); +#endif + +#if defined(REAPERAPI_WANT_GetPreferredDiskReadMode) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetPreferredDiskReadMode +// Gets user configured preferred disk read mode. mode/nb/bs are all parameters that should be passed to WDL_FileRead, see for more information. + + void (*GetPreferredDiskReadMode)(int* mode, int* nb, int* bs); +#endif + +#if defined(REAPERAPI_WANT_GetPreferredDiskReadModePeak) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetPreferredDiskReadModePeak +// Gets user configured preferred disk read mode for use when building peaks. mode/nb/bs are all parameters that should be passed to WDL_FileRead, see for more information. + + void (*GetPreferredDiskReadModePeak)(int* mode, int* nb, int* bs); +#endif + +#if defined(REAPERAPI_WANT_GetPreferredDiskWriteMode) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetPreferredDiskWriteMode +// Gets user configured preferred disk write mode. nb will receive two values, the initial and maximum write buffer counts. mode/nb/bs are all parameters that should be passed to WDL_FileWrite, see for more information. + + void (*GetPreferredDiskWriteMode)(int* mode, int* nb, int* bs); +#endif + +#if defined(REAPERAPI_WANT_GetProjectLength) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetProjectLength +// returns length of project (maximum of end of media item, markers, end of regions, tempo map + + double (*GetProjectLength)(ReaProject* proj); +#endif + +#if defined(REAPERAPI_WANT_GetProjectName) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetProjectName + + void (*GetProjectName)(ReaProject* proj, char* bufOut, int bufOut_sz); +#endif + +#if defined(REAPERAPI_WANT_GetProjectPath) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetProjectPath +// Get the project recording path. + + void (*GetProjectPath)(char* bufOut, int bufOut_sz); +#endif + +#if defined(REAPERAPI_WANT_GetProjectPathEx) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetProjectPathEx +// Get the project recording path. + + void (*GetProjectPathEx)(ReaProject* proj, char* bufOut, int bufOut_sz); +#endif + +#if defined(REAPERAPI_WANT_GetProjectStateChangeCount) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetProjectStateChangeCount +// returns an integer that changes when the project state changes + + int (*GetProjectStateChangeCount)(ReaProject* proj); +#endif + +#if defined(REAPERAPI_WANT_GetProjectTimeOffset) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetProjectTimeOffset +// Gets project time offset in seconds (project settings - project start time). If rndframe is true, the offset is rounded to a multiple of the project frame size. + + double (*GetProjectTimeOffset)(ReaProject* proj, bool rndframe); +#endif + +#if defined(REAPERAPI_WANT_GetProjectTimeSignature) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetProjectTimeSignature +// deprecated + + void (*GetProjectTimeSignature)(double* bpmOut, double* bpiOut); +#endif + +#if defined(REAPERAPI_WANT_GetProjectTimeSignature2) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetProjectTimeSignature2 +// Gets basic time signature (beats per minute, numerator of time signature in bpi) +// this does not reflect tempo envelopes but is purely what is set in the project settings. + + void (*GetProjectTimeSignature2)(ReaProject* proj, double* bpmOut, double* bpiOut); +#endif + +#if defined(REAPERAPI_WANT_GetProjExtState) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetProjExtState +// Get the value previously associated with this extname and key, the last time the project was saved. See SetProjExtState, EnumProjExtState. + + int (*GetProjExtState)(ReaProject* proj, const char* extname, const char* key, char* valOutNeedBig, int valOutNeedBig_sz); +#endif + +#if defined(REAPERAPI_WANT_GetResourcePath) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetResourcePath +// returns path where ini files are stored, other things are in subdirectories. + + const char* (*GetResourcePath)(); +#endif + +#if defined(REAPERAPI_WANT_GetSelectedEnvelope) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetSelectedEnvelope +// get the currently selected envelope, returns NULL/nil if no envelope is selected + + TrackEnvelope* (*GetSelectedEnvelope)(ReaProject* proj); +#endif + +#if defined(REAPERAPI_WANT_GetSelectedMediaItem) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetSelectedMediaItem +// get a selected item by selected item count (zero-based) (proj=0 for active project) + + MediaItem* (*GetSelectedMediaItem)(ReaProject* proj, int selitem); +#endif + +#if defined(REAPERAPI_WANT_GetSelectedTrack) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetSelectedTrack +// Get a selected track from a project (proj=0 for active project) by selected track count (zero-based). This function ignores the master track, see GetSelectedTrack2. + + MediaTrack* (*GetSelectedTrack)(ReaProject* proj, int seltrackidx); +#endif + +#if defined(REAPERAPI_WANT_GetSelectedTrack2) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetSelectedTrack2 +// Get a selected track from a project (proj=0 for active project) by selected track count (zero-based). + + MediaTrack* (*GetSelectedTrack2)(ReaProject* proj, int seltrackidx, bool wantmaster); +#endif + +#if defined(REAPERAPI_WANT_GetSelectedTrackEnvelope) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetSelectedTrackEnvelope +// get the currently selected track envelope, returns NULL/nil if no envelope is selected + + TrackEnvelope* (*GetSelectedTrackEnvelope)(ReaProject* proj); +#endif + +#if defined(REAPERAPI_WANT_GetSet_ArrangeView2) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetSet_ArrangeView2 +// Gets or sets the arrange view start/end time for screen coordinates. use screen_x_start=screen_x_end=0 to use the full arrange view's start/end time + + void (*GetSet_ArrangeView2)(ReaProject* proj, bool isSet, int screen_x_start, int screen_x_end, double* start_timeInOut, double* end_timeInOut); +#endif + +#if defined(REAPERAPI_WANT_GetSet_LoopTimeRange) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetSet_LoopTimeRange + + void (*GetSet_LoopTimeRange)(bool isSet, bool isLoop, double* startOut, double* endOut, bool allowautoseek); +#endif + +#if defined(REAPERAPI_WANT_GetSet_LoopTimeRange2) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetSet_LoopTimeRange2 + + void (*GetSet_LoopTimeRange2)(ReaProject* proj, bool isSet, bool isLoop, double* startOut, double* endOut, bool allowautoseek); +#endif + +#if defined(REAPERAPI_WANT_GetSetAutomationItemInfo) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetSetAutomationItemInfo +// Get or set automation item information. autoitem_idx=0 for the first automation item on an envelope, 1 for the second item, etc. desc can be any of the following: +// D_POOL_ID : double * : automation item pool ID (as an integer); edits are propagated to all other automation items that share a pool ID +// D_POSITION : double * : automation item timeline position in seconds +// D_LENGTH : double * : automation item length in seconds +// D_STARTOFFS : double * : automation item start offset in seconds +// D_PLAYRATE : double * : automation item playback rate +// D_BASELINE : double * : automation item baseline value in the range [0,1] +// D_AMPLITUDE : double * : automation item amplitude in the range [-1,1] +// D_LOOPSRC : double * : nonzero if the automation item contents are looped +// D_UISEL : double * : nonzero if the automation item is selected in the arrange view +// D_POOL_QNLEN : double * : automation item pooled source length in quarter notes (setting will affect all pooled instances) +// + + double (*GetSetAutomationItemInfo)(TrackEnvelope* env, int autoitem_idx, const char* desc, double value, bool is_set); +#endif + +#if defined(REAPERAPI_WANT_GetSetAutomationItemInfo_String) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetSetAutomationItemInfo_String +// Get or set automation item information. autoitem_idx=0 for the first automation item on an envelope, 1 for the second item, etc. returns true on success. desc can be any of the following: +// P_POOL_NAME : char * : name of the underlying automation item pool +// P_POOL_EXT:xyz : char * : extension-specific persistent data +// + + bool (*GetSetAutomationItemInfo_String)(TrackEnvelope* env, int autoitem_idx, const char* desc, char* valuestrNeedBig, bool is_set); +#endif + +#if defined(REAPERAPI_WANT_GetSetEnvelopeInfo_String) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetSetEnvelopeInfo_String +// Gets/sets an attribute string: +// P_EXT:xyz : char * : extension-specific persistent data +// GUID : GUID * : 16-byte GUID, can query only, not set. If using a _String() function, GUID is a string {xyz-...}. +// + + bool (*GetSetEnvelopeInfo_String)(TrackEnvelope* env, const char* parmname, char* stringNeedBig, bool setNewValue); +#endif + +#if defined(REAPERAPI_WANT_GetSetEnvelopeState) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetSetEnvelopeState +// deprecated -- see SetEnvelopeStateChunk, GetEnvelopeStateChunk + + bool (*GetSetEnvelopeState)(TrackEnvelope* env, char* str, int str_sz); +#endif + +#if defined(REAPERAPI_WANT_GetSetEnvelopeState2) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetSetEnvelopeState2 +// deprecated -- see SetEnvelopeStateChunk, GetEnvelopeStateChunk + + bool (*GetSetEnvelopeState2)(TrackEnvelope* env, char* str, int str_sz, bool isundo); +#endif + +#if defined(REAPERAPI_WANT_GetSetItemState) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetSetItemState +// deprecated -- see SetItemStateChunk, GetItemStateChunk + + bool (*GetSetItemState)(MediaItem* item, char* str, int str_sz); +#endif + +#if defined(REAPERAPI_WANT_GetSetItemState2) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetSetItemState2 +// deprecated -- see SetItemStateChunk, GetItemStateChunk + + bool (*GetSetItemState2)(MediaItem* item, char* str, int str_sz, bool isundo); +#endif + +#if defined(REAPERAPI_WANT_GetSetMediaItemInfo) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetSetMediaItemInfo +// P_TRACK : MediaTrack * : (read-only) +// B_MUTE : bool * : muted (item solo overrides). setting this value will clear C_MUTE_SOLO. +// B_MUTE_ACTUAL : bool * : muted (ignores solo). setting this value will not affect C_MUTE_SOLO. +// C_MUTE_SOLO : char * : solo override (-1=soloed, 0=no override, 1=unsoloed). note that this API does not automatically unsolo other items when soloing (nor clear the unsolos when clearing the last soloed item), it must be done by the caller via action or via this API. +// B_LOOPSRC : bool * : loop source +// B_ALLTAKESPLAY : bool * : all takes play +// B_UISEL : bool * : selected in arrange view +// C_BEATATTACHMODE : char * : item timebase, -1=track or project default, 1=beats (position, length, rate), 2=beats (position only). for auto-stretch timebase: C_BEATATTACHMODE=1, C_AUTOSTRETCH=1 +// C_AUTOSTRETCH: : char * : auto-stretch at project tempo changes, 1=enabled, requires C_BEATATTACHMODE=1 +// C_LOCK : char * : locked, &1=locked +// D_VOL : double * : item volume, 0=-inf, 0.5=-6dB, 1=+0dB, 2=+6dB, etc +// D_POSITION : double * : item position in seconds +// D_LENGTH : double * : item length in seconds +// D_SNAPOFFSET : double * : item snap offset in seconds +// D_FADEINLEN : double * : item manual fadein length in seconds +// D_FADEOUTLEN : double * : item manual fadeout length in seconds +// D_FADEINDIR : double * : item fadein curvature, -1..1 +// D_FADEOUTDIR : double * : item fadeout curvature, -1..1 +// D_FADEINLEN_AUTO : double * : item auto-fadein length in seconds, -1=no auto-fadein +// D_FADEOUTLEN_AUTO : double * : item auto-fadeout length in seconds, -1=no auto-fadeout +// C_FADEINSHAPE : int * : fadein shape, 0..6, 0=linear +// C_FADEOUTSHAPE : int * : fadeout shape, 0..6, 0=linear +// I_GROUPID : int * : group ID, 0=no group +// I_LASTY : int * : Y-position (relative to top of track) in pixels (read-only) +// I_LASTH : int * : height in pixels (read-only) +// I_CUSTOMCOLOR : int * : custom color, OS dependent color|0x1000000 (i.e. ColorToNative(r,g,b)|0x1000000). If you do not |0x1000000, then it will not be used, but will store the color +// I_CURTAKE : int * : active take number +// IP_ITEMNUMBER : int : item number on this track (read-only, returns the item number directly) +// F_FREEMODE_Y : float * : free item positioning Y-position, 0=top of track, 1=bottom of track (will never be 1) +// F_FREEMODE_H : float * : free item positioning height, 0=no height, 1=full height of track (will never be 0) +// P_NOTES : char * : item note text (do not write to returned pointer, use setNewValue to update) +// P_EXT:xyz : char * : extension-specific persistent data +// GUID : GUID * : 16-byte GUID, can query or update. If using a _String() function, GUID is a string {xyz-...}. +// + + void* (*GetSetMediaItemInfo)(MediaItem* item, const char* parmname, void* setNewValue); +#endif + +#if defined(REAPERAPI_WANT_GetSetMediaItemInfo_String) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetSetMediaItemInfo_String +// Gets/sets an item attribute string: +// P_NOTES : char * : item note text (do not write to returned pointer, use setNewValue to update) +// P_EXT:xyz : char * : extension-specific persistent data +// GUID : GUID * : 16-byte GUID, can query or update. If using a _String() function, GUID is a string {xyz-...}. +// + + bool (*GetSetMediaItemInfo_String)(MediaItem* item, const char* parmname, char* stringNeedBig, bool setNewValue); +#endif + +#if defined(REAPERAPI_WANT_GetSetMediaItemTakeInfo) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetSetMediaItemTakeInfo +// P_TRACK : pointer to MediaTrack (read-only) +// P_ITEM : pointer to MediaItem (read-only) +// P_SOURCE : PCM_source *. Note that if setting this, you should first retrieve the old source, set the new, THEN delete the old. +// P_NAME : char * : take name +// P_EXT:xyz : char * : extension-specific persistent data +// GUID : GUID * : 16-byte GUID, can query or update. If using a _String() function, GUID is a string {xyz-...}. +// D_STARTOFFS : double * : start offset in source media, in seconds +// D_VOL : double * : take volume, 0=-inf, 0.5=-6dB, 1=+0dB, 2=+6dB, etc, negative if take polarity is flipped +// D_PAN : double * : take pan, -1..1 +// D_PANLAW : double * : take pan law, -1=default, 0.5=-6dB, 1.0=+0dB, etc +// D_PLAYRATE : double * : take playback rate, 0.5=half speed, 1=normal, 2=double speed, etc +// D_PITCH : double * : take pitch adjustment in semitones, -12=one octave down, 0=normal, +12=one octave up, etc +// B_PPITCH : bool * : preserve pitch when changing playback rate +// I_LASTY : int * : Y-position (relative to top of track) in pixels (read-only) +// I_LASTH : int * : height in pixels (read-only) +// I_CHANMODE : int * : channel mode, 0=normal, 1=reverse stereo, 2=downmix, 3=left, 4=right +// I_PITCHMODE : int * : pitch shifter mode, -1=projext default, otherwise high 2 bytes=shifter, low 2 bytes=parameter +// I_CUSTOMCOLOR : int * : custom color, OS dependent color|0x1000000 (i.e. ColorToNative(r,g,b)|0x1000000). If you do not |0x1000000, then it will not be used, but will store the color +// IP_TAKENUMBER : int : take number (read-only, returns the take number directly) +// + + void* (*GetSetMediaItemTakeInfo)(MediaItem_Take* tk, const char* parmname, void* setNewValue); +#endif + +#if defined(REAPERAPI_WANT_GetSetMediaItemTakeInfo_String) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetSetMediaItemTakeInfo_String +// Gets/sets a take attribute string: +// P_NAME : char * : take name +// P_EXT:xyz : char * : extension-specific persistent data +// GUID : GUID * : 16-byte GUID, can query or update. If using a _String() function, GUID is a string {xyz-...}. +// + + bool (*GetSetMediaItemTakeInfo_String)(MediaItem_Take* tk, const char* parmname, char* stringNeedBig, bool setNewValue); +#endif + +#if defined(REAPERAPI_WANT_GetSetMediaTrackInfo) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetSetMediaTrackInfo +// Get or set track attributes. +// P_PARTRACK : MediaTrack * : parent track (read-only) +// P_PROJECT : ReaProject * : parent project (read-only) +// P_NAME : char * : track name (on master returns NULL) +// P_ICON : const char * : track icon (full filename, or relative to resource_path/data/track_icons) +// P_MCP_LAYOUT : const char * : layout name +// P_RAZOREDITS : const char * : list of razor edit areas, as space-separated triples of start time, end time, and envelope GUID string. +// Example: "0.00 1.00 \"\" 0.00 1.00 "{xyz-...}" +// P_TCP_LAYOUT : const char * : layout name +// P_EXT:xyz : char * : extension-specific persistent data +// P_UI_RECT:tcp.mute : char * : read-only, allows querying screen position + size of track WALTER elements (tcp.size queries screen position and size of entire TCP, etc). +// GUID : GUID * : 16-byte GUID, can query or update. If using a _String() function, GUID is a string {xyz-...}. +// B_MUTE : bool * : muted +// B_PHASE : bool * : track phase inverted +// B_RECMON_IN_EFFECT : bool * : record monitoring in effect (current audio-thread playback state, read-only) +// IP_TRACKNUMBER : int : track number 1-based, 0=not found, -1=master track (read-only, returns the int directly) +// I_SOLO : int * : soloed, 0=not soloed, 1=soloed, 2=soloed in place, 5=safe soloed, 6=safe soloed in place +// B_SOLO_DEFEAT : bool * : when set, if anything else is soloed and this track is not muted, this track acts soloed +// I_FXEN : int * : fx enabled, 0=bypassed, !0=fx active +// I_RECARM : int * : record armed, 0=not record armed, 1=record armed +// I_RECINPUT : int * : record input, <0=no input. if 4096 set, input is MIDI and low 5 bits represent channel (0=all, 1-16=only chan), next 6 bits represent physical input (63=all, 62=VKB). If 4096 is not set, low 10 bits (0..1023) are input start channel (ReaRoute/Loopback start at 512). If 2048 is set, input is multichannel input (using track channel count), or if 1024 is set, input is stereo input, otherwise input is mono. +// I_RECMODE : int * : record mode, 0=input, 1=stereo out, 2=none, 3=stereo out w/latency compensation, 4=midi output, 5=mono out, 6=mono out w/ latency compensation, 7=midi overdub, 8=midi replace +// I_RECMON : int * : record monitoring, 0=off, 1=normal, 2=not when playing (tape style) +// I_RECMONITEMS : int * : monitor items while recording, 0=off, 1=on +// B_AUTO_RECARM : bool * : automatically set record arm when selected (does not immediately affect recarm state, script should set directly if desired) +// I_VUMODE : int * : track vu mode, &1:disabled, &30==0:stereo peaks, &30==2:multichannel peaks, &30==4:stereo RMS, &30==8:combined RMS, &30==12:LUFS-M, &30==16:LUFS-S (readout=max), &30==20:LUFS-S (readout=current), &32:LUFS calculation on channels 1+2 only +// I_AUTOMODE : int * : track automation mode, 0=trim/off, 1=read, 2=touch, 3=write, 4=latch +// I_NCHAN : int * : number of track channels, 2-64, even numbers only +// I_SELECTED : int * : track selected, 0=unselected, 1=selected +// I_WNDH : int * : current TCP window height in pixels including envelopes (read-only) +// I_TCPH : int * : current TCP window height in pixels not including envelopes (read-only) +// I_TCPY : int * : current TCP window Y-position in pixels relative to top of arrange view (read-only) +// I_MCPX : int * : current MCP X-position in pixels relative to mixer container (read-only) +// I_MCPY : int * : current MCP Y-position in pixels relative to mixer container (read-only) +// I_MCPW : int * : current MCP width in pixels (read-only) +// I_MCPH : int * : current MCP height in pixels (read-only) +// I_FOLDERDEPTH : int * : folder depth change, 0=normal, 1=track is a folder parent, -1=track is the last in the innermost folder, -2=track is the last in the innermost and next-innermost folders, etc +// I_FOLDERCOMPACT : int * : folder compacted state (only valid on folders), 0=normal, 1=small, 2=tiny children +// I_MIDIHWOUT : int * : track midi hardware output index, <0=disabled, low 5 bits are which channels (0=all, 1-16), next 5 bits are output device index (0-31) +// I_PERFFLAGS : int * : track performance flags, &1=no media buffering, &2=no anticipative FX +// I_CUSTOMCOLOR : int * : custom color, OS dependent color|0x1000000 (i.e. ColorToNative(r,g,b)|0x1000000). If you do not |0x1000000, then it will not be used, but will store the color +// I_HEIGHTOVERRIDE : int * : custom height override for TCP window, 0 for none, otherwise size in pixels +// B_HEIGHTLOCK : bool * : track height lock (must set I_HEIGHTOVERRIDE before locking) +// D_VOL : double * : trim volume of track, 0=-inf, 0.5=-6dB, 1=+0dB, 2=+6dB, etc +// D_PAN : double * : trim pan of track, -1..1 +// D_WIDTH : double * : width of track, -1..1 +// D_DUALPANL : double * : dualpan position 1, -1..1, only if I_PANMODE==6 +// D_DUALPANR : double * : dualpan position 2, -1..1, only if I_PANMODE==6 +// I_PANMODE : int * : pan mode, 0=classic 3.x, 3=new balance, 5=stereo pan, 6=dual pan +// D_PANLAW : double * : pan law of track, <0=project default, 1=+0dB, etc +// P_ENV:<envchunkname or P_ENV:{GUID... : TrackEnvelope * : (read-only) chunkname can be <VOLENV, <PANENV, etc; GUID is the stringified envelope GUID. +// B_SHOWINMIXER : bool * : track control panel visible in mixer (do not use on master track) +// B_SHOWINTCP : bool * : track control panel visible in arrange view (do not use on master track) +// B_MAINSEND : bool * : track sends audio to parent +// C_MAINSEND_OFFS : char * : channel offset of track send to parent +// C_MAINSEND_NCH : char * : channel count of track send to parent (0=use all child track channels, 1=use one channel only) +// B_FREEMODE : bool * : track free item positioning enabled (call UpdateTimeline() after changing) +// C_BEATATTACHMODE : char * : track timebase, -1=project default, 0=time, 1=beats (position, length, rate), 2=beats (position only) +// F_MCP_FXSEND_SCALE : float * : scale of fx+send area in MCP (0=minimum allowed, 1=maximum allowed) +// F_MCP_FXPARM_SCALE : float * : scale of fx parameter area in MCP (0=minimum allowed, 1=maximum allowed) +// F_MCP_SENDRGN_SCALE : float * : scale of send area as proportion of the fx+send total area (0=minimum allowed, 1=maximum allowed) +// F_TCP_FXPARM_SCALE : float * : scale of TCP parameter area when TCP FX are embedded (0=min allowed, default, 1=max allowed) +// I_PLAY_OFFSET_FLAG : int * : track media playback offset state, &1=bypassed, &2=offset value is measured in samples (otherwise measured in seconds) +// D_PLAY_OFFSET : double * : track media playback offset, units depend on I_PLAY_OFFSET_FLAG +// + + void* (*GetSetMediaTrackInfo)(MediaTrack* tr, const char* parmname, void* setNewValue); +#endif + +#if defined(REAPERAPI_WANT_GetSetMediaTrackInfo_String) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetSetMediaTrackInfo_String +// Get or set track string attributes. +// P_NAME : char * : track name (on master returns NULL) +// P_ICON : const char * : track icon (full filename, or relative to resource_path/data/track_icons) +// P_MCP_LAYOUT : const char * : layout name +// P_RAZOREDITS : const char * : list of razor edit areas, as space-separated triples of start time, end time, and envelope GUID string. +// Example: "0.00 1.00 \"\" 0.00 1.00 "{xyz-...}" +// P_TCP_LAYOUT : const char * : layout name +// P_EXT:xyz : char * : extension-specific persistent data +// P_UI_RECT:tcp.mute : char * : read-only, allows querying screen position + size of track WALTER elements (tcp.size queries screen position and size of entire TCP, etc). +// GUID : GUID * : 16-byte GUID, can query or update. If using a _String() function, GUID is a string {xyz-...}. +// + + bool (*GetSetMediaTrackInfo_String)(MediaTrack* tr, const char* parmname, char* stringNeedBig, bool setNewValue); +#endif + +#if defined(REAPERAPI_WANT_GetSetObjectState) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetSetObjectState +// get or set the state of a {track,item,envelope} as an RPPXML chunk +// str="" to get the chunk string returned (must call FreeHeapPtr when done) +// supply str to set the state (returns zero) + + char* (*GetSetObjectState)(void* obj, const char* str); +#endif + +#if defined(REAPERAPI_WANT_GetSetObjectState2) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetSetObjectState2 +// get or set the state of a {track,item,envelope} as an RPPXML chunk +// str="" to get the chunk string returned (must call FreeHeapPtr when done) +// supply str to set the state (returns zero) +// set isundo if the state will be used for undo purposes (which may allow REAPER to get the state more efficiently + + char* (*GetSetObjectState2)(void* obj, const char* str, bool isundo); +#endif + +#if defined(REAPERAPI_WANT_GetSetProjectAuthor) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetSetProjectAuthor +// deprecated, see GetSetProjectInfo_String with desc="PROJECT_AUTHOR" + + void (*GetSetProjectAuthor)(ReaProject* proj, bool set, char* author, int author_sz); +#endif + +#if defined(REAPERAPI_WANT_GetSetProjectGrid) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetSetProjectGrid +// Get or set the arrange view grid division. 0.25=quarter note, 1.0/3.0=half note triplet, etc. swingmode can be 1 for swing enabled, swingamt is -1..1. swingmode can be 3 for measure-grid. Returns grid configuration flags + + int (*GetSetProjectGrid)(ReaProject* project, bool set, double* divisionInOutOptional, int* swingmodeInOutOptional, double* swingamtInOutOptional); +#endif + +#if defined(REAPERAPI_WANT_GetSetProjectInfo) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetSetProjectInfo +// Get or set project information. +// RENDER_SETTINGS : &(1|2)=0:master mix, &1=stems+master mix, &2=stems only, &4=multichannel tracks to multichannel files, &8=use render matrix, &16=tracks with only mono media to mono files, &32=selected media items, &64=selected media items via master, &128=selected tracks via master, &256=embed transients if format supports, &512=embed metadata if format supports, &1024=embed take markers if format supports, &2048=2nd pass render +// RENDER_BOUNDSFLAG : 0=custom time bounds, 1=entire project, 2=time selection, 3=all project regions, 4=selected media items, 5=selected project regions +// RENDER_CHANNELS : number of channels in rendered file +// RENDER_SRATE : sample rate of rendered file (or 0 for project sample rate) +// RENDER_STARTPOS : render start time when RENDER_BOUNDSFLAG=0 +// RENDER_ENDPOS : render end time when RENDER_BOUNDSFLAG=0 +// RENDER_TAILFLAG : apply render tail setting when rendering: &1=custom time bounds, &2=entire project, &4=time selection, &8=all project regions, &16=selected media items, &32=selected project regions +// RENDER_TAILMS : tail length in ms to render (only used if RENDER_BOUNDSFLAG and RENDER_TAILFLAG are set) +// RENDER_ADDTOPROJ : &1=add rendered files to project, &2=do not render files that are likely silent +// RENDER_DITHER : &1=dither, &2=noise shaping, &4=dither stems, &8=noise shaping on stems +// RENDER_NORMALIZE: &1=enable, (&14==0)=LUFS-I, (&14==2)=RMS, (&14==4)=peak, (&14==6)=true peak, (&14==8)=LUFS-M max, (&14==10)=LUFS-S max, &32=normalize stems to common gain based on master, &64=enable brickwall limit +// RENDER_NORMALIZE_TARGET: render normalization target as amplitude, so 0.5 means -6.02dB, 0.25 means -12.04dB, etc +// RENDER_BRICKWALL: render brickwall limit as amplitude, so 0.5 means -6.02dB, 0.25 means -12.04dB, etc +// PROJECT_SRATE : samplerate (ignored unless PROJECT_SRATE_USE set) +// PROJECT_SRATE_USE : set to 1 if project samplerate is used +// + + double (*GetSetProjectInfo)(ReaProject* project, const char* desc, double value, bool is_set); +#endif + +#if defined(REAPERAPI_WANT_GetSetProjectInfo_String) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetSetProjectInfo_String +// Get or set project information. +// PROJECT_NAME : project file name (read-only, is_set will be ignored) +// PROJECT_TITLE : title field from Project Settings/Notes dialog +// PROJECT_AUTHOR : author field from Project Settings/Notes dialog +// TRACK_GROUP_NAME:X : track group name, X should be 1..64 +// MARKER_GUID:X : get the GUID (unique ID) of the marker or region with index X, where X is the index passed to EnumProjectMarkers, not necessarily the displayed number +// RECORD_PATH : recording directory -- may be blank or a relative path, to get the effective path see GetProjectPathEx() +// RECORD_PATH_SECONDARY : secondary recording directory +// RENDER_FILE : render directory +// RENDER_PATTERN : render file name (may contain wildcards) +// RENDER_METADATA : get or set the metadata saved with the project (not metadata embedded in project media). Example, ID3 album name metadata: valuestr="ID3:TALB" to get, valuestr="ID3:TALB|my album name" to set. Call with valuestr="" and is_set=false to get a semicolon-separated list of defined project metadata identifiers. +// RENDER_TARGETS : semicolon separated list of files that would be written if the project is rendered using the most recent render settings +// RENDER_STATS : (read-only) semicolon separated list of statistics for the most recently rendered files. call with valuestr="XXX" to run an action (for example, "42437"=dry run render selected items) before returning statistics. +// RENDER_FORMAT : base64-encoded sink configuration (see project files, etc). Callers can also pass a simple 4-byte string (non-base64-encoded), e.g. "evaw" or "l3pm", to use default settings for that sink type. +// RENDER_FORMAT2 : base64-encoded secondary sink configuration. Callers can also pass a simple 4-byte string (non-base64-encoded), e.g. "evaw" or "l3pm", to use default settings for that sink type, or "" to disable secondary render. +// + + bool (*GetSetProjectInfo_String)(ReaProject* project, const char* desc, char* valuestrNeedBig, bool is_set); +#endif + +#if defined(REAPERAPI_WANT_GetSetProjectNotes) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetSetProjectNotes +// gets or sets project notes, notesNeedBig_sz is ignored when setting + + void (*GetSetProjectNotes)(ReaProject* proj, bool set, char* notesNeedBig, int notesNeedBig_sz); +#endif + +#if defined(REAPERAPI_WANT_GetSetRepeat) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetSetRepeat +// -1 == query,0=clear,1=set,>1=toggle . returns new value + + int (*GetSetRepeat)(int val); +#endif + +#if defined(REAPERAPI_WANT_GetSetRepeatEx) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetSetRepeatEx +// -1 == query,0=clear,1=set,>1=toggle . returns new value + + int (*GetSetRepeatEx)(ReaProject* proj, int val); +#endif + +#if defined(REAPERAPI_WANT_GetSetTrackGroupMembership) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetSetTrackGroupMembership +// Gets or modifies the group membership for a track. Returns group state prior to call (each bit represents one of the 32 group numbers). if setmask has bits set, those bits in setvalue will be applied to group. Group can be one of: +// VOLUME_LEAD +// VOLUME_FOLLOW +// VOLUME_VCA_LEAD +// VOLUME_VCA_FOLLOW +// PAN_LEAD +// PAN_FOLLOW +// WIDTH_LEAD +// WIDTH_FOLLOW +// MUTE_LEAD +// MUTE_FOLLOW +// SOLO_LEAD +// SOLO_FOLLOW +// RECARM_LEAD +// RECARM_FOLLOW +// POLARITY_LEAD +// POLARITY_FOLLOW +// AUTOMODE_LEAD +// AUTOMODE_FOLLOW +// VOLUME_REVERSE +// PAN_REVERSE +// WIDTH_REVERSE +// NO_LEAD_WHEN_FOLLOW +// VOLUME_VCA_FOLLOW_ISPREFX +// +// Note: REAPER v6.11 and earlier used _MASTER and _SLAVE rather than _LEAD and _FOLLOW, which is deprecated but still supported (scripts that must support v6.11 and earlier can use the deprecated strings). +// + + unsigned int (*GetSetTrackGroupMembership)(MediaTrack* tr, const char* groupname, unsigned int setmask, unsigned int setvalue); +#endif + +#if defined(REAPERAPI_WANT_GetSetTrackGroupMembershipHigh) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetSetTrackGroupMembershipHigh +// Gets or modifies the group membership for a track. Returns group state prior to call (each bit represents one of the high 32 group numbers). if setmask has bits set, those bits in setvalue will be applied to group. Group can be one of: +// VOLUME_LEAD +// VOLUME_FOLLOW +// VOLUME_VCA_LEAD +// VOLUME_VCA_FOLLOW +// PAN_LEAD +// PAN_FOLLOW +// WIDTH_LEAD +// WIDTH_FOLLOW +// MUTE_LEAD +// MUTE_FOLLOW +// SOLO_LEAD +// SOLO_FOLLOW +// RECARM_LEAD +// RECARM_FOLLOW +// POLARITY_LEAD +// POLARITY_FOLLOW +// AUTOMODE_LEAD +// AUTOMODE_FOLLOW +// VOLUME_REVERSE +// PAN_REVERSE +// WIDTH_REVERSE +// NO_LEAD_WHEN_FOLLOW +// VOLUME_VCA_FOLLOW_ISPREFX +// +// Note: REAPER v6.11 and earlier used _MASTER and _SLAVE rather than _LEAD and _FOLLOW, which is deprecated but still supported (scripts that must support v6.11 and earlier can use the deprecated strings). +// + + unsigned int (*GetSetTrackGroupMembershipHigh)(MediaTrack* tr, const char* groupname, unsigned int setmask, unsigned int setvalue); +#endif + +#if defined(REAPERAPI_WANT_GetSetTrackMIDISupportFile) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetSetTrackMIDISupportFile +// Get or set the filename for storage of various track MIDI characteristics. 0=MIDI colormap image file, 1 or 2=MIDI bank/program select file (2=set new default). If fn != NULL, a new track MIDI storage file will be set; otherwise the existing track MIDI storage file will be returned. + + const char* (*GetSetTrackMIDISupportFile)(ReaProject* proj, MediaTrack* track, int which, const char* filename); +#endif + +#if defined(REAPERAPI_WANT_GetSetTrackSendInfo) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetSetTrackSendInfo +// Get or set send/receive/hardware output attributes. +// category is <0 for receives, 0=sends, >0 for hardware outputs +// sendidx is 0..n (to enumerate, iterate over sendidx until it returns NULL) +// parameter names: +// P_DESTTRACK : MediaTrack * : destination track, only applies for sends/recvs (read-only) +// P_SRCTRACK : MediaTrack * : source track, only applies for sends/recvs (read-only) +// P_ENV:<envchunkname : TrackEnvelope * : call with :<VOLENV, :<PANENV, etc appended (read-only) +// P_EXT:xyz : char * : extension-specific persistent data +// B_MUTE : bool * +// B_PHASE : bool * : true to flip phase +// B_MONO : bool * +// D_VOL : double * : 1.0 = +0dB etc +// D_PAN : double * : -1..+1 +// D_PANLAW : double * : 1.0=+0.0db, 0.5=-6dB, -1.0 = projdef etc +// I_SENDMODE : int * : 0=post-fader, 1=pre-fx, 2=post-fx (deprecated), 3=post-fx +// I_AUTOMODE : int * : automation mode (-1=use track automode, 0=trim/off, 1=read, 2=touch, 3=write, 4=latch) +// I_SRCCHAN : int * : index,&1024=mono, -1 for none +// I_DSTCHAN : int * : index, &1024=mono, otherwise stereo pair, hwout:&512=rearoute +// I_MIDIFLAGS : int * : low 5 bits=source channel 0=all, 1-16, next 5 bits=dest channel, 0=orig, 1-16=chan +// See CreateTrackSend, RemoveTrackSend. + + void* (*GetSetTrackSendInfo)(MediaTrack* tr, int category, int sendidx, const char* parmname, void* setNewValue); +#endif + +#if defined(REAPERAPI_WANT_GetSetTrackSendInfo_String) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetSetTrackSendInfo_String +// Gets/sets a send attribute string: +// P_EXT:xyz : char * : extension-specific persistent data +// + + bool (*GetSetTrackSendInfo_String)(MediaTrack* tr, int category, int sendidx, const char* parmname, char* stringNeedBig, bool setNewValue); +#endif + +#if defined(REAPERAPI_WANT_GetSetTrackState) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetSetTrackState +// deprecated -- see SetTrackStateChunk, GetTrackStateChunk + + bool (*GetSetTrackState)(MediaTrack* track, char* str, int str_sz); +#endif + +#if defined(REAPERAPI_WANT_GetSetTrackState2) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetSetTrackState2 +// deprecated -- see SetTrackStateChunk, GetTrackStateChunk + + bool (*GetSetTrackState2)(MediaTrack* track, char* str, int str_sz, bool isundo); +#endif + +#if defined(REAPERAPI_WANT_GetSubProjectFromSource) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetSubProjectFromSource + + ReaProject* (*GetSubProjectFromSource)(PCM_source* src); +#endif + +#if defined(REAPERAPI_WANT_GetTake) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetTake +// get a take from an item by take count (zero-based) + + MediaItem_Take* (*GetTake)(MediaItem* item, int takeidx); +#endif + +#if defined(REAPERAPI_WANT_GetTakeEnvelope) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetTakeEnvelope + + TrackEnvelope* (*GetTakeEnvelope)(MediaItem_Take* take, int envidx); +#endif + +#if defined(REAPERAPI_WANT_GetTakeEnvelopeByName) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetTakeEnvelopeByName + + TrackEnvelope* (*GetTakeEnvelopeByName)(MediaItem_Take* take, const char* envname); +#endif + +#if defined(REAPERAPI_WANT_GetTakeMarker) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetTakeMarker +// Get information about a take marker. Returns the position in media item source time, or -1 if the take marker does not exist. See GetNumTakeMarkers, SetTakeMarker, DeleteTakeMarker + + double (*GetTakeMarker)(MediaItem_Take* take, int idx, char* nameOut, int nameOut_sz, int* colorOutOptional); +#endif + +#if defined(REAPERAPI_WANT_GetTakeName) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetTakeName +// returns NULL if the take is not valid + + const char* (*GetTakeName)(MediaItem_Take* take); +#endif + +#if defined(REAPERAPI_WANT_GetTakeNumStretchMarkers) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetTakeNumStretchMarkers +// Returns number of stretch markers in take + + int (*GetTakeNumStretchMarkers)(MediaItem_Take* take); +#endif + +#if defined(REAPERAPI_WANT_GetTakeStretchMarker) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetTakeStretchMarker +// Gets information on a stretch marker, idx is 0..n. Returns -1 if stretch marker not valid. posOut will be set to position in item, srcposOutOptional will be set to source media position. Returns index. if input index is -1, the following marker is found using position (or source position if position is -1). If position/source position are used to find marker position, their values are not updated. + + int (*GetTakeStretchMarker)(MediaItem_Take* take, int idx, double* posOut, double* srcposOutOptional); +#endif + +#if defined(REAPERAPI_WANT_GetTakeStretchMarkerSlope) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetTakeStretchMarkerSlope +// See SetTakeStretchMarkerSlope + + double (*GetTakeStretchMarkerSlope)(MediaItem_Take* take, int idx); +#endif + +#if defined(REAPERAPI_WANT_GetTCPFXParm) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetTCPFXParm +// Get information about a specific FX parameter knob (see CountTCPFXParms). + + bool (*GetTCPFXParm)(ReaProject* project, MediaTrack* track, int index, int* fxindexOut, int* parmidxOut); +#endif + +#if defined(REAPERAPI_WANT_GetTempoMatchPlayRate) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetTempoMatchPlayRate +// finds the playrate and target length to insert this item stretched to a round power-of-2 number of bars, between 1/8 and 256 + + bool (*GetTempoMatchPlayRate)(PCM_source* source, double srcscale, double position, double mult, double* rateOut, double* targetlenOut); +#endif + +#if defined(REAPERAPI_WANT_GetTempoTimeSigMarker) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetTempoTimeSigMarker +// Get information about a tempo/time signature marker. See CountTempoTimeSigMarkers, SetTempoTimeSigMarker, AddTempoTimeSigMarker. + + bool (*GetTempoTimeSigMarker)(ReaProject* proj, int ptidx, double* timeposOut, int* measureposOut, double* beatposOut, double* bpmOut, int* timesig_numOut, int* timesig_denomOut, bool* lineartempoOut); +#endif + +#if defined(REAPERAPI_WANT_GetThemeColor) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetThemeColor +// Returns the theme color specified, or -1 on failure. If the low bit of flags is set, the color as originally specified by the theme (before any transformations) is returned, otherwise the current (possibly transformed and modified) color is returned. See SetThemeColor for a list of valid ini_key. + + int (*GetThemeColor)(const char* ini_key, int flagsOptional); +#endif + +#if defined(REAPERAPI_WANT_GetThingFromPoint) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetThingFromPoint +// Hit tests a point in screen coordinates. Updates infoOut with information such as "arrange", "fx_chain", "fx_0" (first FX in chain, floating). If a track panel is hit, string will begin with "tcp" or "mcp" or "tcp.mute" etc (future versions may append additional information). May return NULL with valid info string to indicate non-track thing. + + MediaTrack* (*GetThingFromPoint)(int screen_x, int screen_y, char* infoOut, int infoOut_sz); +#endif + +#if defined(REAPERAPI_WANT_GetToggleCommandState) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetToggleCommandState +// See GetToggleCommandStateEx. + + int (*GetToggleCommandState)(int command_id); +#endif + +#if defined(REAPERAPI_WANT_GetToggleCommandState2) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetToggleCommandState2 +// See GetToggleCommandStateEx. + + int (*GetToggleCommandState2)(KbdSectionInfo* section, int command_id); +#endif + +#if defined(REAPERAPI_WANT_GetToggleCommandStateEx) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetToggleCommandStateEx +// For the main action context, the MIDI editor, or the media explorer, returns the toggle state of the action. 0=off, 1=on, -1=NA because the action does not have on/off states. For the MIDI editor, the action state for the most recently focused window will be returned. + + int (*GetToggleCommandStateEx)(int section_id, int command_id); +#endif + +#if defined(REAPERAPI_WANT_GetToggleCommandStateThroughHooks) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetToggleCommandStateThroughHooks +// Returns the state of an action via extension plugins' hooks. + + int (*GetToggleCommandStateThroughHooks)(KbdSectionInfo* section, int command_id); +#endif + +#if defined(REAPERAPI_WANT_GetTooltipWindow) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetTooltipWindow +// gets a tooltip window,in case you want to ask it for font information. Can return NULL. + + HWND (*GetTooltipWindow)(); +#endif + +#if defined(REAPERAPI_WANT_GetTrack) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetTrack +// get a track from a project by track count (zero-based) (proj=0 for active project) + + MediaTrack* (*GetTrack)(ReaProject* proj, int trackidx); +#endif + +#if defined(REAPERAPI_WANT_GetTrackAutomationMode) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetTrackAutomationMode +// return the track mode, regardless of global override + + int (*GetTrackAutomationMode)(MediaTrack* tr); +#endif + +#if defined(REAPERAPI_WANT_GetTrackColor) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetTrackColor +// Returns the track custom color as OS dependent color|0x1000000 (i.e. ColorToNative(r,g,b)|0x1000000). Black is returned as 0x1000000, no color setting is returned as 0. + + int (*GetTrackColor)(MediaTrack* track); +#endif + +#if defined(REAPERAPI_WANT_GetTrackDepth) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetTrackDepth + + int (*GetTrackDepth)(MediaTrack* track); +#endif + +#if defined(REAPERAPI_WANT_GetTrackEnvelope) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetTrackEnvelope + + TrackEnvelope* (*GetTrackEnvelope)(MediaTrack* track, int envidx); +#endif + +#if defined(REAPERAPI_WANT_GetTrackEnvelopeByChunkName) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetTrackEnvelopeByChunkName +// Gets a built-in track envelope by configuration chunk name, like "<VOLENV", or GUID string, like "{B577250D-146F-B544-9B34-F24FBE488F1F}". +// + + TrackEnvelope* (*GetTrackEnvelopeByChunkName)(MediaTrack* tr, const char* cfgchunkname_or_guid); +#endif + +#if defined(REAPERAPI_WANT_GetTrackEnvelopeByName) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetTrackEnvelopeByName + + TrackEnvelope* (*GetTrackEnvelopeByName)(MediaTrack* track, const char* envname); +#endif + +#if defined(REAPERAPI_WANT_GetTrackFromPoint) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetTrackFromPoint +// Returns the track from the screen coordinates specified. If the screen coordinates refer to a window associated to the track (such as FX), the track will be returned. infoOutOptional will be set to 1 if it is likely an envelope, 2 if it is likely a track FX. See GetThingFromPoint. + + MediaTrack* (*GetTrackFromPoint)(int screen_x, int screen_y, int* infoOutOptional); +#endif + +#if defined(REAPERAPI_WANT_GetTrackGUID) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetTrackGUID + + GUID* (*GetTrackGUID)(MediaTrack* tr); +#endif + +#if defined(REAPERAPI_WANT_GetTrackInfo) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetTrackInfo +// gets track info (returns name). +// track index, -1=master, 0..n, or cast a MediaTrack* to int +// if flags is non-NULL, will be set to: +// &1=folder +// &2=selected +// &4=has fx enabled +// &8=muted +// &16=soloed +// &32=SIP'd (with &16) +// &64=rec armed +// &128=rec monitoring on +// &256=rec monitoring auto +// &512=hide from TCP +// &1024=hide from MCP + + const char* (*GetTrackInfo)(INT_PTR track, int* flags); +#endif + +#if defined(REAPERAPI_WANT_GetTrackMediaItem) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetTrackMediaItem + + MediaItem* (*GetTrackMediaItem)(MediaTrack* tr, int itemidx); +#endif + +#if defined(REAPERAPI_WANT_GetTrackMIDILyrics) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetTrackMIDILyrics +// Get all MIDI lyrics on the track. Lyrics will be returned as one string with tabs between each word. flag&1: double tabs at the end of each measure and triple tabs when skipping measures, flag&2: each lyric is preceded by its beat position in the project (example with flag=2: "1.1.2\tLyric for measure 1 beat 2\t.1.1\tLyric for measure 2 beat 1 "). See SetTrackMIDILyrics + + bool (*GetTrackMIDILyrics)(MediaTrack* track, int flag, char* bufOutWantNeedBig, int* bufOutWantNeedBig_sz); +#endif + +#if defined(REAPERAPI_WANT_GetTrackMIDINoteName) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetTrackMIDINoteName +// see GetTrackMIDINoteNameEx + + const char* (*GetTrackMIDINoteName)(int track, int pitch, int chan); +#endif + +#if defined(REAPERAPI_WANT_GetTrackMIDINoteNameEx) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetTrackMIDINoteNameEx +// Get note/CC name. pitch 128 for CC0 name, 129 for CC1 name, etc. See SetTrackMIDINoteNameEx + + const char* (*GetTrackMIDINoteNameEx)(ReaProject* proj, MediaTrack* track, int pitch, int chan); +#endif + +#if defined(REAPERAPI_WANT_GetTrackMIDINoteRange) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetTrackMIDINoteRange + + void (*GetTrackMIDINoteRange)(ReaProject* proj, MediaTrack* track, int* note_loOut, int* note_hiOut); +#endif + +#if defined(REAPERAPI_WANT_GetTrackName) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetTrackName +// Returns "MASTER" for master track, "Track N" if track has no name. + + bool (*GetTrackName)(MediaTrack* track, char* bufOut, int bufOut_sz); +#endif + +#if defined(REAPERAPI_WANT_GetTrackNumMediaItems) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetTrackNumMediaItems + + int (*GetTrackNumMediaItems)(MediaTrack* tr); +#endif + +#if defined(REAPERAPI_WANT_GetTrackNumSends) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetTrackNumSends +// returns number of sends/receives/hardware outputs - category is <0 for receives, 0=sends, >0 for hardware outputs + + int (*GetTrackNumSends)(MediaTrack* tr, int category); +#endif + +#if defined(REAPERAPI_WANT_GetTrackReceiveName) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetTrackReceiveName +// See GetTrackSendName. + + bool (*GetTrackReceiveName)(MediaTrack* track, int recv_index, char* bufOut, int bufOut_sz); +#endif + +#if defined(REAPERAPI_WANT_GetTrackReceiveUIMute) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetTrackReceiveUIMute +// See GetTrackSendUIMute. + + bool (*GetTrackReceiveUIMute)(MediaTrack* track, int recv_index, bool* muteOut); +#endif + +#if defined(REAPERAPI_WANT_GetTrackReceiveUIVolPan) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetTrackReceiveUIVolPan +// See GetTrackSendUIVolPan. + + bool (*GetTrackReceiveUIVolPan)(MediaTrack* track, int recv_index, double* volumeOut, double* panOut); +#endif + +#if defined(REAPERAPI_WANT_GetTrackSendInfo_Value) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetTrackSendInfo_Value +// Get send/receive/hardware output numerical-value attributes. +// category is <0 for receives, 0=sends, >0 for hardware outputs +// parameter names: +// B_MUTE : bool * +// B_PHASE : bool * : true to flip phase +// B_MONO : bool * +// D_VOL : double * : 1.0 = +0dB etc +// D_PAN : double * : -1..+1 +// D_PANLAW : double * : 1.0=+0.0db, 0.5=-6dB, -1.0 = projdef etc +// I_SENDMODE : int * : 0=post-fader, 1=pre-fx, 2=post-fx (deprecated), 3=post-fx +// I_AUTOMODE : int * : automation mode (-1=use track automode, 0=trim/off, 1=read, 2=touch, 3=write, 4=latch) +// I_SRCCHAN : int * : index,&1024=mono, -1 for none +// I_DSTCHAN : int * : index, &1024=mono, otherwise stereo pair, hwout:&512=rearoute +// I_MIDIFLAGS : int * : low 5 bits=source channel 0=all, 1-16, next 5 bits=dest channel, 0=orig, 1-16=chan +// P_DESTTRACK : MediaTrack * : destination track, only applies for sends/recvs (read-only) +// P_SRCTRACK : MediaTrack * : source track, only applies for sends/recvs (read-only) +// P_ENV:<envchunkname : TrackEnvelope * : call with :<VOLENV, :<PANENV, etc appended (read-only) +// See CreateTrackSend, RemoveTrackSend, GetTrackNumSends. + + double (*GetTrackSendInfo_Value)(MediaTrack* tr, int category, int sendidx, const char* parmname); +#endif + +#if defined(REAPERAPI_WANT_GetTrackSendName) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetTrackSendName +// send_idx>=0 for hw ouputs, >=nb_of_hw_ouputs for sends. See GetTrackReceiveName. + + bool (*GetTrackSendName)(MediaTrack* track, int send_index, char* bufOut, int bufOut_sz); +#endif + +#if defined(REAPERAPI_WANT_GetTrackSendUIMute) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetTrackSendUIMute +// send_idx>=0 for hw ouputs, >=nb_of_hw_ouputs for sends. See GetTrackReceiveUIMute. + + bool (*GetTrackSendUIMute)(MediaTrack* track, int send_index, bool* muteOut); +#endif + +#if defined(REAPERAPI_WANT_GetTrackSendUIVolPan) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetTrackSendUIVolPan +// send_idx>=0 for hw ouputs, >=nb_of_hw_ouputs for sends. See GetTrackReceiveUIVolPan. + + bool (*GetTrackSendUIVolPan)(MediaTrack* track, int send_index, double* volumeOut, double* panOut); +#endif + +#if defined(REAPERAPI_WANT_GetTrackState) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetTrackState +// Gets track state, returns track name. +// flags will be set to: +// &1=folder +// &2=selected +// &4=has fx enabled +// &8=muted +// &16=soloed +// &32=SIP'd (with &16) +// &64=rec armed +// &128=rec monitoring on +// &256=rec monitoring auto +// &512=hide from TCP +// &1024=hide from MCP + + const char* (*GetTrackState)(MediaTrack* track, int* flagsOut); +#endif + +#if defined(REAPERAPI_WANT_GetTrackStateChunk) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetTrackStateChunk +// Gets the RPPXML state of a track, returns true if successful. Undo flag is a performance/caching hint. + + bool (*GetTrackStateChunk)(MediaTrack* track, char* strNeedBig, int strNeedBig_sz, bool isundoOptional); +#endif + +#if defined(REAPERAPI_WANT_GetTrackUIMute) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetTrackUIMute + + bool (*GetTrackUIMute)(MediaTrack* track, bool* muteOut); +#endif + +#if defined(REAPERAPI_WANT_GetTrackUIPan) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetTrackUIPan + + bool (*GetTrackUIPan)(MediaTrack* track, double* pan1Out, double* pan2Out, int* panmodeOut); +#endif + +#if defined(REAPERAPI_WANT_GetTrackUIVolPan) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetTrackUIVolPan + + bool (*GetTrackUIVolPan)(MediaTrack* track, double* volumeOut, double* panOut); +#endif + +#if defined(REAPERAPI_WANT_GetUnderrunTime) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetUnderrunTime +// retrieves the last timestamps of audio xrun (yellow-flash, if available), media xrun (red-flash), and the current time stamp (all milliseconds) + + void (*GetUnderrunTime)(unsigned int* audio_xrunOut, unsigned int* media_xrunOut, unsigned int* curtimeOut); +#endif + +#if defined(REAPERAPI_WANT_GetUserFileNameForRead) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetUserFileNameForRead +// returns true if the user selected a valid file, false if the user canceled the dialog + + bool (*GetUserFileNameForRead)(char* filenameNeed4096, const char* title, const char* defext); +#endif + +#if defined(REAPERAPI_WANT_GetUserInputs) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GetUserInputs +// Get values from the user. +// If a caption begins with *, for example "*password", the edit field will not display the input text. +// Maximum fields is 16. Values are returned as a comma-separated string. Returns false if the user canceled the dialog. You can supply special extra information via additional caption fields: extrawidth=XXX to increase text field width, separator=X to use a different separator for returned fields. + + bool (*GetUserInputs)(const char* title, int num_inputs, const char* captions_csv, char* retvals_csv, int retvals_csv_sz); +#endif + +#if defined(REAPERAPI_WANT_GoToMarker) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GoToMarker +// Go to marker. If use_timeline_order==true, marker_index 1 refers to the first marker on the timeline. If use_timeline_order==false, marker_index 1 refers to the first marker with the user-editable index of 1. + + void (*GoToMarker)(ReaProject* proj, int marker_index, bool use_timeline_order); +#endif + +#if defined(REAPERAPI_WANT_GoToRegion) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GoToRegion +// Seek to region after current region finishes playing (smooth seek). If use_timeline_order==true, region_index 1 refers to the first region on the timeline. If use_timeline_order==false, region_index 1 refers to the first region with the user-editable index of 1. + + void (*GoToRegion)(ReaProject* proj, int region_index, bool use_timeline_order); +#endif + +#if defined(REAPERAPI_WANT_GR_SelectColor) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GR_SelectColor +// Runs the system color chooser dialog. Returns 0 if the user cancels the dialog. + + int (*GR_SelectColor)(HWND hwnd, int* colorOut); +#endif + +#if defined(REAPERAPI_WANT_GSC_mainwnd) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// GSC_mainwnd +// this is just like win32 GetSysColor() but can have overrides. + + int (*GSC_mainwnd)(int t); +#endif + +#if defined(REAPERAPI_WANT_guidToString) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// guidToString +// dest should be at least 64 chars long to be safe + + void (*guidToString)(const GUID* g, char* destNeed64); +#endif + +#if defined(REAPERAPI_WANT_HasExtState) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// HasExtState +// Returns true if there exists an extended state value for a specific section and key. See SetExtState, GetExtState, DeleteExtState. + + bool (*HasExtState)(const char* section, const char* key); +#endif + +#if defined(REAPERAPI_WANT_HasTrackMIDIPrograms) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// HasTrackMIDIPrograms +// returns name of track plugin that is supplying MIDI programs,or NULL if there is none + + const char* (*HasTrackMIDIPrograms)(int track); +#endif + +#if defined(REAPERAPI_WANT_HasTrackMIDIProgramsEx) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// HasTrackMIDIProgramsEx +// returns name of track plugin that is supplying MIDI programs,or NULL if there is none + + const char* (*HasTrackMIDIProgramsEx)(ReaProject* proj, MediaTrack* track); +#endif + +#if defined(REAPERAPI_WANT_Help_Set) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// Help_Set + + void (*Help_Set)(const char* helpstring, bool is_temporary_help); +#endif + +#if defined(REAPERAPI_WANT_HiresPeaksFromSource) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// HiresPeaksFromSource + + void (*HiresPeaksFromSource)(PCM_source* src, PCM_source_peaktransfer_t* block); +#endif + +#if defined(REAPERAPI_WANT_image_resolve_fn) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// image_resolve_fn + + void (*image_resolve_fn)(const char* in, char* out, int out_sz); +#endif + +#if defined(REAPERAPI_WANT_InsertAutomationItem) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// InsertAutomationItem +// Insert a new automation item. pool_id < 0 collects existing envelope points into the automation item; if pool_id is >= 0 the automation item will be a new instance of that pool (which will be created as an empty instance if it does not exist). Returns the index of the item, suitable for passing to other automation item API functions. See GetSetAutomationItemInfo. + + int (*InsertAutomationItem)(TrackEnvelope* env, int pool_id, double position, double length); +#endif + +#if defined(REAPERAPI_WANT_InsertEnvelopePoint) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// InsertEnvelopePoint +// Insert an envelope point. If setting multiple points at once, set noSort=true, and call Envelope_SortPoints when done. See InsertEnvelopePointEx. + + bool (*InsertEnvelopePoint)(TrackEnvelope* envelope, double time, double value, int shape, double tension, bool selected, bool* noSortInOptional); +#endif + +#if defined(REAPERAPI_WANT_InsertEnvelopePointEx) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// InsertEnvelopePointEx +// Insert an envelope point. If setting multiple points at once, set noSort=true, and call Envelope_SortPoints when done. +// autoitem_idx=-1 for the underlying envelope, 0 for the first automation item on the envelope, etc. +// For automation items, pass autoitem_idx|0x10000000 to base ptidx on the number of points in one full loop iteration, +// even if the automation item is trimmed so that not all points are visible. +// Otherwise, ptidx will be based on the number of visible points in the automation item, including all loop iterations. +// See CountEnvelopePointsEx, GetEnvelopePointEx, SetEnvelopePointEx, DeleteEnvelopePointEx. + + bool (*InsertEnvelopePointEx)(TrackEnvelope* envelope, int autoitem_idx, double time, double value, int shape, double tension, bool selected, bool* noSortInOptional); +#endif + +#if defined(REAPERAPI_WANT_InsertMedia) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// InsertMedia +// mode: 0=add to current track, 1=add new track, 3=add to selected items as takes, &4=stretch/loop to fit time sel, &8=try to match tempo 1x, &16=try to match tempo 0.5x, &32=try to match tempo 2x, &64=don't preserve pitch when matching tempo, &128=no loop/section if startpct/endpct set, &256=force loop regardless of global preference for looping imported items, &512=use high word as absolute track index if mode&3==0, &1024=insert into reasamplomatic on a new track, &2048=insert into open reasamplomatic instance, &4096=move to source preferred position (BWF start offset), &8192=reverse + + int (*InsertMedia)(const char* file, int mode); +#endif + +#if defined(REAPERAPI_WANT_InsertMediaSection) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// InsertMediaSection +// See InsertMedia. + + int (*InsertMediaSection)(const char* file, int mode, double startpct, double endpct, double pitchshift); +#endif + +#if defined(REAPERAPI_WANT_InsertTrackAtIndex) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// InsertTrackAtIndex +// inserts a track at idx,of course this will be clamped to 0..GetNumTracks(). wantDefaults=TRUE for default envelopes/FX,otherwise no enabled fx/env + + void (*InsertTrackAtIndex)(int idx, bool wantDefaults); +#endif + +#if defined(REAPERAPI_WANT_IsInRealTimeAudio) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// IsInRealTimeAudio +// are we in a realtime audio thread (between OnAudioBuffer calls,not in some worker/anticipative FX thread)? threadsafe + + int (*IsInRealTimeAudio)(); +#endif + +#if defined(REAPERAPI_WANT_IsItemTakeActiveForPlayback) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// IsItemTakeActiveForPlayback +// get whether a take will be played (active take, unmuted, etc) + + bool (*IsItemTakeActiveForPlayback)(MediaItem* item, MediaItem_Take* take); +#endif + +#if defined(REAPERAPI_WANT_IsMediaExtension) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// IsMediaExtension +// Tests a file extension (i.e. "wav" or "mid") to see if it's a media extension. +// If wantOthers is set, then "RPP", "TXT" and other project-type formats will also pass. + + bool (*IsMediaExtension)(const char* ext, bool wantOthers); +#endif + +#if defined(REAPERAPI_WANT_IsMediaItemSelected) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// IsMediaItemSelected + + bool (*IsMediaItemSelected)(MediaItem* item); +#endif + +#if defined(REAPERAPI_WANT_IsProjectDirty) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// IsProjectDirty +// Is the project dirty (needing save)? Always returns 0 if 'undo/prompt to save' is disabled in preferences. + + int (*IsProjectDirty)(ReaProject* proj); +#endif + +#if defined(REAPERAPI_WANT_IsREAPER) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// IsREAPER +// Returns true if dealing with REAPER, returns false for ReaMote, etc + + bool (*IsREAPER)(); +#endif + +#if defined(REAPERAPI_WANT_IsTrackSelected) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// IsTrackSelected + + bool (*IsTrackSelected)(MediaTrack* track); +#endif + +#if defined(REAPERAPI_WANT_IsTrackVisible) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// IsTrackVisible +// If mixer==true, returns true if the track is visible in the mixer. If mixer==false, returns true if the track is visible in the track control panel. + + bool (*IsTrackVisible)(MediaTrack* track, bool mixer); +#endif + +#if defined(REAPERAPI_WANT_joystick_create) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// joystick_create +// creates a joystick device + + joystick_device* (*joystick_create)(const GUID* guid); +#endif + +#if defined(REAPERAPI_WANT_joystick_destroy) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// joystick_destroy +// destroys a joystick device + + void (*joystick_destroy)(joystick_device* device); +#endif + +#if defined(REAPERAPI_WANT_joystick_enum) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// joystick_enum +// enumerates installed devices, returns GUID as a string + + const char* (*joystick_enum)(int index, const char** namestrOutOptional); +#endif + +#if defined(REAPERAPI_WANT_joystick_getaxis) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// joystick_getaxis +// returns axis value (-1..1) + + double (*joystick_getaxis)(joystick_device* dev, int axis); +#endif + +#if defined(REAPERAPI_WANT_joystick_getbuttonmask) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// joystick_getbuttonmask +// returns button pressed mask, 1=first button, 2=second... + + unsigned int (*joystick_getbuttonmask)(joystick_device* dev); +#endif + +#if defined(REAPERAPI_WANT_joystick_getinfo) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// joystick_getinfo +// returns button count + + int (*joystick_getinfo)(joystick_device* dev, int* axesOutOptional, int* povsOutOptional); +#endif + +#if defined(REAPERAPI_WANT_joystick_getpov) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// joystick_getpov +// returns POV value (usually 0..655.35, or 655.35 on error) + + double (*joystick_getpov)(joystick_device* dev, int pov); +#endif + +#if defined(REAPERAPI_WANT_joystick_update) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// joystick_update +// Updates joystick state from hardware, returns true if successful (joystick_get* will not be valid until joystick_update() is called successfully) + + bool (*joystick_update)(joystick_device* dev); +#endif + +#if defined(REAPERAPI_WANT_kbd_enumerateActions) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// kbd_enumerateActions + + int (*kbd_enumerateActions)(KbdSectionInfo* section, int idx, const char** nameOut); +#endif + +#if defined(REAPERAPI_WANT_kbd_formatKeyName) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// kbd_formatKeyName + + void (*kbd_formatKeyName)(ACCEL* ac, char* s); +#endif + +#if defined(REAPERAPI_WANT_kbd_getCommandName) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// kbd_getCommandName +// Get the string of a key assigned to command "cmd" in a section. +// This function is poorly named as it doesn't return the command's name, see kbd_getTextFromCmd. + + void (*kbd_getCommandName)(int cmd, char* s, KbdSectionInfo* section); +#endif + +#if defined(REAPERAPI_WANT_kbd_getTextFromCmd) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// kbd_getTextFromCmd + + const char* (*kbd_getTextFromCmd)(DWORD cmd, KbdSectionInfo* section); +#endif + +#if defined(REAPERAPI_WANT_KBD_OnMainActionEx) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// KBD_OnMainActionEx +// val/valhw are used for midi stuff. +// val=[0..127] and valhw=-1 (midi CC), +// valhw >=0 (midi pitch (valhw | val<<7)), +// relmode absolute (0) or 1/2/3 for relative adjust modes + + int (*KBD_OnMainActionEx)(int cmd, int val, int valhw, int relmode, HWND hwnd, ReaProject* proj); +#endif + +#if defined(REAPERAPI_WANT_kbd_OnMidiEvent) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// kbd_OnMidiEvent +// can be called from anywhere (threadsafe) + + void (*kbd_OnMidiEvent)(MIDI_event_t* evt, int dev_index); +#endif + +#if defined(REAPERAPI_WANT_kbd_OnMidiList) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// kbd_OnMidiList +// can be called from anywhere (threadsafe) + + void (*kbd_OnMidiList)(MIDI_eventlist* list, int dev_index); +#endif + +#if defined(REAPERAPI_WANT_kbd_ProcessActionsMenu) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// kbd_ProcessActionsMenu + + void (*kbd_ProcessActionsMenu)(HMENU menu, KbdSectionInfo* section); +#endif + +#if defined(REAPERAPI_WANT_kbd_processMidiEventActionEx) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// kbd_processMidiEventActionEx + + bool (*kbd_processMidiEventActionEx)(MIDI_event_t* evt, KbdSectionInfo* section, HWND hwndCtx); +#endif + +#if defined(REAPERAPI_WANT_kbd_reprocessMenu) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// kbd_reprocessMenu +// Reprocess a menu recursively, setting key assignments to what their command IDs are mapped to. + + void (*kbd_reprocessMenu)(HMENU menu, KbdSectionInfo* section); +#endif + +#if defined(REAPERAPI_WANT_kbd_RunCommandThroughHooks) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// kbd_RunCommandThroughHooks +// actioncommandID may get modified + + bool (*kbd_RunCommandThroughHooks)(KbdSectionInfo* section, int* actionCommandID, int* val, int* valhw, int* relmode, HWND hwnd); +#endif + +#if defined(REAPERAPI_WANT_kbd_translateAccelerator) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// kbd_translateAccelerator +// Pass in the HWND to receive commands, a MSG of a key command, and a valid section, +// and kbd_translateAccelerator() will process it looking for any keys bound to it, and send the messages off. +// Returns 1 if processed, 0 if no key binding found. + + int (*kbd_translateAccelerator)(HWND hwnd, MSG* msg, KbdSectionInfo* section); +#endif + +#if defined(REAPERAPI_WANT_kbd_translateMouse) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// kbd_translateMouse + + bool (*kbd_translateMouse)(void* winmsg, unsigned char* midimsg); +#endif + +#ifndef REAPERAPI_NO_LICE +#if defined(REAPERAPI_WANT_LICE__Destroy) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// LICE__Destroy + + void (*LICE__Destroy)(LICE_IBitmap* bm); +#endif + +#if defined(REAPERAPI_WANT_LICE__DestroyFont) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// LICE__DestroyFont + + void (*LICE__DestroyFont)(LICE_IFont* font); +#endif + +#if defined(REAPERAPI_WANT_LICE__DrawText) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// LICE__DrawText + + int (*LICE__DrawText)(LICE_IFont* font, LICE_IBitmap* bm, const char* str, int strcnt, RECT* rect, UINT dtFlags); +#endif + +#if defined(REAPERAPI_WANT_LICE__GetBits) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// LICE__GetBits + + void* (*LICE__GetBits)(LICE_IBitmap* bm); +#endif + +#if defined(REAPERAPI_WANT_LICE__GetDC) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// LICE__GetDC + + HDC (*LICE__GetDC)(LICE_IBitmap* bm); +#endif + +#if defined(REAPERAPI_WANT_LICE__GetHeight) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// LICE__GetHeight + + int (*LICE__GetHeight)(LICE_IBitmap* bm); +#endif + +#if defined(REAPERAPI_WANT_LICE__GetRowSpan) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// LICE__GetRowSpan + + int (*LICE__GetRowSpan)(LICE_IBitmap* bm); +#endif + +#if defined(REAPERAPI_WANT_LICE__GetWidth) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// LICE__GetWidth + + int (*LICE__GetWidth)(LICE_IBitmap* bm); +#endif + +#if defined(REAPERAPI_WANT_LICE__IsFlipped) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// LICE__IsFlipped + + bool (*LICE__IsFlipped)(LICE_IBitmap* bm); +#endif + +#if defined(REAPERAPI_WANT_LICE__resize) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// LICE__resize + + bool (*LICE__resize)(LICE_IBitmap* bm, int w, int h); +#endif + +#if defined(REAPERAPI_WANT_LICE__SetBkColor) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// LICE__SetBkColor + + LICE_pixel (*LICE__SetBkColor)(LICE_IFont* font, LICE_pixel color); +#endif + +#if defined(REAPERAPI_WANT_LICE__SetFromHFont) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// LICE__SetFromHFont +// font must REMAIN valid,unless LICE_FONT_FLAG_PRECALCALL is set + + void (*LICE__SetFromHFont)(LICE_IFont* font, HFONT hfont, int flags); +#endif + +#if defined(REAPERAPI_WANT_LICE__SetTextColor) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// LICE__SetTextColor + + LICE_pixel (*LICE__SetTextColor)(LICE_IFont* font, LICE_pixel color); +#endif + +#if defined(REAPERAPI_WANT_LICE__SetTextCombineMode) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// LICE__SetTextCombineMode + + void (*LICE__SetTextCombineMode)(LICE_IFont* ifont, int mode, float alpha); +#endif + +#if defined(REAPERAPI_WANT_LICE_Arc) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// LICE_Arc + + void (*LICE_Arc)(LICE_IBitmap* dest, float cx, float cy, float r, float minAngle, float maxAngle, LICE_pixel color, float alpha, int mode, bool aa); +#endif + +#if defined(REAPERAPI_WANT_LICE_Blit) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// LICE_Blit + + void (*LICE_Blit)(LICE_IBitmap* dest, LICE_IBitmap* src, int dstx, int dsty, int srcx, int srcy, int srcw, int srch, float alpha, int mode); +#endif + +#if defined(REAPERAPI_WANT_LICE_Blur) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// LICE_Blur + + void (*LICE_Blur)(LICE_IBitmap* dest, LICE_IBitmap* src, int dstx, int dsty, int srcx, int srcy, int srcw, int srch); +#endif + +#if defined(REAPERAPI_WANT_LICE_BorderedRect) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// LICE_BorderedRect + + void (*LICE_BorderedRect)(LICE_IBitmap* dest, int x, int y, int w, int h, LICE_pixel bgcolor, LICE_pixel fgcolor, float alpha, int mode); +#endif + +#if defined(REAPERAPI_WANT_LICE_Circle) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// LICE_Circle + + void (*LICE_Circle)(LICE_IBitmap* dest, float cx, float cy, float r, LICE_pixel color, float alpha, int mode, bool aa); +#endif + +#if defined(REAPERAPI_WANT_LICE_Clear) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// LICE_Clear + + void (*LICE_Clear)(LICE_IBitmap* dest, LICE_pixel color); +#endif + +#if defined(REAPERAPI_WANT_LICE_ClearRect) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// LICE_ClearRect + + void (*LICE_ClearRect)(LICE_IBitmap* dest, int x, int y, int w, int h, LICE_pixel mask, LICE_pixel orbits); +#endif + +#if defined(REAPERAPI_WANT_LICE_ClipLine) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// LICE_ClipLine +// Returns false if the line is entirely offscreen. + + bool (*LICE_ClipLine)(int* pX1Out, int* pY1Out, int* pX2Out, int* pY2Out, int xLo, int yLo, int xHi, int yHi); +#endif + +#if defined(REAPERAPI_WANT_LICE_Copy) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// LICE_Copy + + void (*LICE_Copy)(LICE_IBitmap* dest, LICE_IBitmap* src); +#endif + +#if defined(REAPERAPI_WANT_LICE_CreateBitmap) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// LICE_CreateBitmap +// create a new bitmap. this is like calling new LICE_MemBitmap (mode=0) or new LICE_SysBitmap (mode=1). + + LICE_IBitmap* (*LICE_CreateBitmap)(int mode, int w, int h); +#endif + +#if defined(REAPERAPI_WANT_LICE_CreateFont) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// LICE_CreateFont + + LICE_IFont* (*LICE_CreateFont)(); +#endif + +#if defined(REAPERAPI_WANT_LICE_DrawCBezier) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// LICE_DrawCBezier + + void (*LICE_DrawCBezier)(LICE_IBitmap* dest, double xstart, double ystart, double xctl1, double yctl1, double xctl2, double yctl2, double xend, double yend, LICE_pixel color, float alpha, int mode, bool aa, double tol); +#endif + +#if defined(REAPERAPI_WANT_LICE_DrawChar) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// LICE_DrawChar + + void (*LICE_DrawChar)(LICE_IBitmap* bm, int x, int y, char c, LICE_pixel color, float alpha, int mode); +#endif + +#if defined(REAPERAPI_WANT_LICE_DrawGlyph) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// LICE_DrawGlyph + + void (*LICE_DrawGlyph)(LICE_IBitmap* dest, int x, int y, LICE_pixel color, LICE_pixel_chan* alphas, int glyph_w, int glyph_h, float alpha, int mode); +#endif + +#if defined(REAPERAPI_WANT_LICE_DrawRect) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// LICE_DrawRect + + void (*LICE_DrawRect)(LICE_IBitmap* dest, int x, int y, int w, int h, LICE_pixel color, float alpha, int mode); +#endif + +#if defined(REAPERAPI_WANT_LICE_DrawText) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// LICE_DrawText + + void (*LICE_DrawText)(LICE_IBitmap* bm, int x, int y, const char* string, LICE_pixel color, float alpha, int mode); +#endif + +#if defined(REAPERAPI_WANT_LICE_FillCBezier) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// LICE_FillCBezier + + void (*LICE_FillCBezier)(LICE_IBitmap* dest, double xstart, double ystart, double xctl1, double yctl1, double xctl2, double yctl2, double xend, double yend, int yfill, LICE_pixel color, float alpha, int mode, bool aa, double tol); +#endif + +#if defined(REAPERAPI_WANT_LICE_FillCircle) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// LICE_FillCircle + + void (*LICE_FillCircle)(LICE_IBitmap* dest, float cx, float cy, float r, LICE_pixel color, float alpha, int mode, bool aa); +#endif + +#if defined(REAPERAPI_WANT_LICE_FillConvexPolygon) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// LICE_FillConvexPolygon + + void (*LICE_FillConvexPolygon)(LICE_IBitmap* dest, int* x, int* y, int npoints, LICE_pixel color, float alpha, int mode); +#endif + +#if defined(REAPERAPI_WANT_LICE_FillRect) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// LICE_FillRect + + void (*LICE_FillRect)(LICE_IBitmap* dest, int x, int y, int w, int h, LICE_pixel color, float alpha, int mode); +#endif + +#if defined(REAPERAPI_WANT_LICE_FillTrapezoid) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// LICE_FillTrapezoid + + void (*LICE_FillTrapezoid)(LICE_IBitmap* dest, int x1a, int x1b, int y1, int x2a, int x2b, int y2, LICE_pixel color, float alpha, int mode); +#endif + +#if defined(REAPERAPI_WANT_LICE_FillTriangle) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// LICE_FillTriangle + + void (*LICE_FillTriangle)(LICE_IBitmap* dest, int x1, int y1, int x2, int y2, int x3, int y3, LICE_pixel color, float alpha, int mode); +#endif + +#if defined(REAPERAPI_WANT_LICE_GetPixel) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// LICE_GetPixel + + LICE_pixel (*LICE_GetPixel)(LICE_IBitmap* bm, int x, int y); +#endif + +#if defined(REAPERAPI_WANT_LICE_GradRect) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// LICE_GradRect + + void (*LICE_GradRect)(LICE_IBitmap* dest, int dstx, int dsty, int dstw, int dsth, float ir, float ig, float ib, float ia, float drdx, float dgdx, float dbdx, float dadx, float drdy, float dgdy, float dbdy, float dady, int mode); +#endif + +#if defined(REAPERAPI_WANT_LICE_Line) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// LICE_Line + + void (*LICE_Line)(LICE_IBitmap* dest, float x1, float y1, float x2, float y2, LICE_pixel color, float alpha, int mode, bool aa); +#endif + +#if defined(REAPERAPI_WANT_LICE_LineInt) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// LICE_LineInt + + void (*LICE_LineInt)(LICE_IBitmap* dest, int x1, int y1, int x2, int y2, LICE_pixel color, float alpha, int mode, bool aa); +#endif + +#if defined(REAPERAPI_WANT_LICE_LoadPNG) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// LICE_LoadPNG + + LICE_IBitmap* (*LICE_LoadPNG)(const char* filename, LICE_IBitmap* bmp); +#endif + +#if defined(REAPERAPI_WANT_LICE_LoadPNGFromResource) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// LICE_LoadPNGFromResource + + LICE_IBitmap* (*LICE_LoadPNGFromResource)(HINSTANCE hInst, const char* resid, LICE_IBitmap* bmp); +#endif + +#if defined(REAPERAPI_WANT_LICE_MeasureText) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// LICE_MeasureText + + void (*LICE_MeasureText)(const char* string, int* w, int* h); +#endif + +#if defined(REAPERAPI_WANT_LICE_MultiplyAddRect) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// LICE_MultiplyAddRect + + void (*LICE_MultiplyAddRect)(LICE_IBitmap* dest, int x, int y, int w, int h, float rsc, float gsc, float bsc, float asc, float radd, float gadd, float badd, float aadd); +#endif + +#if defined(REAPERAPI_WANT_LICE_PutPixel) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// LICE_PutPixel + + void (*LICE_PutPixel)(LICE_IBitmap* bm, int x, int y, LICE_pixel color, float alpha, int mode); +#endif + +#if defined(REAPERAPI_WANT_LICE_RotatedBlit) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// LICE_RotatedBlit +// these coordinates are offset from the center of the image,in source pixel coordinates + + void (*LICE_RotatedBlit)(LICE_IBitmap* dest, LICE_IBitmap* src, int dstx, int dsty, int dstw, int dsth, float srcx, float srcy, float srcw, float srch, float angle, bool cliptosourcerect, float alpha, int mode, float rotxcent, float rotycent); +#endif + +#if defined(REAPERAPI_WANT_LICE_RoundRect) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// LICE_RoundRect + + void (*LICE_RoundRect)(LICE_IBitmap* drawbm, float xpos, float ypos, float w, float h, int cornerradius, LICE_pixel col, float alpha, int mode, bool aa); +#endif + +#if defined(REAPERAPI_WANT_LICE_ScaledBlit) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// LICE_ScaledBlit + + void (*LICE_ScaledBlit)(LICE_IBitmap* dest, LICE_IBitmap* src, int dstx, int dsty, int dstw, int dsth, float srcx, float srcy, float srcw, float srch, float alpha, int mode); +#endif + +#if defined(REAPERAPI_WANT_LICE_SimpleFill) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// LICE_SimpleFill + + void (*LICE_SimpleFill)(LICE_IBitmap* dest, int x, int y, LICE_pixel newcolor, LICE_pixel comparemask, LICE_pixel keepmask); +#endif + +#endif // !REAPERAPI_NO_LICE +#if defined(REAPERAPI_WANT_LocalizeString) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// LocalizeString +// Returns a localized version of src_string, in section section. flags can have 1 set to only localize if sprintf-style formatting matches the original. + + const char* (*LocalizeString)(const char* src_string, const char* section, int flagsOptional); +#endif + +#if defined(REAPERAPI_WANT_Loop_OnArrow) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// Loop_OnArrow +// Move the loop selection left or right. Returns true if snap is enabled. + + bool (*Loop_OnArrow)(ReaProject* project, int direction); +#endif + +#if defined(REAPERAPI_WANT_Main_OnCommand) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// Main_OnCommand +// See Main_OnCommandEx. + + void (*Main_OnCommand)(int command, int flag); +#endif + +#if defined(REAPERAPI_WANT_Main_OnCommandEx) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// Main_OnCommandEx +// Performs an action belonging to the main action section. To perform non-native actions (ReaScripts, custom or extension plugins' actions) safely, see NamedCommandLookup(). + + void (*Main_OnCommandEx)(int command, int flag, ReaProject* proj); +#endif + +#if defined(REAPERAPI_WANT_Main_openProject) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// Main_openProject +// opens a project. will prompt the user to save unless name is prefixed with 'noprompt:'. If name is prefixed with 'template:', project file will be loaded as a template. +// If passed a .RTrackTemplate file, adds the template to the existing project. + + void (*Main_openProject)(const char* name); +#endif + +#if defined(REAPERAPI_WANT_Main_SaveProject) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// Main_SaveProject +// Save the project. + + void (*Main_SaveProject)(ReaProject* proj, bool forceSaveAsInOptional); +#endif + +#if defined(REAPERAPI_WANT_Main_UpdateLoopInfo) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// Main_UpdateLoopInfo + + void (*Main_UpdateLoopInfo)(int ignoremask); +#endif + +#if defined(REAPERAPI_WANT_MarkProjectDirty) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// MarkProjectDirty +// Marks project as dirty (needing save) if 'undo/prompt to save' is enabled in preferences. + + void (*MarkProjectDirty)(ReaProject* proj); +#endif + +#if defined(REAPERAPI_WANT_MarkTrackItemsDirty) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// MarkTrackItemsDirty +// If track is supplied, item is ignored + + void (*MarkTrackItemsDirty)(MediaTrack* track, MediaItem* item); +#endif + +#if defined(REAPERAPI_WANT_Master_GetPlayRate) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// Master_GetPlayRate + + double (*Master_GetPlayRate)(ReaProject* project); +#endif + +#if defined(REAPERAPI_WANT_Master_GetPlayRateAtTime) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// Master_GetPlayRateAtTime + + double (*Master_GetPlayRateAtTime)(double time_s, ReaProject* proj); +#endif + +#if defined(REAPERAPI_WANT_Master_GetTempo) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// Master_GetTempo + + double (*Master_GetTempo)(); +#endif + +#if defined(REAPERAPI_WANT_Master_NormalizePlayRate) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// Master_NormalizePlayRate +// Convert play rate to/from a value between 0 and 1, representing the position on the project playrate slider. + + double (*Master_NormalizePlayRate)(double playrate, bool isnormalized); +#endif + +#if defined(REAPERAPI_WANT_Master_NormalizeTempo) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// Master_NormalizeTempo +// Convert the tempo to/from a value between 0 and 1, representing bpm in the range of 40-296 bpm. + + double (*Master_NormalizeTempo)(double bpm, bool isnormalized); +#endif + +#if defined(REAPERAPI_WANT_MB) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// MB +// type 0=OK,1=OKCANCEL,2=ABORTRETRYIGNORE,3=YESNOCANCEL,4=YESNO,5=RETRYCANCEL : ret 1=OK,2=CANCEL,3=ABORT,4=RETRY,5=IGNORE,6=YES,7=NO + + int (*MB)(const char* msg, const char* title, int type); +#endif + +#if defined(REAPERAPI_WANT_MediaItemDescendsFromTrack) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// MediaItemDescendsFromTrack +// Returns 1 if the track holds the item, 2 if the track is a folder containing the track that holds the item, etc. + + int (*MediaItemDescendsFromTrack)(MediaItem* item, MediaTrack* track); +#endif + +#if defined(REAPERAPI_WANT_MIDI_CountEvts) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// MIDI_CountEvts +// Count the number of notes, CC events, and text/sysex events in a given MIDI item. + + int (*MIDI_CountEvts)(MediaItem_Take* take, int* notecntOut, int* ccevtcntOut, int* textsyxevtcntOut); +#endif + +#if defined(REAPERAPI_WANT_MIDI_DeleteCC) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// MIDI_DeleteCC +// Delete a MIDI CC event. + + bool (*MIDI_DeleteCC)(MediaItem_Take* take, int ccidx); +#endif + +#if defined(REAPERAPI_WANT_MIDI_DeleteEvt) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// MIDI_DeleteEvt +// Delete a MIDI event. + + bool (*MIDI_DeleteEvt)(MediaItem_Take* take, int evtidx); +#endif + +#if defined(REAPERAPI_WANT_MIDI_DeleteNote) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// MIDI_DeleteNote +// Delete a MIDI note. + + bool (*MIDI_DeleteNote)(MediaItem_Take* take, int noteidx); +#endif + +#if defined(REAPERAPI_WANT_MIDI_DeleteTextSysexEvt) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// MIDI_DeleteTextSysexEvt +// Delete a MIDI text or sysex event. + + bool (*MIDI_DeleteTextSysexEvt)(MediaItem_Take* take, int textsyxevtidx); +#endif + +#if defined(REAPERAPI_WANT_MIDI_DisableSort) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// MIDI_DisableSort +// Disable sorting for all MIDI insert, delete, get and set functions, until MIDI_Sort is called. + + void (*MIDI_DisableSort)(MediaItem_Take* take); +#endif + +#if defined(REAPERAPI_WANT_MIDI_EnumSelCC) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// MIDI_EnumSelCC +// Returns the index of the next selected MIDI CC event after ccidx (-1 if there are no more selected events). + + int (*MIDI_EnumSelCC)(MediaItem_Take* take, int ccidx); +#endif + +#if defined(REAPERAPI_WANT_MIDI_EnumSelEvts) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// MIDI_EnumSelEvts +// Returns the index of the next selected MIDI event after evtidx (-1 if there are no more selected events). + + int (*MIDI_EnumSelEvts)(MediaItem_Take* take, int evtidx); +#endif + +#if defined(REAPERAPI_WANT_MIDI_EnumSelNotes) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// MIDI_EnumSelNotes +// Returns the index of the next selected MIDI note after noteidx (-1 if there are no more selected events). + + int (*MIDI_EnumSelNotes)(MediaItem_Take* take, int noteidx); +#endif + +#if defined(REAPERAPI_WANT_MIDI_EnumSelTextSysexEvts) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// MIDI_EnumSelTextSysexEvts +// Returns the index of the next selected MIDI text/sysex event after textsyxidx (-1 if there are no more selected events). + + int (*MIDI_EnumSelTextSysexEvts)(MediaItem_Take* take, int textsyxidx); +#endif + +#if defined(REAPERAPI_WANT_MIDI_eventlist_Create) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// MIDI_eventlist_Create +// Create a MIDI_eventlist object. The returned object must be deleted with MIDI_eventlist_destroy(). + + MIDI_eventlist* (*MIDI_eventlist_Create)(); +#endif + +#if defined(REAPERAPI_WANT_MIDI_eventlist_Destroy) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// MIDI_eventlist_Destroy +// Destroy a MIDI_eventlist object that was created using MIDI_eventlist_Create(). + + void (*MIDI_eventlist_Destroy)(MIDI_eventlist* evtlist); +#endif + +#if defined(REAPERAPI_WANT_MIDI_GetAllEvts) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// MIDI_GetAllEvts +// Get all MIDI data. MIDI buffer is returned as a list of { int offset, char flag, int msglen, unsigned char msg[] }. +// offset: MIDI ticks from previous event +// flag: &1=selected &2=muted +// flag high 4 bits for CC shape: &16=linear, &32=slow start/end, &16|32=fast start, &64=fast end, &64|16=bezier +// msg: the MIDI message. +// A meta-event of type 0xF followed by 'CCBZ ' and 5 more bytes represents bezier curve data for the previous MIDI event: 1 byte for the bezier type (usually 0) and 4 bytes for the bezier tension as a float. +// For tick intervals longer than a 32 bit word can represent, zero-length meta events may be placed between valid events. +// See MIDI_SetAllEvts. + + bool (*MIDI_GetAllEvts)(MediaItem_Take* take, char* bufOutNeedBig, int* bufOutNeedBig_sz); +#endif + +#if defined(REAPERAPI_WANT_MIDI_GetCC) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// MIDI_GetCC +// Get MIDI CC event properties. + + bool (*MIDI_GetCC)(MediaItem_Take* take, int ccidx, bool* selectedOut, bool* mutedOut, double* ppqposOut, int* chanmsgOut, int* chanOut, int* msg2Out, int* msg3Out); +#endif + +#if defined(REAPERAPI_WANT_MIDI_GetCCShape) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// MIDI_GetCCShape +// Get CC shape and bezier tension. See MIDI_GetCC, MIDI_SetCCShape + + bool (*MIDI_GetCCShape)(MediaItem_Take* take, int ccidx, int* shapeOut, double* beztensionOut); +#endif + +#if defined(REAPERAPI_WANT_MIDI_GetEvt) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// MIDI_GetEvt +// Get MIDI event properties. + + bool (*MIDI_GetEvt)(MediaItem_Take* take, int evtidx, bool* selectedOut, bool* mutedOut, double* ppqposOut, char* msgOut, int* msgOut_sz); +#endif + +#if defined(REAPERAPI_WANT_MIDI_GetGrid) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// MIDI_GetGrid +// Returns the most recent MIDI editor grid size for this MIDI take, in QN. Swing is between 0 and 1. Note length is 0 if it follows the grid size. + + double (*MIDI_GetGrid)(MediaItem_Take* take, double* swingOutOptional, double* noteLenOutOptional); +#endif + +#if defined(REAPERAPI_WANT_MIDI_GetHash) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// MIDI_GetHash +// Get a string that only changes when the MIDI data changes. If notesonly==true, then the string changes only when the MIDI notes change. See MIDI_GetTrackHash + + bool (*MIDI_GetHash)(MediaItem_Take* take, bool notesonly, char* hashOut, int hashOut_sz); +#endif + +#if defined(REAPERAPI_WANT_MIDI_GetNote) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// MIDI_GetNote +// Get MIDI note properties. + + bool (*MIDI_GetNote)(MediaItem_Take* take, int noteidx, bool* selectedOut, bool* mutedOut, double* startppqposOut, double* endppqposOut, int* chanOut, int* pitchOut, int* velOut); +#endif + +#if defined(REAPERAPI_WANT_MIDI_GetPPQPos_EndOfMeasure) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// MIDI_GetPPQPos_EndOfMeasure +// Returns the MIDI tick (ppq) position corresponding to the end of the measure. + + double (*MIDI_GetPPQPos_EndOfMeasure)(MediaItem_Take* take, double ppqpos); +#endif + +#if defined(REAPERAPI_WANT_MIDI_GetPPQPos_StartOfMeasure) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// MIDI_GetPPQPos_StartOfMeasure +// Returns the MIDI tick (ppq) position corresponding to the start of the measure. + + double (*MIDI_GetPPQPos_StartOfMeasure)(MediaItem_Take* take, double ppqpos); +#endif + +#if defined(REAPERAPI_WANT_MIDI_GetPPQPosFromProjQN) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// MIDI_GetPPQPosFromProjQN +// Returns the MIDI tick (ppq) position corresponding to a specific project time in quarter notes. + + double (*MIDI_GetPPQPosFromProjQN)(MediaItem_Take* take, double projqn); +#endif + +#if defined(REAPERAPI_WANT_MIDI_GetPPQPosFromProjTime) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// MIDI_GetPPQPosFromProjTime +// Returns the MIDI tick (ppq) position corresponding to a specific project time in seconds. + + double (*MIDI_GetPPQPosFromProjTime)(MediaItem_Take* take, double projtime); +#endif + +#if defined(REAPERAPI_WANT_MIDI_GetProjQNFromPPQPos) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// MIDI_GetProjQNFromPPQPos +// Returns the project time in quarter notes corresponding to a specific MIDI tick (ppq) position. + + double (*MIDI_GetProjQNFromPPQPos)(MediaItem_Take* take, double ppqpos); +#endif + +#if defined(REAPERAPI_WANT_MIDI_GetProjTimeFromPPQPos) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// MIDI_GetProjTimeFromPPQPos +// Returns the project time in seconds corresponding to a specific MIDI tick (ppq) position. + + double (*MIDI_GetProjTimeFromPPQPos)(MediaItem_Take* take, double ppqpos); +#endif + +#if defined(REAPERAPI_WANT_MIDI_GetRecentInputEvent) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// MIDI_GetRecentInputEvent +// Gets a recent MIDI input event from the global history. idx=0 for the most recent event, which also latches to the latest MIDI event state (to get a more recent list, calling with idx=0 is necessary). idx=1 next most recent event, returns a non-zero sequence number for the event, or zero if no more events. tsOut will be set to the timestamp in samples relative to the current position (0 is current, -48000 is one second ago, etc). devIdxOut will have the low 16 bits set to the input device index, and 0x10000 will be set if device was enabled only for control. projPosOut will be set to project position in seconds if project was playing back at time of event, otherwise -1. Large SysEx events will not be included in this event list. + + int (*MIDI_GetRecentInputEvent)(int idx, char* bufOut, int* bufOut_sz, int* tsOut, int* devIdxOut, double* projPosOut, int* projLoopCntOut); +#endif + +#if defined(REAPERAPI_WANT_MIDI_GetScale) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// MIDI_GetScale +// Get the active scale in the media source, if any. root 0=C, 1=C#, etc. scale &0x1=root, &0x2=minor 2nd, &0x4=major 2nd, &0x8=minor 3rd, &0xF=fourth, etc. + + bool (*MIDI_GetScale)(MediaItem_Take* take, int* rootOut, int* scaleOut, char* nameOut, int nameOut_sz); +#endif + +#if defined(REAPERAPI_WANT_MIDI_GetTextSysexEvt) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// MIDI_GetTextSysexEvt +// Get MIDI meta-event properties. Allowable types are -1:sysex (msg should not include bounding F0..F7), 1-14:MIDI text event types, 15=REAPER notation event. For all other meta-messages, type is returned as -2 and msg returned as all zeroes. See MIDI_GetEvt. + + bool (*MIDI_GetTextSysexEvt)(MediaItem_Take* take, int textsyxevtidx, bool* selectedOutOptional, bool* mutedOutOptional, double* ppqposOutOptional, int* typeOutOptional, char* msgOptional, int* msgOptional_sz); +#endif + +#if defined(REAPERAPI_WANT_MIDI_GetTrackHash) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// MIDI_GetTrackHash +// Get a string that only changes when the MIDI data changes. If notesonly==true, then the string changes only when the MIDI notes change. See MIDI_GetHash + + bool (*MIDI_GetTrackHash)(MediaTrack* track, bool notesonly, char* hashOut, int hashOut_sz); +#endif + +#if defined(REAPERAPI_WANT_MIDI_InsertCC) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// MIDI_InsertCC +// Insert a new MIDI CC event. + + bool (*MIDI_InsertCC)(MediaItem_Take* take, bool selected, bool muted, double ppqpos, int chanmsg, int chan, int msg2, int msg3); +#endif + +#if defined(REAPERAPI_WANT_MIDI_InsertEvt) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// MIDI_InsertEvt +// Insert a new MIDI event. + + bool (*MIDI_InsertEvt)(MediaItem_Take* take, bool selected, bool muted, double ppqpos, const char* bytestr, int bytestr_sz); +#endif + +#if defined(REAPERAPI_WANT_MIDI_InsertNote) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// MIDI_InsertNote +// Insert a new MIDI note. Set noSort if inserting multiple events, then call MIDI_Sort when done. + + bool (*MIDI_InsertNote)(MediaItem_Take* take, bool selected, bool muted, double startppqpos, double endppqpos, int chan, int pitch, int vel, const bool* noSortInOptional); +#endif + +#if defined(REAPERAPI_WANT_MIDI_InsertTextSysexEvt) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// MIDI_InsertTextSysexEvt +// Insert a new MIDI text or sysex event. Allowable types are -1:sysex (msg should not include bounding F0..F7), 1-14:MIDI text event types, 15=REAPER notation event. + + bool (*MIDI_InsertTextSysexEvt)(MediaItem_Take* take, bool selected, bool muted, double ppqpos, int type, const char* bytestr, int bytestr_sz); +#endif + +#if defined(REAPERAPI_WANT_midi_reinit) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// midi_reinit +// Reset all MIDI devices + + void (*midi_reinit)(); +#endif + +#if defined(REAPERAPI_WANT_MIDI_SelectAll) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// MIDI_SelectAll +// Select or deselect all MIDI content. + + void (*MIDI_SelectAll)(MediaItem_Take* take, bool select); +#endif + +#if defined(REAPERAPI_WANT_MIDI_SetAllEvts) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// MIDI_SetAllEvts +// Set all MIDI data. MIDI buffer is passed in as a list of { int offset, char flag, int msglen, unsigned char msg[] }. +// offset: MIDI ticks from previous event +// flag: &1=selected &2=muted +// flag high 4 bits for CC shape: &16=linear, &32=slow start/end, &16|32=fast start, &64=fast end, &64|16=bezier +// msg: the MIDI message. +// A meta-event of type 0xF followed by 'CCBZ ' and 5 more bytes represents bezier curve data for the previous MIDI event: 1 byte for the bezier type (usually 0) and 4 bytes for the bezier tension as a float. +// For tick intervals longer than a 32 bit word can represent, zero-length meta events may be placed between valid events. +// See MIDI_GetAllEvts. + + bool (*MIDI_SetAllEvts)(MediaItem_Take* take, const char* buf, int buf_sz); +#endif + +#if defined(REAPERAPI_WANT_MIDI_SetCC) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// MIDI_SetCC +// Set MIDI CC event properties. Properties passed as NULL will not be set. set noSort if setting multiple events, then call MIDI_Sort when done. + + bool (*MIDI_SetCC)(MediaItem_Take* take, int ccidx, const bool* selectedInOptional, const bool* mutedInOptional, const double* ppqposInOptional, const int* chanmsgInOptional, const int* chanInOptional, const int* msg2InOptional, const int* msg3InOptional, const bool* noSortInOptional); +#endif + +#if defined(REAPERAPI_WANT_MIDI_SetCCShape) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// MIDI_SetCCShape +// Set CC shape and bezier tension. set noSort if setting multiple events, then call MIDI_Sort when done. See MIDI_SetCC, MIDI_GetCCShape + + bool (*MIDI_SetCCShape)(MediaItem_Take* take, int ccidx, int shape, double beztension, const bool* noSortInOptional); +#endif + +#if defined(REAPERAPI_WANT_MIDI_SetEvt) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// MIDI_SetEvt +// Set MIDI event properties. Properties passed as NULL will not be set. set noSort if setting multiple events, then call MIDI_Sort when done. + + bool (*MIDI_SetEvt)(MediaItem_Take* take, int evtidx, const bool* selectedInOptional, const bool* mutedInOptional, const double* ppqposInOptional, const char* msgOptional, int msgOptional_sz, const bool* noSortInOptional); +#endif + +#if defined(REAPERAPI_WANT_MIDI_SetItemExtents) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// MIDI_SetItemExtents +// Set the start/end positions of a media item that contains a MIDI take. + + bool (*MIDI_SetItemExtents)(MediaItem* item, double startQN, double endQN); +#endif + +#if defined(REAPERAPI_WANT_MIDI_SetNote) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// MIDI_SetNote +// Set MIDI note properties. Properties passed as NULL (or negative values) will not be set. Set noSort if setting multiple events, then call MIDI_Sort when done. Setting multiple note start positions at once is done more safely by deleting and re-inserting the notes. + + bool (*MIDI_SetNote)(MediaItem_Take* take, int noteidx, const bool* selectedInOptional, const bool* mutedInOptional, const double* startppqposInOptional, const double* endppqposInOptional, const int* chanInOptional, const int* pitchInOptional, const int* velInOptional, const bool* noSortInOptional); +#endif + +#if defined(REAPERAPI_WANT_MIDI_SetTextSysexEvt) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// MIDI_SetTextSysexEvt +// Set MIDI text or sysex event properties. Properties passed as NULL will not be set. Allowable types are -1:sysex (msg should not include bounding F0..F7), 1-14:MIDI text event types, 15=REAPER notation event. set noSort if setting multiple events, then call MIDI_Sort when done. + + bool (*MIDI_SetTextSysexEvt)(MediaItem_Take* take, int textsyxevtidx, const bool* selectedInOptional, const bool* mutedInOptional, const double* ppqposInOptional, const int* typeInOptional, const char* msgOptional, int msgOptional_sz, const bool* noSortInOptional); +#endif + +#if defined(REAPERAPI_WANT_MIDI_Sort) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// MIDI_Sort +// Sort MIDI events after multiple calls to MIDI_SetNote, MIDI_SetCC, etc. + + void (*MIDI_Sort)(MediaItem_Take* take); +#endif + +#if defined(REAPERAPI_WANT_MIDIEditor_EnumTakes) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// MIDIEditor_EnumTakes +// list the takes that are currently being edited in this MIDI editor, starting with the active take. See MIDIEditor_GetTake + + MediaItem_Take* (*MIDIEditor_EnumTakes)(HWND midieditor, int takeindex, bool editable_only); +#endif + +#if defined(REAPERAPI_WANT_MIDIEditor_GetActive) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// MIDIEditor_GetActive +// get a pointer to the focused MIDI editor window +// see MIDIEditor_GetMode, MIDIEditor_OnCommand + + HWND (*MIDIEditor_GetActive)(); +#endif + +#if defined(REAPERAPI_WANT_MIDIEditor_GetMode) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// MIDIEditor_GetMode +// get the mode of a MIDI editor (0=piano roll, 1=event list, -1=invalid editor) +// see MIDIEditor_GetActive, MIDIEditor_OnCommand + + int (*MIDIEditor_GetMode)(HWND midieditor); +#endif + +#if defined(REAPERAPI_WANT_MIDIEditor_GetSetting_int) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// MIDIEditor_GetSetting_int +// Get settings from a MIDI editor. setting_desc can be: +// snap_enabled: returns 0 or 1 +// active_note_row: returns 0-127 +// last_clicked_cc_lane: returns 0-127=CC, 0x100|(0-31)=14-bit CC, 0x200=velocity, 0x201=pitch, 0x202=program, 0x203=channel pressure, 0x204=bank/program select, 0x205=text, 0x206=sysex, 0x207=off velocity, 0x208=notation events, 0x210=media item lane +// default_note_vel: returns 0-127 +// default_note_chan: returns 0-15 +// default_note_len: returns default length in MIDI ticks +// scale_enabled: returns 0-1 +// scale_root: returns 0-12 (0=C) +// list_cnt: if viewing list view, returns event count +// if setting_desc is unsupported, the function returns -1. +// See MIDIEditor_SetSetting_int, MIDIEditor_GetActive, MIDIEditor_GetSetting_str +// + + int (*MIDIEditor_GetSetting_int)(HWND midieditor, const char* setting_desc); +#endif + +#if defined(REAPERAPI_WANT_MIDIEditor_GetSetting_str) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// MIDIEditor_GetSetting_str +// Get settings from a MIDI editor. setting_desc can be: +// last_clicked_cc_lane: returns text description ("velocity", "pitch", etc) +// scale: returns the scale record, for example "102034050607" for a major scale +// list_X: if viewing list view, returns string describing event at row X (0-based). String will have a list of key=value pairs, e.g. 'pos=4.0 len=4.0 offvel=127 msg=90317F'. pos/len times are in QN, len/offvel may not be present if event is not a note. other keys which may be present include pos_pq/len_pq, sel, mute, ccval14, ccshape, ccbeztension. +// if setting_desc is unsupported, the function returns false. +// See MIDIEditor_GetActive, MIDIEditor_GetSetting_int +// + + bool (*MIDIEditor_GetSetting_str)(HWND midieditor, const char* setting_desc, char* bufOut, int bufOut_sz); +#endif + +#if defined(REAPERAPI_WANT_MIDIEditor_GetTake) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// MIDIEditor_GetTake +// get the take that is currently being edited in this MIDI editor. see MIDIEditor_EnumTakes + + MediaItem_Take* (*MIDIEditor_GetTake)(HWND midieditor); +#endif + +#if defined(REAPERAPI_WANT_MIDIEditor_LastFocused_OnCommand) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// MIDIEditor_LastFocused_OnCommand +// Send an action command to the last focused MIDI editor. Returns false if there is no MIDI editor open, or if the view mode (piano roll or event list) does not match the input. +// see MIDIEditor_OnCommand + + bool (*MIDIEditor_LastFocused_OnCommand)(int command_id, bool islistviewcommand); +#endif + +#if defined(REAPERAPI_WANT_MIDIEditor_OnCommand) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// MIDIEditor_OnCommand +// Send an action command to a MIDI editor. Returns false if the supplied MIDI editor pointer is not valid (not an open MIDI editor). +// see MIDIEditor_GetActive, MIDIEditor_LastFocused_OnCommand + + bool (*MIDIEditor_OnCommand)(HWND midieditor, int command_id); +#endif + +#if defined(REAPERAPI_WANT_MIDIEditor_SetSetting_int) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// MIDIEditor_SetSetting_int +// Set settings for a MIDI editor. setting_desc can be: +// active_note_row: 0-127 +// See MIDIEditor_GetSetting_int +// + + bool (*MIDIEditor_SetSetting_int)(HWND midieditor, const char* setting_desc, int setting); +#endif + +#if defined(REAPERAPI_WANT_mkpanstr) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// mkpanstr + + void (*mkpanstr)(char* strNeed64, double pan); +#endif + +#if defined(REAPERAPI_WANT_mkvolpanstr) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// mkvolpanstr + + void (*mkvolpanstr)(char* strNeed64, double vol, double pan); +#endif + +#if defined(REAPERAPI_WANT_mkvolstr) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// mkvolstr + + void (*mkvolstr)(char* strNeed64, double vol); +#endif + +#if defined(REAPERAPI_WANT_MoveEditCursor) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// MoveEditCursor + + void (*MoveEditCursor)(double adjamt, bool dosel); +#endif + +#if defined(REAPERAPI_WANT_MoveMediaItemToTrack) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// MoveMediaItemToTrack +// returns TRUE if move succeeded + + bool (*MoveMediaItemToTrack)(MediaItem* item, MediaTrack* desttr); +#endif + +#if defined(REAPERAPI_WANT_MuteAllTracks) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// MuteAllTracks + + void (*MuteAllTracks)(bool mute); +#endif + +#if defined(REAPERAPI_WANT_my_getViewport) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// my_getViewport + + void (*my_getViewport)(RECT* r, const RECT* sr, bool wantWorkArea); +#endif + +#if defined(REAPERAPI_WANT_NamedCommandLookup) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// NamedCommandLookup +// Get the command ID number for named command that was registered by an extension such as "_SWS_ABOUT" or "_113088d11ae641c193a2b7ede3041ad5" for a ReaScript or a custom action. + + int (*NamedCommandLookup)(const char* command_name); +#endif + +#if defined(REAPERAPI_WANT_OnPauseButton) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// OnPauseButton +// direct way to simulate pause button hit + + void (*OnPauseButton)(); +#endif + +#if defined(REAPERAPI_WANT_OnPauseButtonEx) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// OnPauseButtonEx +// direct way to simulate pause button hit + + void (*OnPauseButtonEx)(ReaProject* proj); +#endif + +#if defined(REAPERAPI_WANT_OnPlayButton) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// OnPlayButton +// direct way to simulate play button hit + + void (*OnPlayButton)(); +#endif + +#if defined(REAPERAPI_WANT_OnPlayButtonEx) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// OnPlayButtonEx +// direct way to simulate play button hit + + void (*OnPlayButtonEx)(ReaProject* proj); +#endif + +#if defined(REAPERAPI_WANT_OnStopButton) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// OnStopButton +// direct way to simulate stop button hit + + void (*OnStopButton)(); +#endif + +#if defined(REAPERAPI_WANT_OnStopButtonEx) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// OnStopButtonEx +// direct way to simulate stop button hit + + void (*OnStopButtonEx)(ReaProject* proj); +#endif + +#if defined(REAPERAPI_WANT_OpenColorThemeFile) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// OpenColorThemeFile + + bool (*OpenColorThemeFile)(const char* fn); +#endif + +#if defined(REAPERAPI_WANT_OpenMediaExplorer) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// OpenMediaExplorer +// Opens mediafn in the Media Explorer, play=true will play the file immediately (or toggle playback if mediafn was already open), =false will just select it. + + HWND (*OpenMediaExplorer)(const char* mediafn, bool play); +#endif + +#if defined(REAPERAPI_WANT_OscLocalMessageToHost) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// OscLocalMessageToHost +// Send an OSC message directly to REAPER. The value argument may be NULL. The message will be matched against the default OSC patterns. Only supported if control surface support was enabled when installing REAPER. + + void (*OscLocalMessageToHost)(const char* message, const double* valueInOptional); +#endif + +#if defined(REAPERAPI_WANT_parse_timestr) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// parse_timestr +// Parse hh:mm:ss.sss time string, return time in seconds (or 0.0 on error). See parse_timestr_pos, parse_timestr_len. + + double (*parse_timestr)(const char* buf); +#endif + +#if defined(REAPERAPI_WANT_parse_timestr_len) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// parse_timestr_len +// time formatting mode overrides: -1=proj default. +// 0=time +// 1=measures.beats + time +// 2=measures.beats +// 3=seconds +// 4=samples +// 5=h:m:s:f +// + + double (*parse_timestr_len)(const char* buf, double offset, int modeoverride); +#endif + +#if defined(REAPERAPI_WANT_parse_timestr_pos) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// parse_timestr_pos +// Parse time string, time formatting mode overrides: -1=proj default. +// 0=time +// 1=measures.beats + time +// 2=measures.beats +// 3=seconds +// 4=samples +// 5=h:m:s:f +// + + double (*parse_timestr_pos)(const char* buf, int modeoverride); +#endif + +#if defined(REAPERAPI_WANT_parsepanstr) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// parsepanstr + + double (*parsepanstr)(const char* str); +#endif + +#if defined(REAPERAPI_WANT_PCM_Sink_Create) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// PCM_Sink_Create + + PCM_sink* (*PCM_Sink_Create)(const char* filename, const char* cfg, int cfg_sz, int nch, int srate, bool buildpeaks); +#endif + +#if defined(REAPERAPI_WANT_PCM_Sink_CreateEx) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// PCM_Sink_CreateEx + + PCM_sink* (*PCM_Sink_CreateEx)(ReaProject* proj, const char* filename, const char* cfg, int cfg_sz, int nch, int srate, bool buildpeaks); +#endif + +#if defined(REAPERAPI_WANT_PCM_Sink_CreateMIDIFile) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// PCM_Sink_CreateMIDIFile + + PCM_sink* (*PCM_Sink_CreateMIDIFile)(const char* filename, const char* cfg, int cfg_sz, double bpm, int div); +#endif + +#if defined(REAPERAPI_WANT_PCM_Sink_CreateMIDIFileEx) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// PCM_Sink_CreateMIDIFileEx + + PCM_sink* (*PCM_Sink_CreateMIDIFileEx)(ReaProject* proj, const char* filename, const char* cfg, int cfg_sz, double bpm, int div); +#endif + +#if defined(REAPERAPI_WANT_PCM_Sink_Enum) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// PCM_Sink_Enum + + unsigned int (*PCM_Sink_Enum)(int idx, const char** descstrOut); +#endif + +#if defined(REAPERAPI_WANT_PCM_Sink_GetExtension) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// PCM_Sink_GetExtension + + const char* (*PCM_Sink_GetExtension)(const char* data, int data_sz); +#endif + +#if defined(REAPERAPI_WANT_PCM_Sink_ShowConfig) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// PCM_Sink_ShowConfig + + HWND (*PCM_Sink_ShowConfig)(const char* cfg, int cfg_sz, HWND hwndParent); +#endif + +#if defined(REAPERAPI_WANT_PCM_Source_BuildPeaks) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// PCM_Source_BuildPeaks +// Calls and returns PCM_source::PeaksBuild_Begin() if mode=0, PeaksBuild_Run() if mode=1, and PeaksBuild_Finish() if mode=2. Normal use is to call PCM_Source_BuildPeaks(src,0), and if that returns nonzero, call PCM_Source_BuildPeaks(src,1) periodically until it returns zero (it returns the percentage of the file remaining), then call PCM_Source_BuildPeaks(src,2) to finalize. If PCM_Source_BuildPeaks(src,0) returns zero, then no further action is necessary. + + int (*PCM_Source_BuildPeaks)(PCM_source* src, int mode); +#endif + +#if defined(REAPERAPI_WANT_PCM_Source_CreateFromFile) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// PCM_Source_CreateFromFile +// See PCM_Source_CreateFromFileEx. + + PCM_source* (*PCM_Source_CreateFromFile)(const char* filename); +#endif + +#if defined(REAPERAPI_WANT_PCM_Source_CreateFromFileEx) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// PCM_Source_CreateFromFileEx +// Create a PCM_source from filename, and override pref of MIDI files being imported as in-project MIDI events. + + PCM_source* (*PCM_Source_CreateFromFileEx)(const char* filename, bool forcenoMidiImp); +#endif + +#if defined(REAPERAPI_WANT_PCM_Source_CreateFromSimple) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// PCM_Source_CreateFromSimple +// Creates a PCM_source from a ISimpleMediaDecoder +// (if fn is non-null, it will open the file in dec) + + PCM_source* (*PCM_Source_CreateFromSimple)(ISimpleMediaDecoder* dec, const char* fn); +#endif + +#if defined(REAPERAPI_WANT_PCM_Source_CreateFromType) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// PCM_Source_CreateFromType +// Create a PCM_source from a "type" (use this if you're going to load its state via LoadState/ProjectStateContext). +// Valid types include "WAVE", "MIDI", or whatever plug-ins define as well. + + PCM_source* (*PCM_Source_CreateFromType)(const char* sourcetype); +#endif + +#if defined(REAPERAPI_WANT_PCM_Source_Destroy) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// PCM_Source_Destroy +// Deletes a PCM_source -- be sure that you remove any project reference before deleting a source + + void (*PCM_Source_Destroy)(PCM_source* src); +#endif + +#if defined(REAPERAPI_WANT_PCM_Source_GetPeaks) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// PCM_Source_GetPeaks +// Gets block of peak samples to buf. Note that the peak samples are interleaved, but in two or three blocks (maximums, then minimums, then extra). Return value has 20 bits of returned sample count, then 4 bits of output_mode (0xf00000), then a bit to signify whether extra_type was available (0x1000000). extra_type can be 115 ('s') for spectral information, which will return peak samples as integers with the low 15 bits frequency, next 14 bits tonality. + + int (*PCM_Source_GetPeaks)(PCM_source* src, double peakrate, double starttime, int numchannels, int numsamplesperchannel, int want_extra_type, double* buf); +#endif + +#if defined(REAPERAPI_WANT_PCM_Source_GetSectionInfo) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// PCM_Source_GetSectionInfo +// If a section/reverse block, retrieves offset/len/reverse. return true if success + + bool (*PCM_Source_GetSectionInfo)(PCM_source* src, double* offsOut, double* lenOut, bool* revOut); +#endif + +#if defined(REAPERAPI_WANT_PeakBuild_Create) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// PeakBuild_Create + + REAPER_PeakBuild_Interface* (*PeakBuild_Create)(PCM_source* src, const char* fn, int srate, int nch); +#endif + +#if defined(REAPERAPI_WANT_PeakBuild_CreateEx) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// PeakBuild_CreateEx +// flags&1 for FP support + + REAPER_PeakBuild_Interface* (*PeakBuild_CreateEx)(PCM_source* src, const char* fn, int srate, int nch, int flags); +#endif + +#if defined(REAPERAPI_WANT_PeakGet_Create) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// PeakGet_Create + + REAPER_PeakGet_Interface* (*PeakGet_Create)(const char* fn, int srate, int nch); +#endif + +#if defined(REAPERAPI_WANT_PitchShiftSubModeMenu) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// PitchShiftSubModeMenu +// menu to select/modify pitch shifter submode, returns new value (or old value if no item selected) + + int (*PitchShiftSubModeMenu)(HWND hwnd, int x, int y, int mode, int submode_sel); +#endif + +#if defined(REAPERAPI_WANT_PlayPreview) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// PlayPreview +// return nonzero on success + + int (*PlayPreview)(preview_register_t* preview); +#endif + +#if defined(REAPERAPI_WANT_PlayPreviewEx) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// PlayPreviewEx +// return nonzero on success. bufflags &1=buffer source, &2=treat length changes in source as varispeed and adjust internal state accordingly if buffering. measure_align<0=play immediately, >0=align playback with measure start + + int (*PlayPreviewEx)(preview_register_t* preview, int bufflags, double measure_align); +#endif + +#if defined(REAPERAPI_WANT_PlayTrackPreview) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// PlayTrackPreview +// return nonzero on success,in these,m_out_chan is a track index (0-n) + + int (*PlayTrackPreview)(preview_register_t* preview); +#endif + +#if defined(REAPERAPI_WANT_PlayTrackPreview2) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// PlayTrackPreview2 +// return nonzero on success,in these,m_out_chan is a track index (0-n) + + int (*PlayTrackPreview2)(ReaProject* proj, preview_register_t* preview); +#endif + +#if defined(REAPERAPI_WANT_PlayTrackPreview2Ex) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// PlayTrackPreview2Ex +// return nonzero on success,in these,m_out_chan is a track index (0-n). see PlayPreviewEx + + int (*PlayTrackPreview2Ex)(ReaProject* proj, preview_register_t* preview, int flags, double measure_align); +#endif + +#if defined(REAPERAPI_WANT_plugin_getapi) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// plugin_getapi + + void* (*plugin_getapi)(const char* name); +#endif + +#if defined(REAPERAPI_WANT_plugin_getFilterList) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// plugin_getFilterList +// Returns a double-NULL terminated list of importable media files, suitable for passing to GetOpenFileName() etc. Includes *.* (All files). + + const char* (*plugin_getFilterList)(); +#endif + +#if defined(REAPERAPI_WANT_plugin_getImportableProjectFilterList) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// plugin_getImportableProjectFilterList +// Returns a double-NULL terminated list of importable project files, suitable for passing to GetOpenFileName() etc. Includes *.* (All files). + + const char* (*plugin_getImportableProjectFilterList)(); +#endif + +#if defined(REAPERAPI_WANT_plugin_register) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// plugin_register +// Alias for reaper_plugin_info_t::Register, see reaper_plugin.h for documented uses. + + int (*plugin_register)(const char* name, void* infostruct); +#endif + +#if defined(REAPERAPI_WANT_PluginWantsAlwaysRunFx) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// PluginWantsAlwaysRunFx + + void (*PluginWantsAlwaysRunFx)(int amt); +#endif + +#if defined(REAPERAPI_WANT_PreventUIRefresh) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// PreventUIRefresh +// adds prevent_count to the UI refresh prevention state; always add then remove the same amount, or major disfunction will occur + + void (*PreventUIRefresh)(int prevent_count); +#endif + +#if defined(REAPERAPI_WANT_projectconfig_var_addr) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// projectconfig_var_addr + + void* (*projectconfig_var_addr)(ReaProject* proj, int idx); +#endif + +#if defined(REAPERAPI_WANT_projectconfig_var_getoffs) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// projectconfig_var_getoffs +// returns offset to pass to projectconfig_var_addr() to get project-config var of name. szout gets size of object. + + int (*projectconfig_var_getoffs)(const char* name, int* szOut); +#endif + +#if defined(REAPERAPI_WANT_PromptForAction) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// PromptForAction +// Uses the action list to choose an action. Call with session_mode=1 to create a session (init_id will be the initial action to select, or 0), then poll with session_mode=0, checking return value for user-selected action (will return 0 if no action selected yet, or -1 if the action window is no longer available). When finished, call with session_mode=-1. + + int (*PromptForAction)(int session_mode, int init_id, int section_id); +#endif + +#if defined(REAPERAPI_WANT_realloc_cmd_ptr) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// realloc_cmd_ptr +// special use for NeedBig script API functions - reallocates a NeedBig buffer and updates its size, returns false on error + + bool (*realloc_cmd_ptr)(char** ptr, int* ptr_size, int new_size); +#endif + +#if defined(REAPERAPI_WANT_ReaperGetPitchShiftAPI) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// ReaperGetPitchShiftAPI +// version must be REAPER_PITCHSHIFT_API_VER + + IReaperPitchShift* (*ReaperGetPitchShiftAPI)(int version); +#endif + +#if defined(REAPERAPI_WANT_ReaScriptError) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// ReaScriptError +// Causes REAPER to display the error message after the current ReaScript finishes. If called within a Lua context and errmsg has a ! prefix, script execution will be terminated. + + void (*ReaScriptError)(const char* errmsg); +#endif + +#if defined(REAPERAPI_WANT_RecursiveCreateDirectory) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// RecursiveCreateDirectory +// returns positive value on success, 0 on failure. + + int (*RecursiveCreateDirectory)(const char* path, size_t ignored); +#endif + +#if defined(REAPERAPI_WANT_reduce_open_files) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// reduce_open_files +// garbage-collects extra open files and closes them. if flags has 1 set, this is done incrementally (call this from a regular timer, if desired). if flags has 2 set, files are aggressively closed (they may need to be re-opened very soon). returns number of files closed by this call. + + int (*reduce_open_files)(int flags); +#endif + +#if defined(REAPERAPI_WANT_RefreshToolbar) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// RefreshToolbar +// See RefreshToolbar2. + + void (*RefreshToolbar)(int command_id); +#endif + +#if defined(REAPERAPI_WANT_RefreshToolbar2) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// RefreshToolbar2 +// Refresh the toolbar button states of a toggle action. + + void (*RefreshToolbar2)(int section_id, int command_id); +#endif + +#if defined(REAPERAPI_WANT_relative_fn) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// relative_fn +// Makes a filename "in" relative to the current project, if any. + + void (*relative_fn)(const char* in, char* out, int out_sz); +#endif + +#if defined(REAPERAPI_WANT_RemoveTrackSend) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// RemoveTrackSend +// Remove a send/receive/hardware output, return true on success. category is <0 for receives, 0=sends, >0 for hardware outputs. See CreateTrackSend, GetSetTrackSendInfo, GetTrackSendInfo_Value, SetTrackSendInfo_Value, GetTrackNumSends. + + bool (*RemoveTrackSend)(MediaTrack* tr, int category, int sendidx); +#endif + +#if defined(REAPERAPI_WANT_RenderFileSection) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// RenderFileSection +// Not available while playing back. + + bool (*RenderFileSection)(const char* source_filename, const char* target_filename, double start_percent, double end_percent, double playrate); +#endif + +#if defined(REAPERAPI_WANT_ReorderSelectedTracks) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// ReorderSelectedTracks +// Moves all selected tracks to immediately above track specified by index beforeTrackIdx, returns false if no tracks were selected. makePrevFolder=0 for normal, 1 = as child of track preceding track specified by beforeTrackIdx, 2 = if track preceding track specified by beforeTrackIdx is last track in folder, extend folder + + bool (*ReorderSelectedTracks)(int beforeTrackIdx, int makePrevFolder); +#endif + +#if defined(REAPERAPI_WANT_Resample_EnumModes) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// Resample_EnumModes + + const char* (*Resample_EnumModes)(int mode); +#endif + +#if defined(REAPERAPI_WANT_Resampler_Create) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// Resampler_Create + + REAPER_Resample_Interface* (*Resampler_Create)(); +#endif + +#if defined(REAPERAPI_WANT_resolve_fn) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// resolve_fn +// See resolve_fn2. + + void (*resolve_fn)(const char* in, char* out, int out_sz); +#endif + +#if defined(REAPERAPI_WANT_resolve_fn2) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// resolve_fn2 +// Resolves a filename "in" by using project settings etc. If no file found, out will be a copy of in. + + void (*resolve_fn2)(const char* in, char* out, int out_sz, const char* checkSubDirOptional); +#endif + +#if defined(REAPERAPI_WANT_ResolveRenderPattern) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// ResolveRenderPattern +// Resolve a wildcard pattern into a set of nul-separated, double-nul terminated render target filenames. Returns the length of the string buffer needed for the returned file list. Call with path=NULL to suppress filtering out illegal pathnames, call with targets=NULL to get just the string buffer length. + + int (*ResolveRenderPattern)(ReaProject* project, const char* path, const char* pattern, char* targets, int targets_sz); +#endif + +#if defined(REAPERAPI_WANT_ReverseNamedCommandLookup) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// ReverseNamedCommandLookup +// Get the named command for the given command ID. The returned string will not start with '_' (e.g. it will return "SWS_ABOUT"), it will be NULL if command_id is a native action. + + const char* (*ReverseNamedCommandLookup)(int command_id); +#endif + +#if defined(REAPERAPI_WANT_ScaleFromEnvelopeMode) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// ScaleFromEnvelopeMode +// See GetEnvelopeScalingMode. + + double (*ScaleFromEnvelopeMode)(int scaling_mode, double val); +#endif + +#if defined(REAPERAPI_WANT_ScaleToEnvelopeMode) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// ScaleToEnvelopeMode +// See GetEnvelopeScalingMode. + + double (*ScaleToEnvelopeMode)(int scaling_mode, double val); +#endif + +#if defined(REAPERAPI_WANT_screenset_register) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// screenset_register + + void (*screenset_register)(char* id, void* callbackFunc, void* param); +#endif + +#if defined(REAPERAPI_WANT_screenset_registerNew) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// screenset_registerNew + + void (*screenset_registerNew)(char* id, screensetNewCallbackFunc callbackFunc, void* param); +#endif + +#if defined(REAPERAPI_WANT_screenset_unregister) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// screenset_unregister + + void (*screenset_unregister)(char* id); +#endif + +#if defined(REAPERAPI_WANT_screenset_unregisterByParam) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// screenset_unregisterByParam + + void (*screenset_unregisterByParam)(void* param); +#endif + +#if defined(REAPERAPI_WANT_screenset_updateLastFocus) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// screenset_updateLastFocus + + void (*screenset_updateLastFocus)(HWND prevWin); +#endif + +#if defined(REAPERAPI_WANT_SectionFromUniqueID) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// SectionFromUniqueID + + KbdSectionInfo* (*SectionFromUniqueID)(int uniqueID); +#endif + +#if defined(REAPERAPI_WANT_SelectAllMediaItems) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// SelectAllMediaItems + + void (*SelectAllMediaItems)(ReaProject* proj, bool selected); +#endif + +#if defined(REAPERAPI_WANT_SelectProjectInstance) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// SelectProjectInstance + + void (*SelectProjectInstance)(ReaProject* proj); +#endif + +#if defined(REAPERAPI_WANT_SendLocalOscMessage) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// SendLocalOscMessage +// Send an OSC message to REAPER. See CreateLocalOscHandler, DestroyLocalOscHandler. + + void (*SendLocalOscMessage)(void* local_osc_handler, const char* msg, int msglen); +#endif + +#if defined(REAPERAPI_WANT_SetActiveTake) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// SetActiveTake +// set this take active in this media item + + void (*SetActiveTake)(MediaItem_Take* take); +#endif + +#if defined(REAPERAPI_WANT_SetAutomationMode) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// SetAutomationMode +// sets all or selected tracks to mode. + + void (*SetAutomationMode)(int mode, bool onlySel); +#endif + +#if defined(REAPERAPI_WANT_SetCurrentBPM) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// SetCurrentBPM +// set current BPM in project, set wantUndo=true to add undo point + + void (*SetCurrentBPM)(ReaProject* __proj, double bpm, bool wantUndo); +#endif + +#if defined(REAPERAPI_WANT_SetCursorContext) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// SetCursorContext +// You must use this to change the focus programmatically. mode=0 to focus track panels, 1 to focus the arrange window, 2 to focus the arrange window and select env (or env==NULL to clear the current track/take envelope selection) + + void (*SetCursorContext)(int mode, TrackEnvelope* envInOptional); +#endif + +#if defined(REAPERAPI_WANT_SetEditCurPos) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// SetEditCurPos + + void (*SetEditCurPos)(double time, bool moveview, bool seekplay); +#endif + +#if defined(REAPERAPI_WANT_SetEditCurPos2) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// SetEditCurPos2 + + void (*SetEditCurPos2)(ReaProject* proj, double time, bool moveview, bool seekplay); +#endif + +#if defined(REAPERAPI_WANT_SetEnvelopePoint) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// SetEnvelopePoint +// Set attributes of an envelope point. Values that are not supplied will be ignored. If setting multiple points at once, set noSort=true, and call Envelope_SortPoints when done. See SetEnvelopePointEx. + + bool (*SetEnvelopePoint)(TrackEnvelope* envelope, int ptidx, double* timeInOptional, double* valueInOptional, int* shapeInOptional, double* tensionInOptional, bool* selectedInOptional, bool* noSortInOptional); +#endif + +#if defined(REAPERAPI_WANT_SetEnvelopePointEx) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// SetEnvelopePointEx +// Set attributes of an envelope point. Values that are not supplied will be ignored. If setting multiple points at once, set noSort=true, and call Envelope_SortPoints when done. +// autoitem_idx=-1 for the underlying envelope, 0 for the first automation item on the envelope, etc. +// For automation items, pass autoitem_idx|0x10000000 to base ptidx on the number of points in one full loop iteration, +// even if the automation item is trimmed so that not all points are visible. +// Otherwise, ptidx will be based on the number of visible points in the automation item, including all loop iterations. +// See CountEnvelopePointsEx, GetEnvelopePointEx, InsertEnvelopePointEx, DeleteEnvelopePointEx. + + bool (*SetEnvelopePointEx)(TrackEnvelope* envelope, int autoitem_idx, int ptidx, double* timeInOptional, double* valueInOptional, int* shapeInOptional, double* tensionInOptional, bool* selectedInOptional, bool* noSortInOptional); +#endif + +#if defined(REAPERAPI_WANT_SetEnvelopeStateChunk) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// SetEnvelopeStateChunk +// Sets the RPPXML state of an envelope, returns true if successful. Undo flag is a performance/caching hint. + + bool (*SetEnvelopeStateChunk)(TrackEnvelope* env, const char* str, bool isundoOptional); +#endif + +#if defined(REAPERAPI_WANT_SetExtState) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// SetExtState +// Set the extended state value for a specific section and key. persist=true means the value should be stored and reloaded the next time REAPER is opened. See GetExtState, DeleteExtState, HasExtState. + + void (*SetExtState)(const char* section, const char* key, const char* value, bool persist); +#endif + +#if defined(REAPERAPI_WANT_SetGlobalAutomationOverride) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// SetGlobalAutomationOverride +// mode: see GetGlobalAutomationOverride + + void (*SetGlobalAutomationOverride)(int mode); +#endif + +#if defined(REAPERAPI_WANT_SetItemStateChunk) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// SetItemStateChunk +// Sets the RPPXML state of an item, returns true if successful. Undo flag is a performance/caching hint. + + bool (*SetItemStateChunk)(MediaItem* item, const char* str, bool isundoOptional); +#endif + +#if defined(REAPERAPI_WANT_SetMasterTrackVisibility) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// SetMasterTrackVisibility +// set &1 to show the master track in the TCP, &2 to HIDE in the mixer. Returns the previous visibility state. See GetMasterTrackVisibility. + + int (*SetMasterTrackVisibility)(int flag); +#endif + +#if defined(REAPERAPI_WANT_SetMediaItemInfo_Value) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// SetMediaItemInfo_Value +// Set media item numerical-value attributes. +// B_MUTE : bool * : muted (item solo overrides). setting this value will clear C_MUTE_SOLO. +// B_MUTE_ACTUAL : bool * : muted (ignores solo). setting this value will not affect C_MUTE_SOLO. +// C_MUTE_SOLO : char * : solo override (-1=soloed, 0=no override, 1=unsoloed). note that this API does not automatically unsolo other items when soloing (nor clear the unsolos when clearing the last soloed item), it must be done by the caller via action or via this API. +// B_LOOPSRC : bool * : loop source +// B_ALLTAKESPLAY : bool * : all takes play +// B_UISEL : bool * : selected in arrange view +// C_BEATATTACHMODE : char * : item timebase, -1=track or project default, 1=beats (position, length, rate), 2=beats (position only). for auto-stretch timebase: C_BEATATTACHMODE=1, C_AUTOSTRETCH=1 +// C_AUTOSTRETCH: : char * : auto-stretch at project tempo changes, 1=enabled, requires C_BEATATTACHMODE=1 +// C_LOCK : char * : locked, &1=locked +// D_VOL : double * : item volume, 0=-inf, 0.5=-6dB, 1=+0dB, 2=+6dB, etc +// D_POSITION : double * : item position in seconds +// D_LENGTH : double * : item length in seconds +// D_SNAPOFFSET : double * : item snap offset in seconds +// D_FADEINLEN : double * : item manual fadein length in seconds +// D_FADEOUTLEN : double * : item manual fadeout length in seconds +// D_FADEINDIR : double * : item fadein curvature, -1..1 +// D_FADEOUTDIR : double * : item fadeout curvature, -1..1 +// D_FADEINLEN_AUTO : double * : item auto-fadein length in seconds, -1=no auto-fadein +// D_FADEOUTLEN_AUTO : double * : item auto-fadeout length in seconds, -1=no auto-fadeout +// C_FADEINSHAPE : int * : fadein shape, 0..6, 0=linear +// C_FADEOUTSHAPE : int * : fadeout shape, 0..6, 0=linear +// I_GROUPID : int * : group ID, 0=no group +// I_LASTY : int * : Y-position (relative to top of track) in pixels (read-only) +// I_LASTH : int * : height in pixels (read-only) +// I_CUSTOMCOLOR : int * : custom color, OS dependent color|0x1000000 (i.e. ColorToNative(r,g,b)|0x1000000). If you do not |0x1000000, then it will not be used, but will store the color +// I_CURTAKE : int * : active take number +// IP_ITEMNUMBER : int : item number on this track (read-only, returns the item number directly) +// F_FREEMODE_Y : float * : free item positioning Y-position, 0=top of track, 1=bottom of track (will never be 1) +// F_FREEMODE_H : float * : free item positioning height, 0=no height, 1=full height of track (will never be 0) +// + + bool (*SetMediaItemInfo_Value)(MediaItem* item, const char* parmname, double newvalue); +#endif + +#if defined(REAPERAPI_WANT_SetMediaItemLength) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// SetMediaItemLength +// Redraws the screen only if refreshUI == true. +// See UpdateArrange(). + + bool (*SetMediaItemLength)(MediaItem* item, double length, bool refreshUI); +#endif + +#if defined(REAPERAPI_WANT_SetMediaItemPosition) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// SetMediaItemPosition +// Redraws the screen only if refreshUI == true. +// See UpdateArrange(). + + bool (*SetMediaItemPosition)(MediaItem* item, double position, bool refreshUI); +#endif + +#if defined(REAPERAPI_WANT_SetMediaItemSelected) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// SetMediaItemSelected + + void (*SetMediaItemSelected)(MediaItem* item, bool selected); +#endif + +#if defined(REAPERAPI_WANT_SetMediaItemTake_Source) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// SetMediaItemTake_Source +// Set media source of media item take. The old source will not be destroyed, it is the caller's responsibility to retrieve it and destroy it after. If source already exists in any project, it will be duplicated before being set. C/C++ code should not use this and instead use GetSetMediaItemTakeInfo() with P_SOURCE to manage ownership directly. + + bool (*SetMediaItemTake_Source)(MediaItem_Take* take, PCM_source* source); +#endif + +#if defined(REAPERAPI_WANT_SetMediaItemTakeInfo_Value) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// SetMediaItemTakeInfo_Value +// Set media item take numerical-value attributes. +// D_STARTOFFS : double * : start offset in source media, in seconds +// D_VOL : double * : take volume, 0=-inf, 0.5=-6dB, 1=+0dB, 2=+6dB, etc, negative if take polarity is flipped +// D_PAN : double * : take pan, -1..1 +// D_PANLAW : double * : take pan law, -1=default, 0.5=-6dB, 1.0=+0dB, etc +// D_PLAYRATE : double * : take playback rate, 0.5=half speed, 1=normal, 2=double speed, etc +// D_PITCH : double * : take pitch adjustment in semitones, -12=one octave down, 0=normal, +12=one octave up, etc +// B_PPITCH : bool * : preserve pitch when changing playback rate +// I_LASTY : int * : Y-position (relative to top of track) in pixels (read-only) +// I_LASTH : int * : height in pixels (read-only) +// I_CHANMODE : int * : channel mode, 0=normal, 1=reverse stereo, 2=downmix, 3=left, 4=right +// I_PITCHMODE : int * : pitch shifter mode, -1=projext default, otherwise high 2 bytes=shifter, low 2 bytes=parameter +// I_CUSTOMCOLOR : int * : custom color, OS dependent color|0x1000000 (i.e. ColorToNative(r,g,b)|0x1000000). If you do not |0x1000000, then it will not be used, but will store the color +// IP_TAKENUMBER : int : take number (read-only, returns the take number directly) +// + + bool (*SetMediaItemTakeInfo_Value)(MediaItem_Take* take, const char* parmname, double newvalue); +#endif + +#if defined(REAPERAPI_WANT_SetMediaTrackInfo_Value) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// SetMediaTrackInfo_Value +// Set track numerical-value attributes. +// B_MUTE : bool * : muted +// B_PHASE : bool * : track phase inverted +// B_RECMON_IN_EFFECT : bool * : record monitoring in effect (current audio-thread playback state, read-only) +// IP_TRACKNUMBER : int : track number 1-based, 0=not found, -1=master track (read-only, returns the int directly) +// I_SOLO : int * : soloed, 0=not soloed, 1=soloed, 2=soloed in place, 5=safe soloed, 6=safe soloed in place +// B_SOLO_DEFEAT : bool * : when set, if anything else is soloed and this track is not muted, this track acts soloed +// I_FXEN : int * : fx enabled, 0=bypassed, !0=fx active +// I_RECARM : int * : record armed, 0=not record armed, 1=record armed +// I_RECINPUT : int * : record input, <0=no input. if 4096 set, input is MIDI and low 5 bits represent channel (0=all, 1-16=only chan), next 6 bits represent physical input (63=all, 62=VKB). If 4096 is not set, low 10 bits (0..1023) are input start channel (ReaRoute/Loopback start at 512). If 2048 is set, input is multichannel input (using track channel count), or if 1024 is set, input is stereo input, otherwise input is mono. +// I_RECMODE : int * : record mode, 0=input, 1=stereo out, 2=none, 3=stereo out w/latency compensation, 4=midi output, 5=mono out, 6=mono out w/ latency compensation, 7=midi overdub, 8=midi replace +// I_RECMON : int * : record monitoring, 0=off, 1=normal, 2=not when playing (tape style) +// I_RECMONITEMS : int * : monitor items while recording, 0=off, 1=on +// B_AUTO_RECARM : bool * : automatically set record arm when selected (does not immediately affect recarm state, script should set directly if desired) +// I_VUMODE : int * : track vu mode, &1:disabled, &30==0:stereo peaks, &30==2:multichannel peaks, &30==4:stereo RMS, &30==8:combined RMS, &30==12:LUFS-M, &30==16:LUFS-S (readout=max), &30==20:LUFS-S (readout=current), &32:LUFS calculation on channels 1+2 only +// I_AUTOMODE : int * : track automation mode, 0=trim/off, 1=read, 2=touch, 3=write, 4=latch +// I_NCHAN : int * : number of track channels, 2-64, even numbers only +// I_SELECTED : int * : track selected, 0=unselected, 1=selected +// I_WNDH : int * : current TCP window height in pixels including envelopes (read-only) +// I_TCPH : int * : current TCP window height in pixels not including envelopes (read-only) +// I_TCPY : int * : current TCP window Y-position in pixels relative to top of arrange view (read-only) +// I_MCPX : int * : current MCP X-position in pixels relative to mixer container (read-only) +// I_MCPY : int * : current MCP Y-position in pixels relative to mixer container (read-only) +// I_MCPW : int * : current MCP width in pixels (read-only) +// I_MCPH : int * : current MCP height in pixels (read-only) +// I_FOLDERDEPTH : int * : folder depth change, 0=normal, 1=track is a folder parent, -1=track is the last in the innermost folder, -2=track is the last in the innermost and next-innermost folders, etc +// I_FOLDERCOMPACT : int * : folder compacted state (only valid on folders), 0=normal, 1=small, 2=tiny children +// I_MIDIHWOUT : int * : track midi hardware output index, <0=disabled, low 5 bits are which channels (0=all, 1-16), next 5 bits are output device index (0-31) +// I_PERFFLAGS : int * : track performance flags, &1=no media buffering, &2=no anticipative FX +// I_CUSTOMCOLOR : int * : custom color, OS dependent color|0x1000000 (i.e. ColorToNative(r,g,b)|0x1000000). If you do not |0x1000000, then it will not be used, but will store the color +// I_HEIGHTOVERRIDE : int * : custom height override for TCP window, 0 for none, otherwise size in pixels +// B_HEIGHTLOCK : bool * : track height lock (must set I_HEIGHTOVERRIDE before locking) +// D_VOL : double * : trim volume of track, 0=-inf, 0.5=-6dB, 1=+0dB, 2=+6dB, etc +// D_PAN : double * : trim pan of track, -1..1 +// D_WIDTH : double * : width of track, -1..1 +// D_DUALPANL : double * : dualpan position 1, -1..1, only if I_PANMODE==6 +// D_DUALPANR : double * : dualpan position 2, -1..1, only if I_PANMODE==6 +// I_PANMODE : int * : pan mode, 0=classic 3.x, 3=new balance, 5=stereo pan, 6=dual pan +// D_PANLAW : double * : pan law of track, <0=project default, 1=+0dB, etc +// P_ENV:<envchunkname or P_ENV:{GUID... : TrackEnvelope * : (read-only) chunkname can be <VOLENV, <PANENV, etc; GUID is the stringified envelope GUID. +// B_SHOWINMIXER : bool * : track control panel visible in mixer (do not use on master track) +// B_SHOWINTCP : bool * : track control panel visible in arrange view (do not use on master track) +// B_MAINSEND : bool * : track sends audio to parent +// C_MAINSEND_OFFS : char * : channel offset of track send to parent +// C_MAINSEND_NCH : char * : channel count of track send to parent (0=use all child track channels, 1=use one channel only) +// B_FREEMODE : bool * : track free item positioning enabled (call UpdateTimeline() after changing) +// C_BEATATTACHMODE : char * : track timebase, -1=project default, 0=time, 1=beats (position, length, rate), 2=beats (position only) +// F_MCP_FXSEND_SCALE : float * : scale of fx+send area in MCP (0=minimum allowed, 1=maximum allowed) +// F_MCP_FXPARM_SCALE : float * : scale of fx parameter area in MCP (0=minimum allowed, 1=maximum allowed) +// F_MCP_SENDRGN_SCALE : float * : scale of send area as proportion of the fx+send total area (0=minimum allowed, 1=maximum allowed) +// F_TCP_FXPARM_SCALE : float * : scale of TCP parameter area when TCP FX are embedded (0=min allowed, default, 1=max allowed) +// I_PLAY_OFFSET_FLAG : int * : track media playback offset state, &1=bypassed, &2=offset value is measured in samples (otherwise measured in seconds) +// D_PLAY_OFFSET : double * : track media playback offset, units depend on I_PLAY_OFFSET_FLAG +// + + bool (*SetMediaTrackInfo_Value)(MediaTrack* tr, const char* parmname, double newvalue); +#endif + +#if defined(REAPERAPI_WANT_SetMIDIEditorGrid) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// SetMIDIEditorGrid +// Set the MIDI editor grid division. 0.25=quarter note, 1.0/3.0=half note tripet, etc. + + void (*SetMIDIEditorGrid)(ReaProject* project, double division); +#endif + +#if defined(REAPERAPI_WANT_SetMixerScroll) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// SetMixerScroll +// Scroll the mixer so that leftmosttrack is the leftmost visible track. Returns the leftmost track after scrolling, which may be different from the passed-in track if there are not enough tracks to its right. + + MediaTrack* (*SetMixerScroll)(MediaTrack* leftmosttrack); +#endif + +#if defined(REAPERAPI_WANT_SetMouseModifier) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// SetMouseModifier +// Set the mouse modifier assignment for a specific modifier key assignment, in a specific context. +// Context is a string like "MM_CTX_ITEM". Find these strings by modifying an assignment in +// Preferences/Editing/Mouse Modifiers, then looking in reaper-mouse.ini. +// Modifier flag is a number from 0 to 15: add 1 for shift, 2 for control, 4 for alt, 8 for win. +// (macOS: add 1 for shift, 2 for command, 4 for opt, 8 for control.) +// For left-click and double-click contexts, the action can be any built-in command ID number +// or any custom action ID string. Find built-in command IDs in the REAPER actions window +// (enable "show action IDs" in the context menu), and find custom action ID strings in reaper-kb.ini. +// For built-in mouse modifier behaviors, find action IDs (which will be low numbers) +// by modifying an assignment in Preferences/Editing/Mouse Modifiers, then looking in reaper-mouse.ini. +// Assigning an action of -1 will reset that mouse modifier behavior to factory default. +// See GetMouseModifier. +// + + void (*SetMouseModifier)(const char* context, int modifier_flag, const char* action); +#endif + +#if defined(REAPERAPI_WANT_SetOnlyTrackSelected) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// SetOnlyTrackSelected +// Set exactly one track selected, deselect all others + + void (*SetOnlyTrackSelected)(MediaTrack* track); +#endif + +#if defined(REAPERAPI_WANT_SetProjectGrid) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// SetProjectGrid +// Set the arrange view grid division. 0.25=quarter note, 1.0/3.0=half note triplet, etc. + + void (*SetProjectGrid)(ReaProject* project, double division); +#endif + +#if defined(REAPERAPI_WANT_SetProjectMarker) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// SetProjectMarker + + bool (*SetProjectMarker)(int markrgnindexnumber, bool isrgn, double pos, double rgnend, const char* name); +#endif + +#if defined(REAPERAPI_WANT_SetProjectMarker2) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// SetProjectMarker2 + + bool (*SetProjectMarker2)(ReaProject* proj, int markrgnindexnumber, bool isrgn, double pos, double rgnend, const char* name); +#endif + +#if defined(REAPERAPI_WANT_SetProjectMarker3) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// SetProjectMarker3 + + bool (*SetProjectMarker3)(ReaProject* proj, int markrgnindexnumber, bool isrgn, double pos, double rgnend, const char* name, int color); +#endif + +#if defined(REAPERAPI_WANT_SetProjectMarker4) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// SetProjectMarker4 +// color should be 0 to not change, or ColorToNative(r,g,b)|0x1000000, flags&1 to clear name + + bool (*SetProjectMarker4)(ReaProject* proj, int markrgnindexnumber, bool isrgn, double pos, double rgnend, const char* name, int color, int flags); +#endif + +#if defined(REAPERAPI_WANT_SetProjectMarkerByIndex) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// SetProjectMarkerByIndex +// See SetProjectMarkerByIndex2. + + bool (*SetProjectMarkerByIndex)(ReaProject* proj, int markrgnidx, bool isrgn, double pos, double rgnend, int IDnumber, const char* name, int color); +#endif + +#if defined(REAPERAPI_WANT_SetProjectMarkerByIndex2) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// SetProjectMarkerByIndex2 +// Differs from SetProjectMarker4 in that markrgnidx is 0 for the first marker/region, 1 for the next, etc (see EnumProjectMarkers3), rather than representing the displayed marker/region ID number (see SetProjectMarker3). Function will fail if attempting to set a duplicate ID number for a region (duplicate ID numbers for markers are OK). , flags&1 to clear name. + + bool (*SetProjectMarkerByIndex2)(ReaProject* proj, int markrgnidx, bool isrgn, double pos, double rgnend, int IDnumber, const char* name, int color, int flags); +#endif + +#if defined(REAPERAPI_WANT_SetProjExtState) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// SetProjExtState +// Save a key/value pair for a specific extension, to be restored the next time this specific project is loaded. Typically extname will be the name of a reascript or extension section. If key is NULL or "", all extended data for that extname will be deleted. If val is NULL or "", the data previously associated with that key will be deleted. Returns the size of the state for this extname. See GetProjExtState, EnumProjExtState. + + int (*SetProjExtState)(ReaProject* proj, const char* extname, const char* key, const char* value); +#endif + +#if defined(REAPERAPI_WANT_SetRegionRenderMatrix) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// SetRegionRenderMatrix +// Add (addorremove > 0) or remove (addorremove < 0) a track from this region when using the region render matrix. + + void (*SetRegionRenderMatrix)(ReaProject* proj, int regionindex, MediaTrack* track, int addorremove); +#endif + +#if defined(REAPERAPI_WANT_SetRenderLastError) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// SetRenderLastError +// Used by pcmsink objects to set an error to display while creating the pcmsink object. + + void (*SetRenderLastError)(const char* errorstr); +#endif + +#if defined(REAPERAPI_WANT_SetTakeMarker) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// SetTakeMarker +// Inserts or updates a take marker. If idx<0, a take marker will be added, otherwise an existing take marker will be updated. Returns the index of the new or updated take marker (which may change if srcPos is updated). See GetNumTakeMarkers, GetTakeMarker, DeleteTakeMarker + + int (*SetTakeMarker)(MediaItem_Take* take, int idx, const char* nameIn, double* srcposInOptional, int* colorInOptional); +#endif + +#if defined(REAPERAPI_WANT_SetTakeStretchMarker) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// SetTakeStretchMarker +// Adds or updates a stretch marker. If idx<0, stretch marker will be added. If idx>=0, stretch marker will be updated. When adding, if srcposInOptional is omitted, source position will be auto-calculated. When updating a stretch marker, if srcposInOptional is omitted, srcpos will not be modified. Position/srcposition values will be constrained to nearby stretch markers. Returns index of stretch marker, or -1 if did not insert (or marker already existed at time). + + int (*SetTakeStretchMarker)(MediaItem_Take* take, int idx, double pos, const double* srcposInOptional); +#endif + +#if defined(REAPERAPI_WANT_SetTakeStretchMarkerSlope) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// SetTakeStretchMarkerSlope +// See GetTakeStretchMarkerSlope + + bool (*SetTakeStretchMarkerSlope)(MediaItem_Take* take, int idx, double slope); +#endif + +#if defined(REAPERAPI_WANT_SetTempoTimeSigMarker) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// SetTempoTimeSigMarker +// Set parameters of a tempo/time signature marker. Provide either timepos (with measurepos=-1, beatpos=-1), or measurepos and beatpos (with timepos=-1). If timesig_num and timesig_denom are zero, the previous time signature will be used. ptidx=-1 will insert a new tempo/time signature marker. See CountTempoTimeSigMarkers, GetTempoTimeSigMarker, AddTempoTimeSigMarker. + + bool (*SetTempoTimeSigMarker)(ReaProject* proj, int ptidx, double timepos, int measurepos, double beatpos, double bpm, int timesig_num, int timesig_denom, bool lineartempo); +#endif + +#if defined(REAPERAPI_WANT_SetThemeColor) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// SetThemeColor +// Temporarily updates the theme color to the color specified (or the theme default color if -1 is specified). Returns -1 on failure, otherwise returns the color (or transformed-color). Note that the UI is not updated by this, the caller should call UpdateArrange() etc as necessary. If the low bit of flags is set, any color transformations are bypassed. To read a value see GetThemeColor. + + int (*SetThemeColor)(const char* ini_key, int color, int flagsOptional); +#endif + +#if defined(REAPERAPI_WANT_SetToggleCommandState) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// SetToggleCommandState +// Updates the toggle state of an action, returns true if succeeded. Only ReaScripts can have their toggle states changed programmatically. See RefreshToolbar2. + + bool (*SetToggleCommandState)(int section_id, int command_id, int state); +#endif + +#if defined(REAPERAPI_WANT_SetTrackAutomationMode) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// SetTrackAutomationMode + + void (*SetTrackAutomationMode)(MediaTrack* tr, int mode); +#endif + +#if defined(REAPERAPI_WANT_SetTrackColor) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// SetTrackColor +// Set the custom track color, color is OS dependent (i.e. ColorToNative(r,g,b). To unset the track color, see SetMediaTrackInfo_Value I_CUSTOMCOLOR + + void (*SetTrackColor)(MediaTrack* track, int color); +#endif + +#if defined(REAPERAPI_WANT_SetTrackMIDILyrics) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// SetTrackMIDILyrics +// Set all MIDI lyrics on the track. Lyrics will be stuffed into any MIDI items found in range. Flag is unused at present. str is passed in as beat position, tab, text, tab (example with flag=2: "1.1.2\tLyric for measure 1 beat 2\t.1.1\tLyric for measure 2 beat 1 "). See GetTrackMIDILyrics + + bool (*SetTrackMIDILyrics)(MediaTrack* track, int flag, const char* str); +#endif + +#if defined(REAPERAPI_WANT_SetTrackMIDINoteName) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// SetTrackMIDINoteName +// channel < 0 assigns these note names to all channels. + + bool (*SetTrackMIDINoteName)(int track, int pitch, int chan, const char* name); +#endif + +#if defined(REAPERAPI_WANT_SetTrackMIDINoteNameEx) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// SetTrackMIDINoteNameEx +// channel < 0 assigns note name to all channels. pitch 128 assigns name for CC0, pitch 129 for CC1, etc. + + bool (*SetTrackMIDINoteNameEx)(ReaProject* proj, MediaTrack* track, int pitch, int chan, const char* name); +#endif + +#if defined(REAPERAPI_WANT_SetTrackSelected) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// SetTrackSelected + + void (*SetTrackSelected)(MediaTrack* track, bool selected); +#endif + +#if defined(REAPERAPI_WANT_SetTrackSendInfo_Value) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// SetTrackSendInfo_Value +// Set send/receive/hardware output numerical-value attributes, return true on success. +// category is <0 for receives, 0=sends, >0 for hardware outputs +// parameter names: +// B_MUTE : bool * +// B_PHASE : bool * : true to flip phase +// B_MONO : bool * +// D_VOL : double * : 1.0 = +0dB etc +// D_PAN : double * : -1..+1 +// D_PANLAW : double * : 1.0=+0.0db, 0.5=-6dB, -1.0 = projdef etc +// I_SENDMODE : int * : 0=post-fader, 1=pre-fx, 2=post-fx (deprecated), 3=post-fx +// I_AUTOMODE : int * : automation mode (-1=use track automode, 0=trim/off, 1=read, 2=touch, 3=write, 4=latch) +// I_SRCCHAN : int * : index,&1024=mono, -1 for none +// I_DSTCHAN : int * : index, &1024=mono, otherwise stereo pair, hwout:&512=rearoute +// I_MIDIFLAGS : int * : low 5 bits=source channel 0=all, 1-16, next 5 bits=dest channel, 0=orig, 1-16=chan +// See CreateTrackSend, RemoveTrackSend, GetTrackNumSends. + + bool (*SetTrackSendInfo_Value)(MediaTrack* tr, int category, int sendidx, const char* parmname, double newvalue); +#endif + +#if defined(REAPERAPI_WANT_SetTrackSendUIPan) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// SetTrackSendUIPan +// send_idx<0 for receives, >=0 for hw ouputs, >=nb_of_hw_ouputs for sends. isend=1 for end of edit, -1 for an instant edit (such as reset), 0 for normal tweak. + + bool (*SetTrackSendUIPan)(MediaTrack* track, int send_idx, double pan, int isend); +#endif + +#if defined(REAPERAPI_WANT_SetTrackSendUIVol) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// SetTrackSendUIVol +// send_idx<0 for receives, >=0 for hw ouputs, >=nb_of_hw_ouputs for sends. isend=1 for end of edit, -1 for an instant edit (such as reset), 0 for normal tweak. + + bool (*SetTrackSendUIVol)(MediaTrack* track, int send_idx, double vol, int isend); +#endif + +#if defined(REAPERAPI_WANT_SetTrackStateChunk) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// SetTrackStateChunk +// Sets the RPPXML state of a track, returns true if successful. Undo flag is a performance/caching hint. + + bool (*SetTrackStateChunk)(MediaTrack* track, const char* str, bool isundoOptional); +#endif + +#if defined(REAPERAPI_WANT_ShowActionList) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// ShowActionList + + void (*ShowActionList)(KbdSectionInfo* caller, HWND callerWnd); +#endif + +#if defined(REAPERAPI_WANT_ShowConsoleMsg) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// ShowConsoleMsg +// Show a message to the user (also useful for debugging). Send "\n" for newline, "" to clear the console. See ClearConsole + + void (*ShowConsoleMsg)(const char* msg); +#endif + +#if defined(REAPERAPI_WANT_ShowMessageBox) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// ShowMessageBox +// type 0=OK,1=OKCANCEL,2=ABORTRETRYIGNORE,3=YESNOCANCEL,4=YESNO,5=RETRYCANCEL : ret 1=OK,2=CANCEL,3=ABORT,4=RETRY,5=IGNORE,6=YES,7=NO + + int (*ShowMessageBox)(const char* msg, const char* title, int type); +#endif + +#if defined(REAPERAPI_WANT_ShowPopupMenu) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// ShowPopupMenu +// shows a context menu, valid names include: track_input, track_panel, track_area, track_routing, item, ruler, envelope, envelope_point, envelope_item. ctxOptional can be a track pointer for track_*, item pointer for item* (but is optional). for envelope_point, ctx2Optional has point index, ctx3Optional has item index (0=main envelope, 1=first AI). for envelope_item, ctx2Optional has AI index (1=first AI) + + void (*ShowPopupMenu)(const char* name, int x, int y, HWND hwndParentOptional, void* ctxOptional, int ctx2Optional, int ctx3Optional); +#endif + +#if defined(REAPERAPI_WANT_SLIDER2DB) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// SLIDER2DB + + double (*SLIDER2DB)(double y); +#endif + +#if defined(REAPERAPI_WANT_SnapToGrid) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// SnapToGrid + + double (*SnapToGrid)(ReaProject* project, double time_pos); +#endif + +#if defined(REAPERAPI_WANT_SoloAllTracks) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// SoloAllTracks +// solo=2 for SIP + + void (*SoloAllTracks)(int solo); +#endif + +#if defined(REAPERAPI_WANT_Splash_GetWnd) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// Splash_GetWnd +// gets the splash window, in case you want to display a message over it. Returns NULL when the splash window is not displayed. + + HWND (*Splash_GetWnd)(); +#endif + +#if defined(REAPERAPI_WANT_SplitMediaItem) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// SplitMediaItem +// the original item becomes the left-hand split, the function returns the right-hand split (or NULL if the split failed) + + MediaItem* (*SplitMediaItem)(MediaItem* item, double position); +#endif + +#if defined(REAPERAPI_WANT_StopPreview) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// StopPreview +// return nonzero on success + + int (*StopPreview)(preview_register_t* preview); +#endif + +#if defined(REAPERAPI_WANT_StopTrackPreview) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// StopTrackPreview +// return nonzero on success + + int (*StopTrackPreview)(preview_register_t* preview); +#endif + +#if defined(REAPERAPI_WANT_StopTrackPreview2) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// StopTrackPreview2 +// return nonzero on success + + int (*StopTrackPreview2)(ReaProject* proj, preview_register_t* preview); +#endif + +#if defined(REAPERAPI_WANT_stringToGuid) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// stringToGuid + + void (*stringToGuid)(const char* str, GUID* g); +#endif + +#if defined(REAPERAPI_WANT_StuffMIDIMessage) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// StuffMIDIMessage +// Stuffs a 3 byte MIDI message into either the Virtual MIDI Keyboard queue, or the MIDI-as-control input queue, or sends to a MIDI hardware output. mode=0 for VKB, 1 for control (actions map etc), 2 for VKB-on-current-channel; 16 for external MIDI device 0, 17 for external MIDI device 1, etc; see GetNumMIDIOutputs, GetMIDIOutputName. + + void (*StuffMIDIMessage)(int mode, int msg1, int msg2, int msg3); +#endif + +#if defined(REAPERAPI_WANT_TakeFX_AddByName) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// TakeFX_AddByName +// Adds or queries the position of a named FX in a take. See TrackFX_AddByName() for information on fxname and instantiate. + + int (*TakeFX_AddByName)(MediaItem_Take* take, const char* fxname, int instantiate); +#endif + +#if defined(REAPERAPI_WANT_TakeFX_CopyToTake) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// TakeFX_CopyToTake +// Copies (or moves) FX from src_take to dest_take. Can be used with src_take=dest_take to reorder. + + void (*TakeFX_CopyToTake)(MediaItem_Take* src_take, int src_fx, MediaItem_Take* dest_take, int dest_fx, bool is_move); +#endif + +#if defined(REAPERAPI_WANT_TakeFX_CopyToTrack) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// TakeFX_CopyToTrack +// Copies (or moves) FX from src_take to dest_track. dest_fx can have 0x1000000 set to reference input FX. + + void (*TakeFX_CopyToTrack)(MediaItem_Take* src_take, int src_fx, MediaTrack* dest_track, int dest_fx, bool is_move); +#endif + +#if defined(REAPERAPI_WANT_TakeFX_Delete) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// TakeFX_Delete +// Remove a FX from take chain (returns true on success) + + bool (*TakeFX_Delete)(MediaItem_Take* take, int fx); +#endif + +#if defined(REAPERAPI_WANT_TakeFX_EndParamEdit) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// TakeFX_EndParamEdit + + bool (*TakeFX_EndParamEdit)(MediaItem_Take* take, int fx, int param); +#endif + +#if defined(REAPERAPI_WANT_TakeFX_FormatParamValue) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// TakeFX_FormatParamValue +// Note: only works with FX that support Cockos VST extensions. + + bool (*TakeFX_FormatParamValue)(MediaItem_Take* take, int fx, int param, double val, char* bufOut, int bufOut_sz); +#endif + +#if defined(REAPERAPI_WANT_TakeFX_FormatParamValueNormalized) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// TakeFX_FormatParamValueNormalized +// Note: only works with FX that support Cockos VST extensions. + + bool (*TakeFX_FormatParamValueNormalized)(MediaItem_Take* take, int fx, int param, double value, char* buf, int buf_sz); +#endif + +#if defined(REAPERAPI_WANT_TakeFX_GetChainVisible) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// TakeFX_GetChainVisible +// returns index of effect visible in chain, or -1 for chain hidden, or -2 for chain visible but no effect selected + + int (*TakeFX_GetChainVisible)(MediaItem_Take* take); +#endif + +#if defined(REAPERAPI_WANT_TakeFX_GetCount) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// TakeFX_GetCount + + int (*TakeFX_GetCount)(MediaItem_Take* take); +#endif + +#if defined(REAPERAPI_WANT_TakeFX_GetEnabled) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// TakeFX_GetEnabled +// See TakeFX_SetEnabled + + bool (*TakeFX_GetEnabled)(MediaItem_Take* take, int fx); +#endif + +#if defined(REAPERAPI_WANT_TakeFX_GetEnvelope) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// TakeFX_GetEnvelope +// Returns the FX parameter envelope. If the envelope does not exist and create=true, the envelope will be created. + + TrackEnvelope* (*TakeFX_GetEnvelope)(MediaItem_Take* take, int fxindex, int parameterindex, bool create); +#endif + +#if defined(REAPERAPI_WANT_TakeFX_GetFloatingWindow) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// TakeFX_GetFloatingWindow +// returns HWND of floating window for effect index, if any + + HWND (*TakeFX_GetFloatingWindow)(MediaItem_Take* take, int index); +#endif + +#if defined(REAPERAPI_WANT_TakeFX_GetFormattedParamValue) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// TakeFX_GetFormattedParamValue + + bool (*TakeFX_GetFormattedParamValue)(MediaItem_Take* take, int fx, int param, char* bufOut, int bufOut_sz); +#endif + +#if defined(REAPERAPI_WANT_TakeFX_GetFXGUID) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// TakeFX_GetFXGUID + + GUID* (*TakeFX_GetFXGUID)(MediaItem_Take* take, int fx); +#endif + +#if defined(REAPERAPI_WANT_TakeFX_GetFXName) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// TakeFX_GetFXName + + bool (*TakeFX_GetFXName)(MediaItem_Take* take, int fx, char* bufOut, int bufOut_sz); +#endif + +#if defined(REAPERAPI_WANT_TakeFX_GetIOSize) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// TakeFX_GetIOSize +// Gets the number of input/output pins for FX if available, returns plug-in type or -1 on error + + int (*TakeFX_GetIOSize)(MediaItem_Take* take, int fx, int* inputPinsOut, int* outputPinsOut); +#endif + +#if defined(REAPERAPI_WANT_TakeFX_GetNamedConfigParm) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// TakeFX_GetNamedConfigParm +// gets plug-in specific named configuration value (returns true on success). see TrackFX_GetNamedConfigParm + + bool (*TakeFX_GetNamedConfigParm)(MediaItem_Take* take, int fx, const char* parmname, char* bufOut, int bufOut_sz); +#endif + +#if defined(REAPERAPI_WANT_TakeFX_GetNumParams) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// TakeFX_GetNumParams + + int (*TakeFX_GetNumParams)(MediaItem_Take* take, int fx); +#endif + +#if defined(REAPERAPI_WANT_TakeFX_GetOffline) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// TakeFX_GetOffline +// See TakeFX_SetOffline + + bool (*TakeFX_GetOffline)(MediaItem_Take* take, int fx); +#endif + +#if defined(REAPERAPI_WANT_TakeFX_GetOpen) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// TakeFX_GetOpen +// Returns true if this FX UI is open in the FX chain window or a floating window. See TakeFX_SetOpen + + bool (*TakeFX_GetOpen)(MediaItem_Take* take, int fx); +#endif + +#if defined(REAPERAPI_WANT_TakeFX_GetParam) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// TakeFX_GetParam + + double (*TakeFX_GetParam)(MediaItem_Take* take, int fx, int param, double* minvalOut, double* maxvalOut); +#endif + +#if defined(REAPERAPI_WANT_TakeFX_GetParameterStepSizes) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// TakeFX_GetParameterStepSizes + + bool (*TakeFX_GetParameterStepSizes)(MediaItem_Take* take, int fx, int param, double* stepOut, double* smallstepOut, double* largestepOut, bool* istoggleOut); +#endif + +#if defined(REAPERAPI_WANT_TakeFX_GetParamEx) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// TakeFX_GetParamEx + + double (*TakeFX_GetParamEx)(MediaItem_Take* take, int fx, int param, double* minvalOut, double* maxvalOut, double* midvalOut); +#endif + +#if defined(REAPERAPI_WANT_TakeFX_GetParamFromIdent) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// TakeFX_GetParamFromIdent +// gets the parameter index from an identifying string (:wet, :bypass, or a string returned from GetParamIdent), or -1 if unknown. + + int (*TakeFX_GetParamFromIdent)(MediaItem_Take* take, int fx, const char* ident_str); +#endif + +#if defined(REAPERAPI_WANT_TakeFX_GetParamIdent) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// TakeFX_GetParamIdent +// gets an identifying string for the parameter + + bool (*TakeFX_GetParamIdent)(MediaItem_Take* take, int fx, int param, char* bufOut, int bufOut_sz); +#endif + +#if defined(REAPERAPI_WANT_TakeFX_GetParamName) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// TakeFX_GetParamName + + bool (*TakeFX_GetParamName)(MediaItem_Take* take, int fx, int param, char* bufOut, int bufOut_sz); +#endif + +#if defined(REAPERAPI_WANT_TakeFX_GetParamNormalized) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// TakeFX_GetParamNormalized + + double (*TakeFX_GetParamNormalized)(MediaItem_Take* take, int fx, int param); +#endif + +#if defined(REAPERAPI_WANT_TakeFX_GetPinMappings) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// TakeFX_GetPinMappings +// gets the effective channel mapping bitmask for a particular pin. high32Out will be set to the high 32 bits + + int (*TakeFX_GetPinMappings)(MediaItem_Take* take, int fx, int isoutput, int pin, int* high32Out); +#endif + +#if defined(REAPERAPI_WANT_TakeFX_GetPreset) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// TakeFX_GetPreset +// Get the name of the preset currently showing in the REAPER dropdown, or the full path to a factory preset file for VST3 plug-ins (.vstpreset). Returns false if the current FX parameters do not exactly match the preset (in other words, if the user loaded the preset but moved the knobs afterward). See TakeFX_SetPreset. + + bool (*TakeFX_GetPreset)(MediaItem_Take* take, int fx, char* presetnameOut, int presetnameOut_sz); +#endif + +#if defined(REAPERAPI_WANT_TakeFX_GetPresetIndex) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// TakeFX_GetPresetIndex +// Returns current preset index, or -1 if error. numberOfPresetsOut will be set to total number of presets available. See TakeFX_SetPresetByIndex + + int (*TakeFX_GetPresetIndex)(MediaItem_Take* take, int fx, int* numberOfPresetsOut); +#endif + +#if defined(REAPERAPI_WANT_TakeFX_GetUserPresetFilename) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// TakeFX_GetUserPresetFilename + + void (*TakeFX_GetUserPresetFilename)(MediaItem_Take* take, int fx, char* fnOut, int fnOut_sz); +#endif + +#if defined(REAPERAPI_WANT_TakeFX_NavigatePresets) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// TakeFX_NavigatePresets +// presetmove==1 activates the next preset, presetmove==-1 activates the previous preset, etc. + + bool (*TakeFX_NavigatePresets)(MediaItem_Take* take, int fx, int presetmove); +#endif + +#if defined(REAPERAPI_WANT_TakeFX_SetEnabled) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// TakeFX_SetEnabled +// See TakeFX_GetEnabled + + void (*TakeFX_SetEnabled)(MediaItem_Take* take, int fx, bool enabled); +#endif + +#if defined(REAPERAPI_WANT_TakeFX_SetNamedConfigParm) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// TakeFX_SetNamedConfigParm +// gets plug-in specific named configuration value (returns true on success) + + bool (*TakeFX_SetNamedConfigParm)(MediaItem_Take* take, int fx, const char* parmname, const char* value); +#endif + +#if defined(REAPERAPI_WANT_TakeFX_SetOffline) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// TakeFX_SetOffline +// See TakeFX_GetOffline + + void (*TakeFX_SetOffline)(MediaItem_Take* take, int fx, bool offline); +#endif + +#if defined(REAPERAPI_WANT_TakeFX_SetOpen) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// TakeFX_SetOpen +// Open this FX UI. See TakeFX_GetOpen + + void (*TakeFX_SetOpen)(MediaItem_Take* take, int fx, bool open); +#endif + +#if defined(REAPERAPI_WANT_TakeFX_SetParam) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// TakeFX_SetParam + + bool (*TakeFX_SetParam)(MediaItem_Take* take, int fx, int param, double val); +#endif + +#if defined(REAPERAPI_WANT_TakeFX_SetParamNormalized) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// TakeFX_SetParamNormalized + + bool (*TakeFX_SetParamNormalized)(MediaItem_Take* take, int fx, int param, double value); +#endif + +#if defined(REAPERAPI_WANT_TakeFX_SetPinMappings) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// TakeFX_SetPinMappings +// sets the channel mapping bitmask for a particular pin. returns false if unsupported (not all types of plug-ins support this capability) + + bool (*TakeFX_SetPinMappings)(MediaItem_Take* take, int fx, int isoutput, int pin, int low32bits, int hi32bits); +#endif + +#if defined(REAPERAPI_WANT_TakeFX_SetPreset) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// TakeFX_SetPreset +// Activate a preset with the name shown in the REAPER dropdown. Full paths to .vstpreset files are also supported for VST3 plug-ins. See TakeFX_GetPreset. + + bool (*TakeFX_SetPreset)(MediaItem_Take* take, int fx, const char* presetname); +#endif + +#if defined(REAPERAPI_WANT_TakeFX_SetPresetByIndex) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// TakeFX_SetPresetByIndex +// Sets the preset idx, or the factory preset (idx==-2), or the default user preset (idx==-1). Returns true on success. See TakeFX_GetPresetIndex. + + bool (*TakeFX_SetPresetByIndex)(MediaItem_Take* take, int fx, int idx); +#endif + +#if defined(REAPERAPI_WANT_TakeFX_Show) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// TakeFX_Show +// showflag=0 for hidechain, =1 for show chain(index valid), =2 for hide floating window(index valid), =3 for show floating window (index valid) + + void (*TakeFX_Show)(MediaItem_Take* take, int index, int showFlag); +#endif + +#if defined(REAPERAPI_WANT_TakeIsMIDI) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// TakeIsMIDI +// Returns true if the active take contains MIDI. + + bool (*TakeIsMIDI)(MediaItem_Take* take); +#endif + +#if defined(REAPERAPI_WANT_ThemeLayout_GetLayout) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// ThemeLayout_GetLayout +// Gets theme layout information. section can be 'global' for global layout override, 'seclist' to enumerate a list of layout sections, otherwise a layout section such as 'mcp', 'tcp', 'trans', etc. idx can be -1 to query the current value, -2 to get the description of the section (if not global), -3 will return the current context DPI-scaling (256=normal, 512=retina, etc), or 0..x. returns false if failed. + + bool (*ThemeLayout_GetLayout)(const char* section, int idx, char* nameOut, int nameOut_sz); +#endif + +#if defined(REAPERAPI_WANT_ThemeLayout_GetParameter) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// ThemeLayout_GetParameter +// returns theme layout parameter. return value is cfg-name, or nil/empty if out of range. + + const char* (*ThemeLayout_GetParameter)(int wp, const char** descOutOptional, int* valueOutOptional, int* defValueOutOptional, int* minValueOutOptional, int* maxValueOutOptional); +#endif + +#if defined(REAPERAPI_WANT_ThemeLayout_RefreshAll) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// ThemeLayout_RefreshAll +// Refreshes all layouts + + void (*ThemeLayout_RefreshAll)(); +#endif + +#if defined(REAPERAPI_WANT_ThemeLayout_SetLayout) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// ThemeLayout_SetLayout +// Sets theme layout override for a particular section -- section can be 'global' or 'mcp' etc. If setting global layout, prefix a ! to the layout string to clear any per-layout overrides. Returns false if failed. + + bool (*ThemeLayout_SetLayout)(const char* section, const char* layout); +#endif + +#if defined(REAPERAPI_WANT_ThemeLayout_SetParameter) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// ThemeLayout_SetParameter +// sets theme layout parameter to value. persist=true in order to have change loaded on next theme load. note that the caller should update layouts via ??? to make changes visible. + + bool (*ThemeLayout_SetParameter)(int wp, int value, bool persist); +#endif + +#if defined(REAPERAPI_WANT_time_precise) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// time_precise +// Gets a precise system timestamp in seconds + + double (*time_precise)(); +#endif + +#if defined(REAPERAPI_WANT_TimeMap2_beatsToTime) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// TimeMap2_beatsToTime +// convert a beat position (or optionally a beats+measures if measures is non-NULL) to time. + + double (*TimeMap2_beatsToTime)(ReaProject* proj, double tpos, const int* measuresInOptional); +#endif + +#if defined(REAPERAPI_WANT_TimeMap2_GetDividedBpmAtTime) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// TimeMap2_GetDividedBpmAtTime +// get the effective BPM at the time (seconds) position (i.e. 2x in /8 signatures) + + double (*TimeMap2_GetDividedBpmAtTime)(ReaProject* proj, double time); +#endif + +#if defined(REAPERAPI_WANT_TimeMap2_GetNextChangeTime) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// TimeMap2_GetNextChangeTime +// when does the next time map (tempo or time sig) change occur + + double (*TimeMap2_GetNextChangeTime)(ReaProject* proj, double time); +#endif + +#if defined(REAPERAPI_WANT_TimeMap2_QNToTime) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// TimeMap2_QNToTime +// converts project QN position to time. + + double (*TimeMap2_QNToTime)(ReaProject* proj, double qn); +#endif + +#if defined(REAPERAPI_WANT_TimeMap2_timeToBeats) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// TimeMap2_timeToBeats +// convert a time into beats. +// if measures is non-NULL, measures will be set to the measure count, return value will be beats since measure. +// if cml is non-NULL, will be set to current measure length in beats (i.e. time signature numerator) +// if fullbeats is non-NULL, and measures is non-NULL, fullbeats will get the full beat count (same value returned if measures is NULL). +// if cdenom is non-NULL, will be set to the current time signature denominator. + + double (*TimeMap2_timeToBeats)(ReaProject* proj, double tpos, int* measuresOutOptional, int* cmlOutOptional, double* fullbeatsOutOptional, int* cdenomOutOptional); +#endif + +#if defined(REAPERAPI_WANT_TimeMap2_timeToQN) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// TimeMap2_timeToQN +// converts project time position to QN position. + + double (*TimeMap2_timeToQN)(ReaProject* proj, double tpos); +#endif + +#if defined(REAPERAPI_WANT_TimeMap_curFrameRate) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// TimeMap_curFrameRate +// Gets project framerate, and optionally whether it is drop-frame timecode + + double (*TimeMap_curFrameRate)(ReaProject* proj, bool* dropFrameOut); +#endif + +#if defined(REAPERAPI_WANT_TimeMap_GetDividedBpmAtTime) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// TimeMap_GetDividedBpmAtTime +// get the effective BPM at the time (seconds) position (i.e. 2x in /8 signatures) + + double (*TimeMap_GetDividedBpmAtTime)(double time); +#endif + +#if defined(REAPERAPI_WANT_TimeMap_GetMeasureInfo) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// TimeMap_GetMeasureInfo +// Get the QN position and time signature information for the start of a measure. Return the time in seconds of the measure start. + + double (*TimeMap_GetMeasureInfo)(ReaProject* proj, int measure, double* qn_startOut, double* qn_endOut, int* timesig_numOut, int* timesig_denomOut, double* tempoOut); +#endif + +#if defined(REAPERAPI_WANT_TimeMap_GetMetronomePattern) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// TimeMap_GetMetronomePattern +// Fills in a string representing the active metronome pattern. For example, in a 7/8 measure divided 3+4, the pattern might be "1221222". The length of the string is the time signature numerator, and the function returns the time signature denominator. + + int (*TimeMap_GetMetronomePattern)(ReaProject* proj, double time, char* pattern, int pattern_sz); +#endif + +#if defined(REAPERAPI_WANT_TimeMap_GetTimeSigAtTime) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// TimeMap_GetTimeSigAtTime +// get the effective time signature and tempo + + void (*TimeMap_GetTimeSigAtTime)(ReaProject* proj, double time, int* timesig_numOut, int* timesig_denomOut, double* tempoOut); +#endif + +#if defined(REAPERAPI_WANT_TimeMap_QNToMeasures) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// TimeMap_QNToMeasures +// Find which measure the given QN position falls in. + + int (*TimeMap_QNToMeasures)(ReaProject* proj, double qn, double* qnMeasureStartOutOptional, double* qnMeasureEndOutOptional); +#endif + +#if defined(REAPERAPI_WANT_TimeMap_QNToTime) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// TimeMap_QNToTime +// converts project QN position to time. + + double (*TimeMap_QNToTime)(double qn); +#endif + +#if defined(REAPERAPI_WANT_TimeMap_QNToTime_abs) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// TimeMap_QNToTime_abs +// Converts project quarter note count (QN) to time. QN is counted from the start of the project, regardless of any partial measures. See TimeMap2_QNToTime + + double (*TimeMap_QNToTime_abs)(ReaProject* proj, double qn); +#endif + +#if defined(REAPERAPI_WANT_TimeMap_timeToQN) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// TimeMap_timeToQN +// converts project QN position to time. + + double (*TimeMap_timeToQN)(double tpos); +#endif + +#if defined(REAPERAPI_WANT_TimeMap_timeToQN_abs) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// TimeMap_timeToQN_abs +// Converts project time position to quarter note count (QN). QN is counted from the start of the project, regardless of any partial measures. See TimeMap2_timeToQN + + double (*TimeMap_timeToQN_abs)(ReaProject* proj, double tpos); +#endif + +#if defined(REAPERAPI_WANT_ToggleTrackSendUIMute) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// ToggleTrackSendUIMute +// send_idx<0 for receives, >=0 for hw ouputs, >=nb_of_hw_ouputs for sends. + + bool (*ToggleTrackSendUIMute)(MediaTrack* track, int send_idx); +#endif + +#if defined(REAPERAPI_WANT_Track_GetPeakHoldDB) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// Track_GetPeakHoldDB +// Returns meter hold state, in dB*0.01 (0 = +0dB, -0.01 = -1dB, 0.02 = +2dB, etc). If clear is set, clears the meter hold. If channel==1024 or channel==1025, returns loudness values if this is the master track or this track's VU meters are set to display loudness. + + double (*Track_GetPeakHoldDB)(MediaTrack* track, int channel, bool clear); +#endif + +#if defined(REAPERAPI_WANT_Track_GetPeakInfo) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// Track_GetPeakInfo +// Returns peak meter value (1.0=+0dB, 0.0=-inf) for channel. If channel==1024 or channel==1025, returns loudness values if this is the master track or this track's VU meters are set to display loudness. + + double (*Track_GetPeakInfo)(MediaTrack* track, int channel); +#endif + +#if defined(REAPERAPI_WANT_TrackCtl_SetToolTip) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// TrackCtl_SetToolTip +// displays tooltip at location, or removes if empty string + + void (*TrackCtl_SetToolTip)(const char* fmt, int xpos, int ypos, bool topmost); +#endif + +#if defined(REAPERAPI_WANT_TrackFX_AddByName) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// TrackFX_AddByName +// Adds or queries the position of a named FX from the track FX chain (recFX=false) or record input FX/monitoring FX (recFX=true, monitoring FX are on master track). Specify a negative value for instantiate to always create a new effect, 0 to only query the first instance of an effect, or a positive value to add an instance if one is not found. If instantiate is <= -1000, it is used for the insertion position (-1000 is first item in chain, -1001 is second, etc). fxname can have prefix to specify type: VST3:,VST2:,VST:,AU:,JS:, or DX:, or FXADD: which adds selected items from the currently-open FX browser, FXADD:2 to limit to 2 FX added, or FXADD:2e to only succeed if exactly 2 FX are selected. Returns -1 on failure or the new position in chain on success. + + int (*TrackFX_AddByName)(MediaTrack* track, const char* fxname, bool recFX, int instantiate); +#endif + +#if defined(REAPERAPI_WANT_TrackFX_CopyToTake) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// TrackFX_CopyToTake +// Copies (or moves) FX from src_track to dest_take. src_fx can have 0x1000000 set to reference input FX. + + void (*TrackFX_CopyToTake)(MediaTrack* src_track, int src_fx, MediaItem_Take* dest_take, int dest_fx, bool is_move); +#endif + +#if defined(REAPERAPI_WANT_TrackFX_CopyToTrack) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// TrackFX_CopyToTrack +// Copies (or moves) FX from src_track to dest_track. Can be used with src_track=dest_track to reorder, FX indices have 0x1000000 set to reference input FX. + + void (*TrackFX_CopyToTrack)(MediaTrack* src_track, int src_fx, MediaTrack* dest_track, int dest_fx, bool is_move); +#endif + +#if defined(REAPERAPI_WANT_TrackFX_Delete) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// TrackFX_Delete +// Remove a FX from track chain (returns true on success) + + bool (*TrackFX_Delete)(MediaTrack* track, int fx); +#endif + +#if defined(REAPERAPI_WANT_TrackFX_EndParamEdit) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// TrackFX_EndParamEdit + + bool (*TrackFX_EndParamEdit)(MediaTrack* track, int fx, int param); +#endif + +#if defined(REAPERAPI_WANT_TrackFX_FormatParamValue) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// TrackFX_FormatParamValue +// Note: only works with FX that support Cockos VST extensions. + + bool (*TrackFX_FormatParamValue)(MediaTrack* track, int fx, int param, double val, char* bufOut, int bufOut_sz); +#endif + +#if defined(REAPERAPI_WANT_TrackFX_FormatParamValueNormalized) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// TrackFX_FormatParamValueNormalized +// Note: only works with FX that support Cockos VST extensions. + + bool (*TrackFX_FormatParamValueNormalized)(MediaTrack* track, int fx, int param, double value, char* buf, int buf_sz); +#endif + +#if defined(REAPERAPI_WANT_TrackFX_GetByName) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// TrackFX_GetByName +// Get the index of the first track FX insert that matches fxname. If the FX is not in the chain and instantiate is true, it will be inserted. See TrackFX_GetInstrument, TrackFX_GetEQ. Deprecated in favor of TrackFX_AddByName. + + int (*TrackFX_GetByName)(MediaTrack* track, const char* fxname, bool instantiate); +#endif + +#if defined(REAPERAPI_WANT_TrackFX_GetChainVisible) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// TrackFX_GetChainVisible +// returns index of effect visible in chain, or -1 for chain hidden, or -2 for chain visible but no effect selected + + int (*TrackFX_GetChainVisible)(MediaTrack* track); +#endif + +#if defined(REAPERAPI_WANT_TrackFX_GetCount) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// TrackFX_GetCount + + int (*TrackFX_GetCount)(MediaTrack* track); +#endif + +#if defined(REAPERAPI_WANT_TrackFX_GetEnabled) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// TrackFX_GetEnabled +// See TrackFX_SetEnabled + + bool (*TrackFX_GetEnabled)(MediaTrack* track, int fx); +#endif + +#if defined(REAPERAPI_WANT_TrackFX_GetEQ) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// TrackFX_GetEQ +// Get the index of ReaEQ in the track FX chain. If ReaEQ is not in the chain and instantiate is true, it will be inserted. See TrackFX_GetInstrument, TrackFX_GetByName. + + int (*TrackFX_GetEQ)(MediaTrack* track, bool instantiate); +#endif + +#if defined(REAPERAPI_WANT_TrackFX_GetEQBandEnabled) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// TrackFX_GetEQBandEnabled +// Returns true if the EQ band is enabled. +// Returns false if the band is disabled, or if track/fxidx is not ReaEQ. +// Bandtype: -1=master gain, 0=hipass, 1=loshelf, 2=band, 3=notch, 4=hishelf, 5=lopass, 6=bandpass, 7=parallel bandpass. +// Bandidx (ignored for master gain): 0=target first band matching bandtype, 1=target 2nd band matching bandtype, etc. +// +// See TrackFX_GetEQ, TrackFX_GetEQParam, TrackFX_SetEQParam, TrackFX_SetEQBandEnabled. + + bool (*TrackFX_GetEQBandEnabled)(MediaTrack* track, int fxidx, int bandtype, int bandidx); +#endif + +#if defined(REAPERAPI_WANT_TrackFX_GetEQParam) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// TrackFX_GetEQParam +// Returns false if track/fxidx is not ReaEQ. +// Bandtype: -1=master gain, 0=hipass, 1=loshelf, 2=band, 3=notch, 4=hishelf, 5=lopass, 6=bandpass, 7=parallel bandpass. +// Bandidx (ignored for master gain): 0=target first band matching bandtype, 1=target 2nd band matching bandtype, etc. +// Paramtype (ignored for master gain): 0=freq, 1=gain, 2=Q. +// See TrackFX_GetEQ, TrackFX_SetEQParam, TrackFX_GetEQBandEnabled, TrackFX_SetEQBandEnabled. + + bool (*TrackFX_GetEQParam)(MediaTrack* track, int fxidx, int paramidx, int* bandtypeOut, int* bandidxOut, int* paramtypeOut, double* normvalOut); +#endif + +#if defined(REAPERAPI_WANT_TrackFX_GetFloatingWindow) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// TrackFX_GetFloatingWindow +// returns HWND of floating window for effect index, if any + + HWND (*TrackFX_GetFloatingWindow)(MediaTrack* track, int index); +#endif + +#if defined(REAPERAPI_WANT_TrackFX_GetFormattedParamValue) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// TrackFX_GetFormattedParamValue + + bool (*TrackFX_GetFormattedParamValue)(MediaTrack* track, int fx, int param, char* bufOut, int bufOut_sz); +#endif + +#if defined(REAPERAPI_WANT_TrackFX_GetFXGUID) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// TrackFX_GetFXGUID + + GUID* (*TrackFX_GetFXGUID)(MediaTrack* track, int fx); +#endif + +#if defined(REAPERAPI_WANT_TrackFX_GetFXName) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// TrackFX_GetFXName + + bool (*TrackFX_GetFXName)(MediaTrack* track, int fx, char* bufOut, int bufOut_sz); +#endif + +#if defined(REAPERAPI_WANT_TrackFX_GetInstrument) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// TrackFX_GetInstrument +// Get the index of the first track FX insert that is a virtual instrument, or -1 if none. See TrackFX_GetEQ, TrackFX_GetByName. + + int (*TrackFX_GetInstrument)(MediaTrack* track); +#endif + +#if defined(REAPERAPI_WANT_TrackFX_GetIOSize) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// TrackFX_GetIOSize +// Gets the number of input/output pins for FX if available, returns plug-in type or -1 on error + + int (*TrackFX_GetIOSize)(MediaTrack* track, int fx, int* inputPinsOut, int* outputPinsOut); +#endif + +#if defined(REAPERAPI_WANT_TrackFX_GetNamedConfigParm) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// TrackFX_GetNamedConfigParm +// gets plug-in specific named configuration value (returns true on success). Special values: 'pdc' returns PDC latency. 'in_pin_0' returns name of first input pin (if available), 'out_pin_0' returns name of first output pin (if available), etc. 'fx_type' returns type string, 'fx_ident' returns type-specific identifier, 'fx_name' returns pre-aliased name. + + bool (*TrackFX_GetNamedConfigParm)(MediaTrack* track, int fx, const char* parmname, char* bufOut, int bufOut_sz); +#endif + +#if defined(REAPERAPI_WANT_TrackFX_GetNumParams) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// TrackFX_GetNumParams + + int (*TrackFX_GetNumParams)(MediaTrack* track, int fx); +#endif + +#if defined(REAPERAPI_WANT_TrackFX_GetOffline) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// TrackFX_GetOffline +// See TrackFX_SetOffline + + bool (*TrackFX_GetOffline)(MediaTrack* track, int fx); +#endif + +#if defined(REAPERAPI_WANT_TrackFX_GetOpen) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// TrackFX_GetOpen +// Returns true if this FX UI is open in the FX chain window or a floating window. See TrackFX_SetOpen + + bool (*TrackFX_GetOpen)(MediaTrack* track, int fx); +#endif + +#if defined(REAPERAPI_WANT_TrackFX_GetParam) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// TrackFX_GetParam + + double (*TrackFX_GetParam)(MediaTrack* track, int fx, int param, double* minvalOut, double* maxvalOut); +#endif + +#if defined(REAPERAPI_WANT_TrackFX_GetParameterStepSizes) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// TrackFX_GetParameterStepSizes + + bool (*TrackFX_GetParameterStepSizes)(MediaTrack* track, int fx, int param, double* stepOut, double* smallstepOut, double* largestepOut, bool* istoggleOut); +#endif + +#if defined(REAPERAPI_WANT_TrackFX_GetParamEx) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// TrackFX_GetParamEx + + double (*TrackFX_GetParamEx)(MediaTrack* track, int fx, int param, double* minvalOut, double* maxvalOut, double* midvalOut); +#endif + +#if defined(REAPERAPI_WANT_TrackFX_GetParamFromIdent) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// TrackFX_GetParamFromIdent +// gets the parameter index from an identifying string (:wet, :bypass, :delta, or a string returned from GetParamIdent), or -1 if unknown. + + int (*TrackFX_GetParamFromIdent)(MediaTrack* track, int fx, const char* ident_str); +#endif + +#if defined(REAPERAPI_WANT_TrackFX_GetParamIdent) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// TrackFX_GetParamIdent +// gets an identifying string for the parameter + + bool (*TrackFX_GetParamIdent)(MediaTrack* track, int fx, int param, char* bufOut, int bufOut_sz); +#endif + +#if defined(REAPERAPI_WANT_TrackFX_GetParamName) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// TrackFX_GetParamName + + bool (*TrackFX_GetParamName)(MediaTrack* track, int fx, int param, char* bufOut, int bufOut_sz); +#endif + +#if defined(REAPERAPI_WANT_TrackFX_GetParamNormalized) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// TrackFX_GetParamNormalized + + double (*TrackFX_GetParamNormalized)(MediaTrack* track, int fx, int param); +#endif + +#if defined(REAPERAPI_WANT_TrackFX_GetPinMappings) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// TrackFX_GetPinMappings +// gets the effective channel mapping bitmask for a particular pin. high32Out will be set to the high 32 bits + + int (*TrackFX_GetPinMappings)(MediaTrack* tr, int fx, int isoutput, int pin, int* high32Out); +#endif + +#if defined(REAPERAPI_WANT_TrackFX_GetPreset) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// TrackFX_GetPreset +// Get the name of the preset currently showing in the REAPER dropdown, or the full path to a factory preset file for VST3 plug-ins (.vstpreset). Returns false if the current FX parameters do not exactly match the preset (in other words, if the user loaded the preset but moved the knobs afterward). See TrackFX_SetPreset. + + bool (*TrackFX_GetPreset)(MediaTrack* track, int fx, char* presetnameOut, int presetnameOut_sz); +#endif + +#if defined(REAPERAPI_WANT_TrackFX_GetPresetIndex) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// TrackFX_GetPresetIndex +// Returns current preset index, or -1 if error. numberOfPresetsOut will be set to total number of presets available. See TrackFX_SetPresetByIndex + + int (*TrackFX_GetPresetIndex)(MediaTrack* track, int fx, int* numberOfPresetsOut); +#endif + +#if defined(REAPERAPI_WANT_TrackFX_GetRecChainVisible) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// TrackFX_GetRecChainVisible +// returns index of effect visible in record input chain, or -1 for chain hidden, or -2 for chain visible but no effect selected + + int (*TrackFX_GetRecChainVisible)(MediaTrack* track); +#endif + +#if defined(REAPERAPI_WANT_TrackFX_GetRecCount) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// TrackFX_GetRecCount +// returns count of record input FX. To access record input FX, use a FX indices [0x1000000..0x1000000+n). On the master track, this accesses monitoring FX rather than record input FX. + + int (*TrackFX_GetRecCount)(MediaTrack* track); +#endif + +#if defined(REAPERAPI_WANT_TrackFX_GetUserPresetFilename) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// TrackFX_GetUserPresetFilename + + void (*TrackFX_GetUserPresetFilename)(MediaTrack* track, int fx, char* fnOut, int fnOut_sz); +#endif + +#if defined(REAPERAPI_WANT_TrackFX_NavigatePresets) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// TrackFX_NavigatePresets +// presetmove==1 activates the next preset, presetmove==-1 activates the previous preset, etc. + + bool (*TrackFX_NavigatePresets)(MediaTrack* track, int fx, int presetmove); +#endif + +#if defined(REAPERAPI_WANT_TrackFX_SetEnabled) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// TrackFX_SetEnabled +// See TrackFX_GetEnabled + + void (*TrackFX_SetEnabled)(MediaTrack* track, int fx, bool enabled); +#endif + +#if defined(REAPERAPI_WANT_TrackFX_SetEQBandEnabled) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// TrackFX_SetEQBandEnabled +// Enable or disable a ReaEQ band. +// Returns false if track/fxidx is not ReaEQ. +// Bandtype: -1=master gain, 0=hipass, 1=loshelf, 2=band, 3=notch, 4=hishelf, 5=lopass, 6=bandpass, 7=parallel bandpass. +// Bandidx (ignored for master gain): 0=target first band matching bandtype, 1=target 2nd band matching bandtype, etc. +// +// See TrackFX_GetEQ, TrackFX_GetEQParam, TrackFX_SetEQParam, TrackFX_GetEQBandEnabled. + + bool (*TrackFX_SetEQBandEnabled)(MediaTrack* track, int fxidx, int bandtype, int bandidx, bool enable); +#endif + +#if defined(REAPERAPI_WANT_TrackFX_SetEQParam) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// TrackFX_SetEQParam +// Returns false if track/fxidx is not ReaEQ. Targets a band matching bandtype. +// Bandtype: -1=master gain, 0=hipass, 1=loshelf, 2=band, 3=notch, 4=hishelf, 5=lopass, 6=bandpass, 7=parallel bandpass. +// Bandidx (ignored for master gain): 0=target first band matching bandtype, 1=target 2nd band matching bandtype, etc. +// Paramtype (ignored for master gain): 0=freq, 1=gain, 2=Q. +// See TrackFX_GetEQ, TrackFX_GetEQParam, TrackFX_GetEQBandEnabled, TrackFX_SetEQBandEnabled. + + bool (*TrackFX_SetEQParam)(MediaTrack* track, int fxidx, int bandtype, int bandidx, int paramtype, double val, bool isnorm); +#endif + +#if defined(REAPERAPI_WANT_TrackFX_SetNamedConfigParm) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// TrackFX_SetNamedConfigParm +// sets plug-in specific named configuration value (returns true on success) + + bool (*TrackFX_SetNamedConfigParm)(MediaTrack* track, int fx, const char* parmname, const char* value); +#endif + +#if defined(REAPERAPI_WANT_TrackFX_SetOffline) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// TrackFX_SetOffline +// See TrackFX_GetOffline + + void (*TrackFX_SetOffline)(MediaTrack* track, int fx, bool offline); +#endif + +#if defined(REAPERAPI_WANT_TrackFX_SetOpen) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// TrackFX_SetOpen +// Open this FX UI. See TrackFX_GetOpen + + void (*TrackFX_SetOpen)(MediaTrack* track, int fx, bool open); +#endif + +#if defined(REAPERAPI_WANT_TrackFX_SetParam) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// TrackFX_SetParam + + bool (*TrackFX_SetParam)(MediaTrack* track, int fx, int param, double val); +#endif + +#if defined(REAPERAPI_WANT_TrackFX_SetParamNormalized) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// TrackFX_SetParamNormalized + + bool (*TrackFX_SetParamNormalized)(MediaTrack* track, int fx, int param, double value); +#endif + +#if defined(REAPERAPI_WANT_TrackFX_SetPinMappings) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// TrackFX_SetPinMappings +// sets the channel mapping bitmask for a particular pin. returns false if unsupported (not all types of plug-ins support this capability) + + bool (*TrackFX_SetPinMappings)(MediaTrack* tr, int fx, int isoutput, int pin, int low32bits, int hi32bits); +#endif + +#if defined(REAPERAPI_WANT_TrackFX_SetPreset) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// TrackFX_SetPreset +// Activate a preset with the name shown in the REAPER dropdown. Full paths to .vstpreset files are also supported for VST3 plug-ins. See TrackFX_GetPreset. + + bool (*TrackFX_SetPreset)(MediaTrack* track, int fx, const char* presetname); +#endif + +#if defined(REAPERAPI_WANT_TrackFX_SetPresetByIndex) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// TrackFX_SetPresetByIndex +// Sets the preset idx, or the factory preset (idx==-2), or the default user preset (idx==-1). Returns true on success. See TrackFX_GetPresetIndex. + + bool (*TrackFX_SetPresetByIndex)(MediaTrack* track, int fx, int idx); +#endif + +#if defined(REAPERAPI_WANT_TrackFX_Show) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// TrackFX_Show +// showflag=0 for hidechain, =1 for show chain(index valid), =2 for hide floating window(index valid), =3 for show floating window (index valid) + + void (*TrackFX_Show)(MediaTrack* track, int index, int showFlag); +#endif + +#if defined(REAPERAPI_WANT_TrackList_AdjustWindows) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// TrackList_AdjustWindows + + void (*TrackList_AdjustWindows)(bool isMinor); +#endif + +#if defined(REAPERAPI_WANT_TrackList_UpdateAllExternalSurfaces) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// TrackList_UpdateAllExternalSurfaces + + void (*TrackList_UpdateAllExternalSurfaces)(); +#endif + +#if defined(REAPERAPI_WANT_Undo_BeginBlock) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// Undo_BeginBlock +// call to start a new block + + void (*Undo_BeginBlock)(); +#endif + +#if defined(REAPERAPI_WANT_Undo_BeginBlock2) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// Undo_BeginBlock2 +// call to start a new block + + void (*Undo_BeginBlock2)(ReaProject* proj); +#endif + +#if defined(REAPERAPI_WANT_Undo_CanRedo2) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// Undo_CanRedo2 +// returns string of next action,if able,NULL if not + + const char* (*Undo_CanRedo2)(ReaProject* proj); +#endif + +#if defined(REAPERAPI_WANT_Undo_CanUndo2) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// Undo_CanUndo2 +// returns string of last action,if able,NULL if not + + const char* (*Undo_CanUndo2)(ReaProject* proj); +#endif + +#if defined(REAPERAPI_WANT_Undo_DoRedo2) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// Undo_DoRedo2 +// nonzero if success + + int (*Undo_DoRedo2)(ReaProject* proj); +#endif + +#if defined(REAPERAPI_WANT_Undo_DoUndo2) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// Undo_DoUndo2 +// nonzero if success + + int (*Undo_DoUndo2)(ReaProject* proj); +#endif + +#if defined(REAPERAPI_WANT_Undo_EndBlock) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// Undo_EndBlock +// call to end the block,with extra flags if any,and a description + + void (*Undo_EndBlock)(const char* descchange, int extraflags); +#endif + +#if defined(REAPERAPI_WANT_Undo_EndBlock2) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// Undo_EndBlock2 +// call to end the block,with extra flags if any,and a description + + void (*Undo_EndBlock2)(ReaProject* proj, const char* descchange, int extraflags); +#endif + +#if defined(REAPERAPI_WANT_Undo_OnStateChange) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// Undo_OnStateChange +// limited state change to items + + void (*Undo_OnStateChange)(const char* descchange); +#endif + +#if defined(REAPERAPI_WANT_Undo_OnStateChange2) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// Undo_OnStateChange2 +// limited state change to items + + void (*Undo_OnStateChange2)(ReaProject* proj, const char* descchange); +#endif + +#if defined(REAPERAPI_WANT_Undo_OnStateChange_Item) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// Undo_OnStateChange_Item + + void (*Undo_OnStateChange_Item)(ReaProject* proj, const char* name, MediaItem* item); +#endif + +#if defined(REAPERAPI_WANT_Undo_OnStateChangeEx) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// Undo_OnStateChangeEx +// trackparm=-1 by default,or if updating one fx chain,you can specify track index + + void (*Undo_OnStateChangeEx)(const char* descchange, int whichStates, int trackparm); +#endif + +#if defined(REAPERAPI_WANT_Undo_OnStateChangeEx2) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// Undo_OnStateChangeEx2 +// trackparm=-1 by default,or if updating one fx chain,you can specify track index + + void (*Undo_OnStateChangeEx2)(ReaProject* proj, const char* descchange, int whichStates, int trackparm); +#endif + +#if defined(REAPERAPI_WANT_update_disk_counters) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// update_disk_counters +// Updates disk I/O statistics with bytes transferred since last call. notify REAPER of a write error by calling with readamt=0, writeamt=-101010110 for unknown or -101010111 for disk full + + void (*update_disk_counters)(int readamt, int writeamt); +#endif + +#if defined(REAPERAPI_WANT_UpdateArrange) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// UpdateArrange +// Redraw the arrange view + + void (*UpdateArrange)(); +#endif + +#if defined(REAPERAPI_WANT_UpdateItemInProject) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// UpdateItemInProject + + void (*UpdateItemInProject)(MediaItem* item); +#endif + +#if defined(REAPERAPI_WANT_UpdateTimeline) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// UpdateTimeline +// Redraw the arrange view and ruler + + void (*UpdateTimeline)(); +#endif + +#if defined(REAPERAPI_WANT_ValidatePtr) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// ValidatePtr +// see ValidatePtr2 + + bool (*ValidatePtr)(void* pointer, const char* ctypename); +#endif + +#if defined(REAPERAPI_WANT_ValidatePtr2) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// ValidatePtr2 +// Return true if the pointer is a valid object of the right type in proj (proj is ignored if pointer is itself a project). Supported types are: ReaProject*, MediaTrack*, MediaItem*, MediaItem_Take*, TrackEnvelope* and PCM_source*. + + bool (*ValidatePtr2)(ReaProject* proj, void* pointer, const char* ctypename); +#endif + +#if defined(REAPERAPI_WANT_ViewPrefs) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// ViewPrefs +// Opens the prefs to a page, use pageByName if page is 0. + + void (*ViewPrefs)(int page, const char* pageByName); +#endif + +#if defined(REAPERAPI_WANT_WDL_VirtualWnd_ScaledBlitBG) || !defined(REAPERAPI_MINIMAL) +REAPERAPI_DEF //============================================== +// WDL_VirtualWnd_ScaledBlitBG + + bool (*WDL_VirtualWnd_ScaledBlitBG)(LICE_IBitmap* dest, WDL_VirtualWnd_BGCfg* src, int destx, int desty, int destw, int desth, int clipx, int clipy, int clipw, int cliph, float alpha, int mode); +#endif + +#ifdef REAPERAPI_IMPLEMENT + int REAPERAPI_LoadAPI(void *(*getAPI)(const char *)) + { + static const struct { void **dest; const char *name; } table[]={ + #if defined(REAPERAPI_WANT___mergesort) || !defined(REAPERAPI_MINIMAL) + {(void**)&__mergesort,"__mergesort"}, + #endif + #if defined(REAPERAPI_WANT_AddCustomizableMenu) || !defined(REAPERAPI_MINIMAL) + {(void**)&AddCustomizableMenu,"AddCustomizableMenu"}, + #endif + #if defined(REAPERAPI_WANT_AddExtensionsMainMenu) || !defined(REAPERAPI_MINIMAL) + {(void**)&AddExtensionsMainMenu,"AddExtensionsMainMenu"}, + #endif + #if defined(REAPERAPI_WANT_AddMediaItemToTrack) || !defined(REAPERAPI_MINIMAL) + {(void**)&AddMediaItemToTrack,"AddMediaItemToTrack"}, + #endif + #if defined(REAPERAPI_WANT_AddProjectMarker) || !defined(REAPERAPI_MINIMAL) + {(void**)&AddProjectMarker,"AddProjectMarker"}, + #endif + #if defined(REAPERAPI_WANT_AddProjectMarker2) || !defined(REAPERAPI_MINIMAL) + {(void**)&AddProjectMarker2,"AddProjectMarker2"}, + #endif + #if defined(REAPERAPI_WANT_AddRemoveReaScript) || !defined(REAPERAPI_MINIMAL) + {(void**)&AddRemoveReaScript,"AddRemoveReaScript"}, + #endif + #if defined(REAPERAPI_WANT_AddTakeToMediaItem) || !defined(REAPERAPI_MINIMAL) + {(void**)&AddTakeToMediaItem,"AddTakeToMediaItem"}, + #endif + #if defined(REAPERAPI_WANT_AddTempoTimeSigMarker) || !defined(REAPERAPI_MINIMAL) + {(void**)&AddTempoTimeSigMarker,"AddTempoTimeSigMarker"}, + #endif + #if defined(REAPERAPI_WANT_adjustZoom) || !defined(REAPERAPI_MINIMAL) + {(void**)&adjustZoom,"adjustZoom"}, + #endif + #if defined(REAPERAPI_WANT_AnyTrackSolo) || !defined(REAPERAPI_MINIMAL) + {(void**)&AnyTrackSolo,"AnyTrackSolo"}, + #endif + #if defined(REAPERAPI_WANT_APIExists) || !defined(REAPERAPI_MINIMAL) + {(void**)&APIExists,"APIExists"}, + #endif + #if defined(REAPERAPI_WANT_APITest) || !defined(REAPERAPI_MINIMAL) + {(void**)&APITest,"APITest"}, + #endif + #if defined(REAPERAPI_WANT_ApplyNudge) || !defined(REAPERAPI_MINIMAL) + {(void**)&ApplyNudge,"ApplyNudge"}, + #endif + #if defined(REAPERAPI_WANT_ArmCommand) || !defined(REAPERAPI_MINIMAL) + {(void**)&ArmCommand,"ArmCommand"}, + #endif + #if defined(REAPERAPI_WANT_Audio_Init) || !defined(REAPERAPI_MINIMAL) + {(void**)&Audio_Init,"Audio_Init"}, + #endif + #if defined(REAPERAPI_WANT_Audio_IsPreBuffer) || !defined(REAPERAPI_MINIMAL) + {(void**)&Audio_IsPreBuffer,"Audio_IsPreBuffer"}, + #endif + #if defined(REAPERAPI_WANT_Audio_IsRunning) || !defined(REAPERAPI_MINIMAL) + {(void**)&Audio_IsRunning,"Audio_IsRunning"}, + #endif + #if defined(REAPERAPI_WANT_Audio_Quit) || !defined(REAPERAPI_MINIMAL) + {(void**)&Audio_Quit,"Audio_Quit"}, + #endif + #if defined(REAPERAPI_WANT_Audio_RegHardwareHook) || !defined(REAPERAPI_MINIMAL) + {(void**)&Audio_RegHardwareHook,"Audio_RegHardwareHook"}, + #endif + #if defined(REAPERAPI_WANT_AudioAccessorStateChanged) || !defined(REAPERAPI_MINIMAL) + {(void**)&AudioAccessorStateChanged,"AudioAccessorStateChanged"}, + #endif + #if defined(REAPERAPI_WANT_AudioAccessorUpdate) || !defined(REAPERAPI_MINIMAL) + {(void**)&AudioAccessorUpdate,"AudioAccessorUpdate"}, + #endif + #if defined(REAPERAPI_WANT_AudioAccessorValidateState) || !defined(REAPERAPI_MINIMAL) + {(void**)&AudioAccessorValidateState,"AudioAccessorValidateState"}, + #endif + #if defined(REAPERAPI_WANT_BypassFxAllTracks) || !defined(REAPERAPI_MINIMAL) + {(void**)&BypassFxAllTracks,"BypassFxAllTracks"}, + #endif + #if defined(REAPERAPI_WANT_CalculateNormalization) || !defined(REAPERAPI_MINIMAL) + {(void**)&CalculateNormalization,"CalculateNormalization"}, + #endif + #if defined(REAPERAPI_WANT_CalculatePeaks) || !defined(REAPERAPI_MINIMAL) + {(void**)&CalculatePeaks,"CalculatePeaks"}, + #endif + #if defined(REAPERAPI_WANT_CalculatePeaksFloatSrcPtr) || !defined(REAPERAPI_MINIMAL) + {(void**)&CalculatePeaksFloatSrcPtr,"CalculatePeaksFloatSrcPtr"}, + #endif + #if defined(REAPERAPI_WANT_ClearAllRecArmed) || !defined(REAPERAPI_MINIMAL) + {(void**)&ClearAllRecArmed,"ClearAllRecArmed"}, + #endif + #if defined(REAPERAPI_WANT_ClearConsole) || !defined(REAPERAPI_MINIMAL) + {(void**)&ClearConsole,"ClearConsole"}, + #endif + #if defined(REAPERAPI_WANT_ClearPeakCache) || !defined(REAPERAPI_MINIMAL) + {(void**)&ClearPeakCache,"ClearPeakCache"}, + #endif + #if defined(REAPERAPI_WANT_ColorFromNative) || !defined(REAPERAPI_MINIMAL) + {(void**)&ColorFromNative,"ColorFromNative"}, + #endif + #if defined(REAPERAPI_WANT_ColorToNative) || !defined(REAPERAPI_MINIMAL) + {(void**)&ColorToNative,"ColorToNative"}, + #endif + #if defined(REAPERAPI_WANT_CountActionShortcuts) || !defined(REAPERAPI_MINIMAL) + {(void**)&CountActionShortcuts,"CountActionShortcuts"}, + #endif + #if defined(REAPERAPI_WANT_CountAutomationItems) || !defined(REAPERAPI_MINIMAL) + {(void**)&CountAutomationItems,"CountAutomationItems"}, + #endif + #if defined(REAPERAPI_WANT_CountEnvelopePoints) || !defined(REAPERAPI_MINIMAL) + {(void**)&CountEnvelopePoints,"CountEnvelopePoints"}, + #endif + #if defined(REAPERAPI_WANT_CountEnvelopePointsEx) || !defined(REAPERAPI_MINIMAL) + {(void**)&CountEnvelopePointsEx,"CountEnvelopePointsEx"}, + #endif + #if defined(REAPERAPI_WANT_CountMediaItems) || !defined(REAPERAPI_MINIMAL) + {(void**)&CountMediaItems,"CountMediaItems"}, + #endif + #if defined(REAPERAPI_WANT_CountProjectMarkers) || !defined(REAPERAPI_MINIMAL) + {(void**)&CountProjectMarkers,"CountProjectMarkers"}, + #endif + #if defined(REAPERAPI_WANT_CountSelectedMediaItems) || !defined(REAPERAPI_MINIMAL) + {(void**)&CountSelectedMediaItems,"CountSelectedMediaItems"}, + #endif + #if defined(REAPERAPI_WANT_CountSelectedTracks) || !defined(REAPERAPI_MINIMAL) + {(void**)&CountSelectedTracks,"CountSelectedTracks"}, + #endif + #if defined(REAPERAPI_WANT_CountSelectedTracks2) || !defined(REAPERAPI_MINIMAL) + {(void**)&CountSelectedTracks2,"CountSelectedTracks2"}, + #endif + #if defined(REAPERAPI_WANT_CountTakeEnvelopes) || !defined(REAPERAPI_MINIMAL) + {(void**)&CountTakeEnvelopes,"CountTakeEnvelopes"}, + #endif + #if defined(REAPERAPI_WANT_CountTakes) || !defined(REAPERAPI_MINIMAL) + {(void**)&CountTakes,"CountTakes"}, + #endif + #if defined(REAPERAPI_WANT_CountTCPFXParms) || !defined(REAPERAPI_MINIMAL) + {(void**)&CountTCPFXParms,"CountTCPFXParms"}, + #endif + #if defined(REAPERAPI_WANT_CountTempoTimeSigMarkers) || !defined(REAPERAPI_MINIMAL) + {(void**)&CountTempoTimeSigMarkers,"CountTempoTimeSigMarkers"}, + #endif + #if defined(REAPERAPI_WANT_CountTrackEnvelopes) || !defined(REAPERAPI_MINIMAL) + {(void**)&CountTrackEnvelopes,"CountTrackEnvelopes"}, + #endif + #if defined(REAPERAPI_WANT_CountTrackMediaItems) || !defined(REAPERAPI_MINIMAL) + {(void**)&CountTrackMediaItems,"CountTrackMediaItems"}, + #endif + #if defined(REAPERAPI_WANT_CountTracks) || !defined(REAPERAPI_MINIMAL) + {(void**)&CountTracks,"CountTracks"}, + #endif + #if defined(REAPERAPI_WANT_CreateLocalOscHandler) || !defined(REAPERAPI_MINIMAL) + {(void**)&CreateLocalOscHandler,"CreateLocalOscHandler"}, + #endif + #if defined(REAPERAPI_WANT_CreateMIDIInput) || !defined(REAPERAPI_MINIMAL) + {(void**)&CreateMIDIInput,"CreateMIDIInput"}, + #endif + #if defined(REAPERAPI_WANT_CreateMIDIOutput) || !defined(REAPERAPI_MINIMAL) + {(void**)&CreateMIDIOutput,"CreateMIDIOutput"}, + #endif + #if defined(REAPERAPI_WANT_CreateNewMIDIItemInProj) || !defined(REAPERAPI_MINIMAL) + {(void**)&CreateNewMIDIItemInProj,"CreateNewMIDIItemInProj"}, + #endif + #if defined(REAPERAPI_WANT_CreateTakeAudioAccessor) || !defined(REAPERAPI_MINIMAL) + {(void**)&CreateTakeAudioAccessor,"CreateTakeAudioAccessor"}, + #endif + #if defined(REAPERAPI_WANT_CreateTrackAudioAccessor) || !defined(REAPERAPI_MINIMAL) + {(void**)&CreateTrackAudioAccessor,"CreateTrackAudioAccessor"}, + #endif + #if defined(REAPERAPI_WANT_CreateTrackSend) || !defined(REAPERAPI_MINIMAL) + {(void**)&CreateTrackSend,"CreateTrackSend"}, + #endif + #if defined(REAPERAPI_WANT_CSurf_FlushUndo) || !defined(REAPERAPI_MINIMAL) + {(void**)&CSurf_FlushUndo,"CSurf_FlushUndo"}, + #endif + #if defined(REAPERAPI_WANT_CSurf_GetTouchState) || !defined(REAPERAPI_MINIMAL) + {(void**)&CSurf_GetTouchState,"CSurf_GetTouchState"}, + #endif + #if defined(REAPERAPI_WANT_CSurf_GoEnd) || !defined(REAPERAPI_MINIMAL) + {(void**)&CSurf_GoEnd,"CSurf_GoEnd"}, + #endif + #if defined(REAPERAPI_WANT_CSurf_GoStart) || !defined(REAPERAPI_MINIMAL) + {(void**)&CSurf_GoStart,"CSurf_GoStart"}, + #endif + #if defined(REAPERAPI_WANT_CSurf_NumTracks) || !defined(REAPERAPI_MINIMAL) + {(void**)&CSurf_NumTracks,"CSurf_NumTracks"}, + #endif + #if defined(REAPERAPI_WANT_CSurf_OnArrow) || !defined(REAPERAPI_MINIMAL) + {(void**)&CSurf_OnArrow,"CSurf_OnArrow"}, + #endif + #if defined(REAPERAPI_WANT_CSurf_OnFwd) || !defined(REAPERAPI_MINIMAL) + {(void**)&CSurf_OnFwd,"CSurf_OnFwd"}, + #endif + #if defined(REAPERAPI_WANT_CSurf_OnFXChange) || !defined(REAPERAPI_MINIMAL) + {(void**)&CSurf_OnFXChange,"CSurf_OnFXChange"}, + #endif + #if defined(REAPERAPI_WANT_CSurf_OnInputMonitorChange) || !defined(REAPERAPI_MINIMAL) + {(void**)&CSurf_OnInputMonitorChange,"CSurf_OnInputMonitorChange"}, + #endif + #if defined(REAPERAPI_WANT_CSurf_OnInputMonitorChangeEx) || !defined(REAPERAPI_MINIMAL) + {(void**)&CSurf_OnInputMonitorChangeEx,"CSurf_OnInputMonitorChangeEx"}, + #endif + #if defined(REAPERAPI_WANT_CSurf_OnMuteChange) || !defined(REAPERAPI_MINIMAL) + {(void**)&CSurf_OnMuteChange,"CSurf_OnMuteChange"}, + #endif + #if defined(REAPERAPI_WANT_CSurf_OnMuteChangeEx) || !defined(REAPERAPI_MINIMAL) + {(void**)&CSurf_OnMuteChangeEx,"CSurf_OnMuteChangeEx"}, + #endif + #if defined(REAPERAPI_WANT_CSurf_OnOscControlMessage) || !defined(REAPERAPI_MINIMAL) + {(void**)&CSurf_OnOscControlMessage,"CSurf_OnOscControlMessage"}, + #endif + #if defined(REAPERAPI_WANT_CSurf_OnPanChange) || !defined(REAPERAPI_MINIMAL) + {(void**)&CSurf_OnPanChange,"CSurf_OnPanChange"}, + #endif + #if defined(REAPERAPI_WANT_CSurf_OnPanChangeEx) || !defined(REAPERAPI_MINIMAL) + {(void**)&CSurf_OnPanChangeEx,"CSurf_OnPanChangeEx"}, + #endif + #if defined(REAPERAPI_WANT_CSurf_OnPause) || !defined(REAPERAPI_MINIMAL) + {(void**)&CSurf_OnPause,"CSurf_OnPause"}, + #endif + #if defined(REAPERAPI_WANT_CSurf_OnPlay) || !defined(REAPERAPI_MINIMAL) + {(void**)&CSurf_OnPlay,"CSurf_OnPlay"}, + #endif + #if defined(REAPERAPI_WANT_CSurf_OnPlayRateChange) || !defined(REAPERAPI_MINIMAL) + {(void**)&CSurf_OnPlayRateChange,"CSurf_OnPlayRateChange"}, + #endif + #if defined(REAPERAPI_WANT_CSurf_OnRecArmChange) || !defined(REAPERAPI_MINIMAL) + {(void**)&CSurf_OnRecArmChange,"CSurf_OnRecArmChange"}, + #endif + #if defined(REAPERAPI_WANT_CSurf_OnRecArmChangeEx) || !defined(REAPERAPI_MINIMAL) + {(void**)&CSurf_OnRecArmChangeEx,"CSurf_OnRecArmChangeEx"}, + #endif + #if defined(REAPERAPI_WANT_CSurf_OnRecord) || !defined(REAPERAPI_MINIMAL) + {(void**)&CSurf_OnRecord,"CSurf_OnRecord"}, + #endif + #if defined(REAPERAPI_WANT_CSurf_OnRecvPanChange) || !defined(REAPERAPI_MINIMAL) + {(void**)&CSurf_OnRecvPanChange,"CSurf_OnRecvPanChange"}, + #endif + #if defined(REAPERAPI_WANT_CSurf_OnRecvVolumeChange) || !defined(REAPERAPI_MINIMAL) + {(void**)&CSurf_OnRecvVolumeChange,"CSurf_OnRecvVolumeChange"}, + #endif + #if defined(REAPERAPI_WANT_CSurf_OnRew) || !defined(REAPERAPI_MINIMAL) + {(void**)&CSurf_OnRew,"CSurf_OnRew"}, + #endif + #if defined(REAPERAPI_WANT_CSurf_OnRewFwd) || !defined(REAPERAPI_MINIMAL) + {(void**)&CSurf_OnRewFwd,"CSurf_OnRewFwd"}, + #endif + #if defined(REAPERAPI_WANT_CSurf_OnScroll) || !defined(REAPERAPI_MINIMAL) + {(void**)&CSurf_OnScroll,"CSurf_OnScroll"}, + #endif + #if defined(REAPERAPI_WANT_CSurf_OnSelectedChange) || !defined(REAPERAPI_MINIMAL) + {(void**)&CSurf_OnSelectedChange,"CSurf_OnSelectedChange"}, + #endif + #if defined(REAPERAPI_WANT_CSurf_OnSendPanChange) || !defined(REAPERAPI_MINIMAL) + {(void**)&CSurf_OnSendPanChange,"CSurf_OnSendPanChange"}, + #endif + #if defined(REAPERAPI_WANT_CSurf_OnSendVolumeChange) || !defined(REAPERAPI_MINIMAL) + {(void**)&CSurf_OnSendVolumeChange,"CSurf_OnSendVolumeChange"}, + #endif + #if defined(REAPERAPI_WANT_CSurf_OnSoloChange) || !defined(REAPERAPI_MINIMAL) + {(void**)&CSurf_OnSoloChange,"CSurf_OnSoloChange"}, + #endif + #if defined(REAPERAPI_WANT_CSurf_OnSoloChangeEx) || !defined(REAPERAPI_MINIMAL) + {(void**)&CSurf_OnSoloChangeEx,"CSurf_OnSoloChangeEx"}, + #endif + #if defined(REAPERAPI_WANT_CSurf_OnStop) || !defined(REAPERAPI_MINIMAL) + {(void**)&CSurf_OnStop,"CSurf_OnStop"}, + #endif + #if defined(REAPERAPI_WANT_CSurf_OnTempoChange) || !defined(REAPERAPI_MINIMAL) + {(void**)&CSurf_OnTempoChange,"CSurf_OnTempoChange"}, + #endif + #if defined(REAPERAPI_WANT_CSurf_OnTrackSelection) || !defined(REAPERAPI_MINIMAL) + {(void**)&CSurf_OnTrackSelection,"CSurf_OnTrackSelection"}, + #endif + #if defined(REAPERAPI_WANT_CSurf_OnVolumeChange) || !defined(REAPERAPI_MINIMAL) + {(void**)&CSurf_OnVolumeChange,"CSurf_OnVolumeChange"}, + #endif + #if defined(REAPERAPI_WANT_CSurf_OnVolumeChangeEx) || !defined(REAPERAPI_MINIMAL) + {(void**)&CSurf_OnVolumeChangeEx,"CSurf_OnVolumeChangeEx"}, + #endif + #if defined(REAPERAPI_WANT_CSurf_OnWidthChange) || !defined(REAPERAPI_MINIMAL) + {(void**)&CSurf_OnWidthChange,"CSurf_OnWidthChange"}, + #endif + #if defined(REAPERAPI_WANT_CSurf_OnWidthChangeEx) || !defined(REAPERAPI_MINIMAL) + {(void**)&CSurf_OnWidthChangeEx,"CSurf_OnWidthChangeEx"}, + #endif + #if defined(REAPERAPI_WANT_CSurf_OnZoom) || !defined(REAPERAPI_MINIMAL) + {(void**)&CSurf_OnZoom,"CSurf_OnZoom"}, + #endif + #if defined(REAPERAPI_WANT_CSurf_ResetAllCachedVolPanStates) || !defined(REAPERAPI_MINIMAL) + {(void**)&CSurf_ResetAllCachedVolPanStates,"CSurf_ResetAllCachedVolPanStates"}, + #endif + #if defined(REAPERAPI_WANT_CSurf_ScrubAmt) || !defined(REAPERAPI_MINIMAL) + {(void**)&CSurf_ScrubAmt,"CSurf_ScrubAmt"}, + #endif + #if defined(REAPERAPI_WANT_CSurf_SetAutoMode) || !defined(REAPERAPI_MINIMAL) + {(void**)&CSurf_SetAutoMode,"CSurf_SetAutoMode"}, + #endif + #if defined(REAPERAPI_WANT_CSurf_SetPlayState) || !defined(REAPERAPI_MINIMAL) + {(void**)&CSurf_SetPlayState,"CSurf_SetPlayState"}, + #endif + #if defined(REAPERAPI_WANT_CSurf_SetRepeatState) || !defined(REAPERAPI_MINIMAL) + {(void**)&CSurf_SetRepeatState,"CSurf_SetRepeatState"}, + #endif + #if defined(REAPERAPI_WANT_CSurf_SetSurfaceMute) || !defined(REAPERAPI_MINIMAL) + {(void**)&CSurf_SetSurfaceMute,"CSurf_SetSurfaceMute"}, + #endif + #if defined(REAPERAPI_WANT_CSurf_SetSurfacePan) || !defined(REAPERAPI_MINIMAL) + {(void**)&CSurf_SetSurfacePan,"CSurf_SetSurfacePan"}, + #endif + #if defined(REAPERAPI_WANT_CSurf_SetSurfaceRecArm) || !defined(REAPERAPI_MINIMAL) + {(void**)&CSurf_SetSurfaceRecArm,"CSurf_SetSurfaceRecArm"}, + #endif + #if defined(REAPERAPI_WANT_CSurf_SetSurfaceSelected) || !defined(REAPERAPI_MINIMAL) + {(void**)&CSurf_SetSurfaceSelected,"CSurf_SetSurfaceSelected"}, + #endif + #if defined(REAPERAPI_WANT_CSurf_SetSurfaceSolo) || !defined(REAPERAPI_MINIMAL) + {(void**)&CSurf_SetSurfaceSolo,"CSurf_SetSurfaceSolo"}, + #endif + #if defined(REAPERAPI_WANT_CSurf_SetSurfaceVolume) || !defined(REAPERAPI_MINIMAL) + {(void**)&CSurf_SetSurfaceVolume,"CSurf_SetSurfaceVolume"}, + #endif + #if defined(REAPERAPI_WANT_CSurf_SetTrackListChange) || !defined(REAPERAPI_MINIMAL) + {(void**)&CSurf_SetTrackListChange,"CSurf_SetTrackListChange"}, + #endif + #if defined(REAPERAPI_WANT_CSurf_TrackFromID) || !defined(REAPERAPI_MINIMAL) + {(void**)&CSurf_TrackFromID,"CSurf_TrackFromID"}, + #endif + #if defined(REAPERAPI_WANT_CSurf_TrackToID) || !defined(REAPERAPI_MINIMAL) + {(void**)&CSurf_TrackToID,"CSurf_TrackToID"}, + #endif + #if defined(REAPERAPI_WANT_DB2SLIDER) || !defined(REAPERAPI_MINIMAL) + {(void**)&DB2SLIDER,"DB2SLIDER"}, + #endif + #if defined(REAPERAPI_WANT_DeleteActionShortcut) || !defined(REAPERAPI_MINIMAL) + {(void**)&DeleteActionShortcut,"DeleteActionShortcut"}, + #endif + #if defined(REAPERAPI_WANT_DeleteEnvelopePointEx) || !defined(REAPERAPI_MINIMAL) + {(void**)&DeleteEnvelopePointEx,"DeleteEnvelopePointEx"}, + #endif + #if defined(REAPERAPI_WANT_DeleteEnvelopePointRange) || !defined(REAPERAPI_MINIMAL) + {(void**)&DeleteEnvelopePointRange,"DeleteEnvelopePointRange"}, + #endif + #if defined(REAPERAPI_WANT_DeleteEnvelopePointRangeEx) || !defined(REAPERAPI_MINIMAL) + {(void**)&DeleteEnvelopePointRangeEx,"DeleteEnvelopePointRangeEx"}, + #endif + #if defined(REAPERAPI_WANT_DeleteExtState) || !defined(REAPERAPI_MINIMAL) + {(void**)&DeleteExtState,"DeleteExtState"}, + #endif + #if defined(REAPERAPI_WANT_DeleteProjectMarker) || !defined(REAPERAPI_MINIMAL) + {(void**)&DeleteProjectMarker,"DeleteProjectMarker"}, + #endif + #if defined(REAPERAPI_WANT_DeleteProjectMarkerByIndex) || !defined(REAPERAPI_MINIMAL) + {(void**)&DeleteProjectMarkerByIndex,"DeleteProjectMarkerByIndex"}, + #endif + #if defined(REAPERAPI_WANT_DeleteTakeMarker) || !defined(REAPERAPI_MINIMAL) + {(void**)&DeleteTakeMarker,"DeleteTakeMarker"}, + #endif + #if defined(REAPERAPI_WANT_DeleteTakeStretchMarkers) || !defined(REAPERAPI_MINIMAL) + {(void**)&DeleteTakeStretchMarkers,"DeleteTakeStretchMarkers"}, + #endif + #if defined(REAPERAPI_WANT_DeleteTempoTimeSigMarker) || !defined(REAPERAPI_MINIMAL) + {(void**)&DeleteTempoTimeSigMarker,"DeleteTempoTimeSigMarker"}, + #endif + #if defined(REAPERAPI_WANT_DeleteTrack) || !defined(REAPERAPI_MINIMAL) + {(void**)&DeleteTrack,"DeleteTrack"}, + #endif + #if defined(REAPERAPI_WANT_DeleteTrackMediaItem) || !defined(REAPERAPI_MINIMAL) + {(void**)&DeleteTrackMediaItem,"DeleteTrackMediaItem"}, + #endif + #if defined(REAPERAPI_WANT_DestroyAudioAccessor) || !defined(REAPERAPI_MINIMAL) + {(void**)&DestroyAudioAccessor,"DestroyAudioAccessor"}, + #endif + #if defined(REAPERAPI_WANT_DestroyLocalOscHandler) || !defined(REAPERAPI_MINIMAL) + {(void**)&DestroyLocalOscHandler,"DestroyLocalOscHandler"}, + #endif + #if defined(REAPERAPI_WANT_DoActionShortcutDialog) || !defined(REAPERAPI_MINIMAL) + {(void**)&DoActionShortcutDialog,"DoActionShortcutDialog"}, + #endif + #if defined(REAPERAPI_WANT_Dock_UpdateDockID) || !defined(REAPERAPI_MINIMAL) + {(void**)&Dock_UpdateDockID,"Dock_UpdateDockID"}, + #endif + #if defined(REAPERAPI_WANT_DockGetPosition) || !defined(REAPERAPI_MINIMAL) + {(void**)&DockGetPosition,"DockGetPosition"}, + #endif + #if defined(REAPERAPI_WANT_DockIsChildOfDock) || !defined(REAPERAPI_MINIMAL) + {(void**)&DockIsChildOfDock,"DockIsChildOfDock"}, + #endif + #if defined(REAPERAPI_WANT_DockWindowActivate) || !defined(REAPERAPI_MINIMAL) + {(void**)&DockWindowActivate,"DockWindowActivate"}, + #endif + #if defined(REAPERAPI_WANT_DockWindowAdd) || !defined(REAPERAPI_MINIMAL) + {(void**)&DockWindowAdd,"DockWindowAdd"}, + #endif + #if defined(REAPERAPI_WANT_DockWindowAddEx) || !defined(REAPERAPI_MINIMAL) + {(void**)&DockWindowAddEx,"DockWindowAddEx"}, + #endif + #if defined(REAPERAPI_WANT_DockWindowRefresh) || !defined(REAPERAPI_MINIMAL) + {(void**)&DockWindowRefresh,"DockWindowRefresh"}, + #endif + #if defined(REAPERAPI_WANT_DockWindowRefreshForHWND) || !defined(REAPERAPI_MINIMAL) + {(void**)&DockWindowRefreshForHWND,"DockWindowRefreshForHWND"}, + #endif + #if defined(REAPERAPI_WANT_DockWindowRemove) || !defined(REAPERAPI_MINIMAL) + {(void**)&DockWindowRemove,"DockWindowRemove"}, + #endif + #if defined(REAPERAPI_WANT_DuplicateCustomizableMenu) || !defined(REAPERAPI_MINIMAL) + {(void**)&DuplicateCustomizableMenu,"DuplicateCustomizableMenu"}, + #endif + #if defined(REAPERAPI_WANT_EditTempoTimeSigMarker) || !defined(REAPERAPI_MINIMAL) + {(void**)&EditTempoTimeSigMarker,"EditTempoTimeSigMarker"}, + #endif + #if defined(REAPERAPI_WANT_EnsureNotCompletelyOffscreen) || !defined(REAPERAPI_MINIMAL) + {(void**)&EnsureNotCompletelyOffscreen,"EnsureNotCompletelyOffscreen"}, + #endif + #if defined(REAPERAPI_WANT_EnumerateFiles) || !defined(REAPERAPI_MINIMAL) + {(void**)&EnumerateFiles,"EnumerateFiles"}, + #endif + #if defined(REAPERAPI_WANT_EnumerateSubdirectories) || !defined(REAPERAPI_MINIMAL) + {(void**)&EnumerateSubdirectories,"EnumerateSubdirectories"}, + #endif + #if defined(REAPERAPI_WANT_EnumPitchShiftModes) || !defined(REAPERAPI_MINIMAL) + {(void**)&EnumPitchShiftModes,"EnumPitchShiftModes"}, + #endif + #if defined(REAPERAPI_WANT_EnumPitchShiftSubModes) || !defined(REAPERAPI_MINIMAL) + {(void**)&EnumPitchShiftSubModes,"EnumPitchShiftSubModes"}, + #endif + #if defined(REAPERAPI_WANT_EnumProjectMarkers) || !defined(REAPERAPI_MINIMAL) + {(void**)&EnumProjectMarkers,"EnumProjectMarkers"}, + #endif + #if defined(REAPERAPI_WANT_EnumProjectMarkers2) || !defined(REAPERAPI_MINIMAL) + {(void**)&EnumProjectMarkers2,"EnumProjectMarkers2"}, + #endif + #if defined(REAPERAPI_WANT_EnumProjectMarkers3) || !defined(REAPERAPI_MINIMAL) + {(void**)&EnumProjectMarkers3,"EnumProjectMarkers3"}, + #endif + #if defined(REAPERAPI_WANT_EnumProjects) || !defined(REAPERAPI_MINIMAL) + {(void**)&EnumProjects,"EnumProjects"}, + #endif + #if defined(REAPERAPI_WANT_EnumProjExtState) || !defined(REAPERAPI_MINIMAL) + {(void**)&EnumProjExtState,"EnumProjExtState"}, + #endif + #if defined(REAPERAPI_WANT_EnumRegionRenderMatrix) || !defined(REAPERAPI_MINIMAL) + {(void**)&EnumRegionRenderMatrix,"EnumRegionRenderMatrix"}, + #endif + #if defined(REAPERAPI_WANT_EnumTrackMIDIProgramNames) || !defined(REAPERAPI_MINIMAL) + {(void**)&EnumTrackMIDIProgramNames,"EnumTrackMIDIProgramNames"}, + #endif + #if defined(REAPERAPI_WANT_EnumTrackMIDIProgramNamesEx) || !defined(REAPERAPI_MINIMAL) + {(void**)&EnumTrackMIDIProgramNamesEx,"EnumTrackMIDIProgramNamesEx"}, + #endif + #if defined(REAPERAPI_WANT_Envelope_Evaluate) || !defined(REAPERAPI_MINIMAL) + {(void**)&Envelope_Evaluate,"Envelope_Evaluate"}, + #endif + #if defined(REAPERAPI_WANT_Envelope_FormatValue) || !defined(REAPERAPI_MINIMAL) + {(void**)&Envelope_FormatValue,"Envelope_FormatValue"}, + #endif + #if defined(REAPERAPI_WANT_Envelope_GetParentTake) || !defined(REAPERAPI_MINIMAL) + {(void**)&Envelope_GetParentTake,"Envelope_GetParentTake"}, + #endif + #if defined(REAPERAPI_WANT_Envelope_GetParentTrack) || !defined(REAPERAPI_MINIMAL) + {(void**)&Envelope_GetParentTrack,"Envelope_GetParentTrack"}, + #endif + #if defined(REAPERAPI_WANT_Envelope_SortPoints) || !defined(REAPERAPI_MINIMAL) + {(void**)&Envelope_SortPoints,"Envelope_SortPoints"}, + #endif + #if defined(REAPERAPI_WANT_Envelope_SortPointsEx) || !defined(REAPERAPI_MINIMAL) + {(void**)&Envelope_SortPointsEx,"Envelope_SortPointsEx"}, + #endif + #if defined(REAPERAPI_WANT_ExecProcess) || !defined(REAPERAPI_MINIMAL) + {(void**)&ExecProcess,"ExecProcess"}, + #endif + #if defined(REAPERAPI_WANT_file_exists) || !defined(REAPERAPI_MINIMAL) + {(void**)&file_exists,"file_exists"}, + #endif + #if defined(REAPERAPI_WANT_FindTempoTimeSigMarker) || !defined(REAPERAPI_MINIMAL) + {(void**)&FindTempoTimeSigMarker,"FindTempoTimeSigMarker"}, + #endif + #if defined(REAPERAPI_WANT_format_timestr) || !defined(REAPERAPI_MINIMAL) + {(void**)&format_timestr,"format_timestr"}, + #endif + #if defined(REAPERAPI_WANT_format_timestr_len) || !defined(REAPERAPI_MINIMAL) + {(void**)&format_timestr_len,"format_timestr_len"}, + #endif + #if defined(REAPERAPI_WANT_format_timestr_pos) || !defined(REAPERAPI_MINIMAL) + {(void**)&format_timestr_pos,"format_timestr_pos"}, + #endif + #if defined(REAPERAPI_WANT_FreeHeapPtr) || !defined(REAPERAPI_MINIMAL) + {(void**)&FreeHeapPtr,"FreeHeapPtr"}, + #endif + #if defined(REAPERAPI_WANT_genGuid) || !defined(REAPERAPI_MINIMAL) + {(void**)&genGuid,"genGuid"}, + #endif + #if defined(REAPERAPI_WANT_get_config_var) || !defined(REAPERAPI_MINIMAL) + {(void**)&get_config_var,"get_config_var"}, + #endif + #if defined(REAPERAPI_WANT_get_config_var_string) || !defined(REAPERAPI_MINIMAL) + {(void**)&get_config_var_string,"get_config_var_string"}, + #endif + #if defined(REAPERAPI_WANT_get_ini_file) || !defined(REAPERAPI_MINIMAL) + {(void**)&get_ini_file,"get_ini_file"}, + #endif + #if defined(REAPERAPI_WANT_get_midi_config_var) || !defined(REAPERAPI_MINIMAL) + {(void**)&get_midi_config_var,"get_midi_config_var"}, + #endif + #if defined(REAPERAPI_WANT_GetActionShortcutDesc) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetActionShortcutDesc,"GetActionShortcutDesc"}, + #endif + #if defined(REAPERAPI_WANT_GetActiveTake) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetActiveTake,"GetActiveTake"}, + #endif + #if defined(REAPERAPI_WANT_GetAllProjectPlayStates) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetAllProjectPlayStates,"GetAllProjectPlayStates"}, + #endif + #if defined(REAPERAPI_WANT_GetAppVersion) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetAppVersion,"GetAppVersion"}, + #endif + #if defined(REAPERAPI_WANT_GetArmedCommand) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetArmedCommand,"GetArmedCommand"}, + #endif + #if defined(REAPERAPI_WANT_GetAudioAccessorEndTime) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetAudioAccessorEndTime,"GetAudioAccessorEndTime"}, + #endif + #if defined(REAPERAPI_WANT_GetAudioAccessorHash) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetAudioAccessorHash,"GetAudioAccessorHash"}, + #endif + #if defined(REAPERAPI_WANT_GetAudioAccessorSamples) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetAudioAccessorSamples,"GetAudioAccessorSamples"}, + #endif + #if defined(REAPERAPI_WANT_GetAudioAccessorStartTime) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetAudioAccessorStartTime,"GetAudioAccessorStartTime"}, + #endif + #if defined(REAPERAPI_WANT_GetAudioDeviceInfo) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetAudioDeviceInfo,"GetAudioDeviceInfo"}, + #endif + #if defined(REAPERAPI_WANT_GetColorTheme) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetColorTheme,"GetColorTheme"}, + #endif + #if defined(REAPERAPI_WANT_GetColorThemeStruct) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetColorThemeStruct,"GetColorThemeStruct"}, + #endif + #if defined(REAPERAPI_WANT_GetConfigWantsDock) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetConfigWantsDock,"GetConfigWantsDock"}, + #endif + #if defined(REAPERAPI_WANT_GetContextMenu) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetContextMenu,"GetContextMenu"}, + #endif + #if defined(REAPERAPI_WANT_GetCurrentProjectInLoadSave) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetCurrentProjectInLoadSave,"GetCurrentProjectInLoadSave"}, + #endif + #if defined(REAPERAPI_WANT_GetCursorContext) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetCursorContext,"GetCursorContext"}, + #endif + #if defined(REAPERAPI_WANT_GetCursorContext2) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetCursorContext2,"GetCursorContext2"}, + #endif + #if defined(REAPERAPI_WANT_GetCursorPosition) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetCursorPosition,"GetCursorPosition"}, + #endif + #if defined(REAPERAPI_WANT_GetCursorPositionEx) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetCursorPositionEx,"GetCursorPositionEx"}, + #endif + #if defined(REAPERAPI_WANT_GetDisplayedMediaItemColor) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetDisplayedMediaItemColor,"GetDisplayedMediaItemColor"}, + #endif + #if defined(REAPERAPI_WANT_GetDisplayedMediaItemColor2) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetDisplayedMediaItemColor2,"GetDisplayedMediaItemColor2"}, + #endif + #if defined(REAPERAPI_WANT_GetEnvelopeInfo_Value) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetEnvelopeInfo_Value,"GetEnvelopeInfo_Value"}, + #endif + #if defined(REAPERAPI_WANT_GetEnvelopeName) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetEnvelopeName,"GetEnvelopeName"}, + #endif + #if defined(REAPERAPI_WANT_GetEnvelopePoint) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetEnvelopePoint,"GetEnvelopePoint"}, + #endif + #if defined(REAPERAPI_WANT_GetEnvelopePointByTime) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetEnvelopePointByTime,"GetEnvelopePointByTime"}, + #endif + #if defined(REAPERAPI_WANT_GetEnvelopePointByTimeEx) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetEnvelopePointByTimeEx,"GetEnvelopePointByTimeEx"}, + #endif + #if defined(REAPERAPI_WANT_GetEnvelopePointEx) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetEnvelopePointEx,"GetEnvelopePointEx"}, + #endif + #if defined(REAPERAPI_WANT_GetEnvelopeScalingMode) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetEnvelopeScalingMode,"GetEnvelopeScalingMode"}, + #endif + #if defined(REAPERAPI_WANT_GetEnvelopeStateChunk) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetEnvelopeStateChunk,"GetEnvelopeStateChunk"}, + #endif + #if defined(REAPERAPI_WANT_GetExePath) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetExePath,"GetExePath"}, + #endif + #if defined(REAPERAPI_WANT_GetExtState) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetExtState,"GetExtState"}, + #endif + #if defined(REAPERAPI_WANT_GetFocusedFX) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetFocusedFX,"GetFocusedFX"}, + #endif + #if defined(REAPERAPI_WANT_GetFocusedFX2) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetFocusedFX2,"GetFocusedFX2"}, + #endif + #if defined(REAPERAPI_WANT_GetFreeDiskSpaceForRecordPath) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetFreeDiskSpaceForRecordPath,"GetFreeDiskSpaceForRecordPath"}, + #endif + #if defined(REAPERAPI_WANT_GetFXEnvelope) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetFXEnvelope,"GetFXEnvelope"}, + #endif + #if defined(REAPERAPI_WANT_GetGlobalAutomationOverride) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetGlobalAutomationOverride,"GetGlobalAutomationOverride"}, + #endif + #if defined(REAPERAPI_WANT_GetHZoomLevel) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetHZoomLevel,"GetHZoomLevel"}, + #endif + #if defined(REAPERAPI_WANT_GetIconThemePointer) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetIconThemePointer,"GetIconThemePointer"}, + #endif + #if defined(REAPERAPI_WANT_GetIconThemePointerForDPI) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetIconThemePointerForDPI,"GetIconThemePointerForDPI"}, + #endif + #if defined(REAPERAPI_WANT_GetIconThemeStruct) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetIconThemeStruct,"GetIconThemeStruct"}, + #endif + #if defined(REAPERAPI_WANT_GetInputChannelName) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetInputChannelName,"GetInputChannelName"}, + #endif + #if defined(REAPERAPI_WANT_GetInputOutputLatency) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetInputOutputLatency,"GetInputOutputLatency"}, + #endif + #if defined(REAPERAPI_WANT_GetItemEditingTime2) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetItemEditingTime2,"GetItemEditingTime2"}, + #endif + #if defined(REAPERAPI_WANT_GetItemFromPoint) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetItemFromPoint,"GetItemFromPoint"}, + #endif + #if defined(REAPERAPI_WANT_GetItemProjectContext) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetItemProjectContext,"GetItemProjectContext"}, + #endif + #if defined(REAPERAPI_WANT_GetItemStateChunk) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetItemStateChunk,"GetItemStateChunk"}, + #endif + #if defined(REAPERAPI_WANT_GetLastColorThemeFile) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetLastColorThemeFile,"GetLastColorThemeFile"}, + #endif + #if defined(REAPERAPI_WANT_GetLastMarkerAndCurRegion) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetLastMarkerAndCurRegion,"GetLastMarkerAndCurRegion"}, + #endif + #if defined(REAPERAPI_WANT_GetLastTouchedFX) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetLastTouchedFX,"GetLastTouchedFX"}, + #endif + #if defined(REAPERAPI_WANT_GetLastTouchedTrack) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetLastTouchedTrack,"GetLastTouchedTrack"}, + #endif + #if defined(REAPERAPI_WANT_GetMainHwnd) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetMainHwnd,"GetMainHwnd"}, + #endif + #if defined(REAPERAPI_WANT_GetMasterMuteSoloFlags) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetMasterMuteSoloFlags,"GetMasterMuteSoloFlags"}, + #endif + #if defined(REAPERAPI_WANT_GetMasterTrack) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetMasterTrack,"GetMasterTrack"}, + #endif + #if defined(REAPERAPI_WANT_GetMasterTrackVisibility) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetMasterTrackVisibility,"GetMasterTrackVisibility"}, + #endif + #if defined(REAPERAPI_WANT_GetMaxMidiInputs) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetMaxMidiInputs,"GetMaxMidiInputs"}, + #endif + #if defined(REAPERAPI_WANT_GetMaxMidiOutputs) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetMaxMidiOutputs,"GetMaxMidiOutputs"}, + #endif + #if defined(REAPERAPI_WANT_GetMediaFileMetadata) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetMediaFileMetadata,"GetMediaFileMetadata"}, + #endif + #if defined(REAPERAPI_WANT_GetMediaItem) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetMediaItem,"GetMediaItem"}, + #endif + #if defined(REAPERAPI_WANT_GetMediaItem_Track) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetMediaItem_Track,"GetMediaItem_Track"}, + #endif + #if defined(REAPERAPI_WANT_GetMediaItemInfo_Value) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetMediaItemInfo_Value,"GetMediaItemInfo_Value"}, + #endif + #if defined(REAPERAPI_WANT_GetMediaItemNumTakes) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetMediaItemNumTakes,"GetMediaItemNumTakes"}, + #endif + #if defined(REAPERAPI_WANT_GetMediaItemTake) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetMediaItemTake,"GetMediaItemTake"}, + #endif + #if defined(REAPERAPI_WANT_GetMediaItemTake_Item) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetMediaItemTake_Item,"GetMediaItemTake_Item"}, + #endif + #if defined(REAPERAPI_WANT_GetMediaItemTake_Peaks) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetMediaItemTake_Peaks,"GetMediaItemTake_Peaks"}, + #endif + #if defined(REAPERAPI_WANT_GetMediaItemTake_Source) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetMediaItemTake_Source,"GetMediaItemTake_Source"}, + #endif + #if defined(REAPERAPI_WANT_GetMediaItemTake_Track) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetMediaItemTake_Track,"GetMediaItemTake_Track"}, + #endif + #if defined(REAPERAPI_WANT_GetMediaItemTakeByGUID) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetMediaItemTakeByGUID,"GetMediaItemTakeByGUID"}, + #endif + #if defined(REAPERAPI_WANT_GetMediaItemTakeInfo_Value) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetMediaItemTakeInfo_Value,"GetMediaItemTakeInfo_Value"}, + #endif + #if defined(REAPERAPI_WANT_GetMediaItemTrack) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetMediaItemTrack,"GetMediaItemTrack"}, + #endif + #if defined(REAPERAPI_WANT_GetMediaSourceFileName) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetMediaSourceFileName,"GetMediaSourceFileName"}, + #endif + #if defined(REAPERAPI_WANT_GetMediaSourceLength) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetMediaSourceLength,"GetMediaSourceLength"}, + #endif + #if defined(REAPERAPI_WANT_GetMediaSourceNumChannels) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetMediaSourceNumChannels,"GetMediaSourceNumChannels"}, + #endif + #if defined(REAPERAPI_WANT_GetMediaSourceParent) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetMediaSourceParent,"GetMediaSourceParent"}, + #endif + #if defined(REAPERAPI_WANT_GetMediaSourceSampleRate) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetMediaSourceSampleRate,"GetMediaSourceSampleRate"}, + #endif + #if defined(REAPERAPI_WANT_GetMediaSourceType) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetMediaSourceType,"GetMediaSourceType"}, + #endif + #if defined(REAPERAPI_WANT_GetMediaTrackInfo_Value) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetMediaTrackInfo_Value,"GetMediaTrackInfo_Value"}, + #endif + #if defined(REAPERAPI_WANT_GetMIDIInputName) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetMIDIInputName,"GetMIDIInputName"}, + #endif + #if defined(REAPERAPI_WANT_GetMIDIOutputName) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetMIDIOutputName,"GetMIDIOutputName"}, + #endif + #if defined(REAPERAPI_WANT_GetMixerScroll) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetMixerScroll,"GetMixerScroll"}, + #endif + #if defined(REAPERAPI_WANT_GetMouseModifier) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetMouseModifier,"GetMouseModifier"}, + #endif + #if defined(REAPERAPI_WANT_GetMousePosition) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetMousePosition,"GetMousePosition"}, + #endif + #if defined(REAPERAPI_WANT_GetNumAudioInputs) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetNumAudioInputs,"GetNumAudioInputs"}, + #endif + #if defined(REAPERAPI_WANT_GetNumAudioOutputs) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetNumAudioOutputs,"GetNumAudioOutputs"}, + #endif + #if defined(REAPERAPI_WANT_GetNumMIDIInputs) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetNumMIDIInputs,"GetNumMIDIInputs"}, + #endif + #if defined(REAPERAPI_WANT_GetNumMIDIOutputs) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetNumMIDIOutputs,"GetNumMIDIOutputs"}, + #endif + #if defined(REAPERAPI_WANT_GetNumTakeMarkers) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetNumTakeMarkers,"GetNumTakeMarkers"}, + #endif + #if defined(REAPERAPI_WANT_GetNumTracks) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetNumTracks,"GetNumTracks"}, + #endif + #if defined(REAPERAPI_WANT_GetOS) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetOS,"GetOS"}, + #endif + #if defined(REAPERAPI_WANT_GetOutputChannelName) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetOutputChannelName,"GetOutputChannelName"}, + #endif + #if defined(REAPERAPI_WANT_GetOutputLatency) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetOutputLatency,"GetOutputLatency"}, + #endif + #if defined(REAPERAPI_WANT_GetParentTrack) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetParentTrack,"GetParentTrack"}, + #endif + #if defined(REAPERAPI_WANT_GetPeakFileName) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetPeakFileName,"GetPeakFileName"}, + #endif + #if defined(REAPERAPI_WANT_GetPeakFileNameEx) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetPeakFileNameEx,"GetPeakFileNameEx"}, + #endif + #if defined(REAPERAPI_WANT_GetPeakFileNameEx2) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetPeakFileNameEx2,"GetPeakFileNameEx2"}, + #endif + #if defined(REAPERAPI_WANT_GetPeaksBitmap) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetPeaksBitmap,"GetPeaksBitmap"}, + #endif + #if defined(REAPERAPI_WANT_GetPlayPosition) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetPlayPosition,"GetPlayPosition"}, + #endif + #if defined(REAPERAPI_WANT_GetPlayPosition2) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetPlayPosition2,"GetPlayPosition2"}, + #endif + #if defined(REAPERAPI_WANT_GetPlayPosition2Ex) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetPlayPosition2Ex,"GetPlayPosition2Ex"}, + #endif + #if defined(REAPERAPI_WANT_GetPlayPositionEx) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetPlayPositionEx,"GetPlayPositionEx"}, + #endif + #if defined(REAPERAPI_WANT_GetPlayState) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetPlayState,"GetPlayState"}, + #endif + #if defined(REAPERAPI_WANT_GetPlayStateEx) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetPlayStateEx,"GetPlayStateEx"}, + #endif + #if defined(REAPERAPI_WANT_GetPreferredDiskReadMode) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetPreferredDiskReadMode,"GetPreferredDiskReadMode"}, + #endif + #if defined(REAPERAPI_WANT_GetPreferredDiskReadModePeak) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetPreferredDiskReadModePeak,"GetPreferredDiskReadModePeak"}, + #endif + #if defined(REAPERAPI_WANT_GetPreferredDiskWriteMode) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetPreferredDiskWriteMode,"GetPreferredDiskWriteMode"}, + #endif + #if defined(REAPERAPI_WANT_GetProjectLength) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetProjectLength,"GetProjectLength"}, + #endif + #if defined(REAPERAPI_WANT_GetProjectName) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetProjectName,"GetProjectName"}, + #endif + #if defined(REAPERAPI_WANT_GetProjectPath) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetProjectPath,"GetProjectPath"}, + #endif + #if defined(REAPERAPI_WANT_GetProjectPathEx) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetProjectPathEx,"GetProjectPathEx"}, + #endif + #if defined(REAPERAPI_WANT_GetProjectStateChangeCount) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetProjectStateChangeCount,"GetProjectStateChangeCount"}, + #endif + #if defined(REAPERAPI_WANT_GetProjectTimeOffset) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetProjectTimeOffset,"GetProjectTimeOffset"}, + #endif + #if defined(REAPERAPI_WANT_GetProjectTimeSignature) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetProjectTimeSignature,"GetProjectTimeSignature"}, + #endif + #if defined(REAPERAPI_WANT_GetProjectTimeSignature2) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetProjectTimeSignature2,"GetProjectTimeSignature2"}, + #endif + #if defined(REAPERAPI_WANT_GetProjExtState) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetProjExtState,"GetProjExtState"}, + #endif + #if defined(REAPERAPI_WANT_GetResourcePath) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetResourcePath,"GetResourcePath"}, + #endif + #if defined(REAPERAPI_WANT_GetSelectedEnvelope) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetSelectedEnvelope,"GetSelectedEnvelope"}, + #endif + #if defined(REAPERAPI_WANT_GetSelectedMediaItem) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetSelectedMediaItem,"GetSelectedMediaItem"}, + #endif + #if defined(REAPERAPI_WANT_GetSelectedTrack) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetSelectedTrack,"GetSelectedTrack"}, + #endif + #if defined(REAPERAPI_WANT_GetSelectedTrack2) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetSelectedTrack2,"GetSelectedTrack2"}, + #endif + #if defined(REAPERAPI_WANT_GetSelectedTrackEnvelope) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetSelectedTrackEnvelope,"GetSelectedTrackEnvelope"}, + #endif + #if defined(REAPERAPI_WANT_GetSet_ArrangeView2) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetSet_ArrangeView2,"GetSet_ArrangeView2"}, + #endif + #if defined(REAPERAPI_WANT_GetSet_LoopTimeRange) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetSet_LoopTimeRange,"GetSet_LoopTimeRange"}, + #endif + #if defined(REAPERAPI_WANT_GetSet_LoopTimeRange2) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetSet_LoopTimeRange2,"GetSet_LoopTimeRange2"}, + #endif + #if defined(REAPERAPI_WANT_GetSetAutomationItemInfo) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetSetAutomationItemInfo,"GetSetAutomationItemInfo"}, + #endif + #if defined(REAPERAPI_WANT_GetSetAutomationItemInfo_String) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetSetAutomationItemInfo_String,"GetSetAutomationItemInfo_String"}, + #endif + #if defined(REAPERAPI_WANT_GetSetEnvelopeInfo_String) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetSetEnvelopeInfo_String,"GetSetEnvelopeInfo_String"}, + #endif + #if defined(REAPERAPI_WANT_GetSetEnvelopeState) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetSetEnvelopeState,"GetSetEnvelopeState"}, + #endif + #if defined(REAPERAPI_WANT_GetSetEnvelopeState2) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetSetEnvelopeState2,"GetSetEnvelopeState2"}, + #endif + #if defined(REAPERAPI_WANT_GetSetItemState) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetSetItemState,"GetSetItemState"}, + #endif + #if defined(REAPERAPI_WANT_GetSetItemState2) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetSetItemState2,"GetSetItemState2"}, + #endif + #if defined(REAPERAPI_WANT_GetSetMediaItemInfo) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetSetMediaItemInfo,"GetSetMediaItemInfo"}, + #endif + #if defined(REAPERAPI_WANT_GetSetMediaItemInfo_String) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetSetMediaItemInfo_String,"GetSetMediaItemInfo_String"}, + #endif + #if defined(REAPERAPI_WANT_GetSetMediaItemTakeInfo) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetSetMediaItemTakeInfo,"GetSetMediaItemTakeInfo"}, + #endif + #if defined(REAPERAPI_WANT_GetSetMediaItemTakeInfo_String) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetSetMediaItemTakeInfo_String,"GetSetMediaItemTakeInfo_String"}, + #endif + #if defined(REAPERAPI_WANT_GetSetMediaTrackInfo) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetSetMediaTrackInfo,"GetSetMediaTrackInfo"}, + #endif + #if defined(REAPERAPI_WANT_GetSetMediaTrackInfo_String) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetSetMediaTrackInfo_String,"GetSetMediaTrackInfo_String"}, + #endif + #if defined(REAPERAPI_WANT_GetSetObjectState) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetSetObjectState,"GetSetObjectState"}, + #endif + #if defined(REAPERAPI_WANT_GetSetObjectState2) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetSetObjectState2,"GetSetObjectState2"}, + #endif + #if defined(REAPERAPI_WANT_GetSetProjectAuthor) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetSetProjectAuthor,"GetSetProjectAuthor"}, + #endif + #if defined(REAPERAPI_WANT_GetSetProjectGrid) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetSetProjectGrid,"GetSetProjectGrid"}, + #endif + #if defined(REAPERAPI_WANT_GetSetProjectInfo) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetSetProjectInfo,"GetSetProjectInfo"}, + #endif + #if defined(REAPERAPI_WANT_GetSetProjectInfo_String) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetSetProjectInfo_String,"GetSetProjectInfo_String"}, + #endif + #if defined(REAPERAPI_WANT_GetSetProjectNotes) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetSetProjectNotes,"GetSetProjectNotes"}, + #endif + #if defined(REAPERAPI_WANT_GetSetRepeat) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetSetRepeat,"GetSetRepeat"}, + #endif + #if defined(REAPERAPI_WANT_GetSetRepeatEx) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetSetRepeatEx,"GetSetRepeatEx"}, + #endif + #if defined(REAPERAPI_WANT_GetSetTrackGroupMembership) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetSetTrackGroupMembership,"GetSetTrackGroupMembership"}, + #endif + #if defined(REAPERAPI_WANT_GetSetTrackGroupMembershipHigh) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetSetTrackGroupMembershipHigh,"GetSetTrackGroupMembershipHigh"}, + #endif + #if defined(REAPERAPI_WANT_GetSetTrackMIDISupportFile) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetSetTrackMIDISupportFile,"GetSetTrackMIDISupportFile"}, + #endif + #if defined(REAPERAPI_WANT_GetSetTrackSendInfo) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetSetTrackSendInfo,"GetSetTrackSendInfo"}, + #endif + #if defined(REAPERAPI_WANT_GetSetTrackSendInfo_String) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetSetTrackSendInfo_String,"GetSetTrackSendInfo_String"}, + #endif + #if defined(REAPERAPI_WANT_GetSetTrackState) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetSetTrackState,"GetSetTrackState"}, + #endif + #if defined(REAPERAPI_WANT_GetSetTrackState2) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetSetTrackState2,"GetSetTrackState2"}, + #endif + #if defined(REAPERAPI_WANT_GetSubProjectFromSource) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetSubProjectFromSource,"GetSubProjectFromSource"}, + #endif + #if defined(REAPERAPI_WANT_GetTake) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetTake,"GetTake"}, + #endif + #if defined(REAPERAPI_WANT_GetTakeEnvelope) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetTakeEnvelope,"GetTakeEnvelope"}, + #endif + #if defined(REAPERAPI_WANT_GetTakeEnvelopeByName) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetTakeEnvelopeByName,"GetTakeEnvelopeByName"}, + #endif + #if defined(REAPERAPI_WANT_GetTakeMarker) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetTakeMarker,"GetTakeMarker"}, + #endif + #if defined(REAPERAPI_WANT_GetTakeName) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetTakeName,"GetTakeName"}, + #endif + #if defined(REAPERAPI_WANT_GetTakeNumStretchMarkers) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetTakeNumStretchMarkers,"GetTakeNumStretchMarkers"}, + #endif + #if defined(REAPERAPI_WANT_GetTakeStretchMarker) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetTakeStretchMarker,"GetTakeStretchMarker"}, + #endif + #if defined(REAPERAPI_WANT_GetTakeStretchMarkerSlope) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetTakeStretchMarkerSlope,"GetTakeStretchMarkerSlope"}, + #endif + #if defined(REAPERAPI_WANT_GetTCPFXParm) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetTCPFXParm,"GetTCPFXParm"}, + #endif + #if defined(REAPERAPI_WANT_GetTempoMatchPlayRate) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetTempoMatchPlayRate,"GetTempoMatchPlayRate"}, + #endif + #if defined(REAPERAPI_WANT_GetTempoTimeSigMarker) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetTempoTimeSigMarker,"GetTempoTimeSigMarker"}, + #endif + #if defined(REAPERAPI_WANT_GetThemeColor) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetThemeColor,"GetThemeColor"}, + #endif + #if defined(REAPERAPI_WANT_GetThingFromPoint) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetThingFromPoint,"GetThingFromPoint"}, + #endif + #if defined(REAPERAPI_WANT_GetToggleCommandState) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetToggleCommandState,"GetToggleCommandState"}, + #endif + #if defined(REAPERAPI_WANT_GetToggleCommandState2) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetToggleCommandState2,"GetToggleCommandState2"}, + #endif + #if defined(REAPERAPI_WANT_GetToggleCommandStateEx) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetToggleCommandStateEx,"GetToggleCommandStateEx"}, + #endif + #if defined(REAPERAPI_WANT_GetToggleCommandStateThroughHooks) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetToggleCommandStateThroughHooks,"GetToggleCommandStateThroughHooks"}, + #endif + #if defined(REAPERAPI_WANT_GetTooltipWindow) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetTooltipWindow,"GetTooltipWindow"}, + #endif + #if defined(REAPERAPI_WANT_GetTrack) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetTrack,"GetTrack"}, + #endif + #if defined(REAPERAPI_WANT_GetTrackAutomationMode) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetTrackAutomationMode,"GetTrackAutomationMode"}, + #endif + #if defined(REAPERAPI_WANT_GetTrackColor) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetTrackColor,"GetTrackColor"}, + #endif + #if defined(REAPERAPI_WANT_GetTrackDepth) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetTrackDepth,"GetTrackDepth"}, + #endif + #if defined(REAPERAPI_WANT_GetTrackEnvelope) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetTrackEnvelope,"GetTrackEnvelope"}, + #endif + #if defined(REAPERAPI_WANT_GetTrackEnvelopeByChunkName) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetTrackEnvelopeByChunkName,"GetTrackEnvelopeByChunkName"}, + #endif + #if defined(REAPERAPI_WANT_GetTrackEnvelopeByName) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetTrackEnvelopeByName,"GetTrackEnvelopeByName"}, + #endif + #if defined(REAPERAPI_WANT_GetTrackFromPoint) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetTrackFromPoint,"GetTrackFromPoint"}, + #endif + #if defined(REAPERAPI_WANT_GetTrackGUID) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetTrackGUID,"GetTrackGUID"}, + #endif + #if defined(REAPERAPI_WANT_GetTrackInfo) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetTrackInfo,"GetTrackInfo"}, + #endif + #if defined(REAPERAPI_WANT_GetTrackMediaItem) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetTrackMediaItem,"GetTrackMediaItem"}, + #endif + #if defined(REAPERAPI_WANT_GetTrackMIDILyrics) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetTrackMIDILyrics,"GetTrackMIDILyrics"}, + #endif + #if defined(REAPERAPI_WANT_GetTrackMIDINoteName) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetTrackMIDINoteName,"GetTrackMIDINoteName"}, + #endif + #if defined(REAPERAPI_WANT_GetTrackMIDINoteNameEx) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetTrackMIDINoteNameEx,"GetTrackMIDINoteNameEx"}, + #endif + #if defined(REAPERAPI_WANT_GetTrackMIDINoteRange) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetTrackMIDINoteRange,"GetTrackMIDINoteRange"}, + #endif + #if defined(REAPERAPI_WANT_GetTrackName) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetTrackName,"GetTrackName"}, + #endif + #if defined(REAPERAPI_WANT_GetTrackNumMediaItems) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetTrackNumMediaItems,"GetTrackNumMediaItems"}, + #endif + #if defined(REAPERAPI_WANT_GetTrackNumSends) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetTrackNumSends,"GetTrackNumSends"}, + #endif + #if defined(REAPERAPI_WANT_GetTrackReceiveName) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetTrackReceiveName,"GetTrackReceiveName"}, + #endif + #if defined(REAPERAPI_WANT_GetTrackReceiveUIMute) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetTrackReceiveUIMute,"GetTrackReceiveUIMute"}, + #endif + #if defined(REAPERAPI_WANT_GetTrackReceiveUIVolPan) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetTrackReceiveUIVolPan,"GetTrackReceiveUIVolPan"}, + #endif + #if defined(REAPERAPI_WANT_GetTrackSendInfo_Value) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetTrackSendInfo_Value,"GetTrackSendInfo_Value"}, + #endif + #if defined(REAPERAPI_WANT_GetTrackSendName) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetTrackSendName,"GetTrackSendName"}, + #endif + #if defined(REAPERAPI_WANT_GetTrackSendUIMute) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetTrackSendUIMute,"GetTrackSendUIMute"}, + #endif + #if defined(REAPERAPI_WANT_GetTrackSendUIVolPan) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetTrackSendUIVolPan,"GetTrackSendUIVolPan"}, + #endif + #if defined(REAPERAPI_WANT_GetTrackState) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetTrackState,"GetTrackState"}, + #endif + #if defined(REAPERAPI_WANT_GetTrackStateChunk) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetTrackStateChunk,"GetTrackStateChunk"}, + #endif + #if defined(REAPERAPI_WANT_GetTrackUIMute) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetTrackUIMute,"GetTrackUIMute"}, + #endif + #if defined(REAPERAPI_WANT_GetTrackUIPan) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetTrackUIPan,"GetTrackUIPan"}, + #endif + #if defined(REAPERAPI_WANT_GetTrackUIVolPan) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetTrackUIVolPan,"GetTrackUIVolPan"}, + #endif + #if defined(REAPERAPI_WANT_GetUnderrunTime) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetUnderrunTime,"GetUnderrunTime"}, + #endif + #if defined(REAPERAPI_WANT_GetUserFileNameForRead) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetUserFileNameForRead,"GetUserFileNameForRead"}, + #endif + #if defined(REAPERAPI_WANT_GetUserInputs) || !defined(REAPERAPI_MINIMAL) + {(void**)&GetUserInputs,"GetUserInputs"}, + #endif + #if defined(REAPERAPI_WANT_GoToMarker) || !defined(REAPERAPI_MINIMAL) + {(void**)&GoToMarker,"GoToMarker"}, + #endif + #if defined(REAPERAPI_WANT_GoToRegion) || !defined(REAPERAPI_MINIMAL) + {(void**)&GoToRegion,"GoToRegion"}, + #endif + #if defined(REAPERAPI_WANT_GR_SelectColor) || !defined(REAPERAPI_MINIMAL) + {(void**)&GR_SelectColor,"GR_SelectColor"}, + #endif + #if defined(REAPERAPI_WANT_GSC_mainwnd) || !defined(REAPERAPI_MINIMAL) + {(void**)&GSC_mainwnd,"GSC_mainwnd"}, + #endif + #if defined(REAPERAPI_WANT_guidToString) || !defined(REAPERAPI_MINIMAL) + {(void**)&guidToString,"guidToString"}, + #endif + #if defined(REAPERAPI_WANT_HasExtState) || !defined(REAPERAPI_MINIMAL) + {(void**)&HasExtState,"HasExtState"}, + #endif + #if defined(REAPERAPI_WANT_HasTrackMIDIPrograms) || !defined(REAPERAPI_MINIMAL) + {(void**)&HasTrackMIDIPrograms,"HasTrackMIDIPrograms"}, + #endif + #if defined(REAPERAPI_WANT_HasTrackMIDIProgramsEx) || !defined(REAPERAPI_MINIMAL) + {(void**)&HasTrackMIDIProgramsEx,"HasTrackMIDIProgramsEx"}, + #endif + #if defined(REAPERAPI_WANT_Help_Set) || !defined(REAPERAPI_MINIMAL) + {(void**)&Help_Set,"Help_Set"}, + #endif + #if defined(REAPERAPI_WANT_HiresPeaksFromSource) || !defined(REAPERAPI_MINIMAL) + {(void**)&HiresPeaksFromSource,"HiresPeaksFromSource"}, + #endif + #if defined(REAPERAPI_WANT_image_resolve_fn) || !defined(REAPERAPI_MINIMAL) + {(void**)&image_resolve_fn,"image_resolve_fn"}, + #endif + #if defined(REAPERAPI_WANT_InsertAutomationItem) || !defined(REAPERAPI_MINIMAL) + {(void**)&InsertAutomationItem,"InsertAutomationItem"}, + #endif + #if defined(REAPERAPI_WANT_InsertEnvelopePoint) || !defined(REAPERAPI_MINIMAL) + {(void**)&InsertEnvelopePoint,"InsertEnvelopePoint"}, + #endif + #if defined(REAPERAPI_WANT_InsertEnvelopePointEx) || !defined(REAPERAPI_MINIMAL) + {(void**)&InsertEnvelopePointEx,"InsertEnvelopePointEx"}, + #endif + #if defined(REAPERAPI_WANT_InsertMedia) || !defined(REAPERAPI_MINIMAL) + {(void**)&InsertMedia,"InsertMedia"}, + #endif + #if defined(REAPERAPI_WANT_InsertMediaSection) || !defined(REAPERAPI_MINIMAL) + {(void**)&InsertMediaSection,"InsertMediaSection"}, + #endif + #if defined(REAPERAPI_WANT_InsertTrackAtIndex) || !defined(REAPERAPI_MINIMAL) + {(void**)&InsertTrackAtIndex,"InsertTrackAtIndex"}, + #endif + #if defined(REAPERAPI_WANT_IsInRealTimeAudio) || !defined(REAPERAPI_MINIMAL) + {(void**)&IsInRealTimeAudio,"IsInRealTimeAudio"}, + #endif + #if defined(REAPERAPI_WANT_IsItemTakeActiveForPlayback) || !defined(REAPERAPI_MINIMAL) + {(void**)&IsItemTakeActiveForPlayback,"IsItemTakeActiveForPlayback"}, + #endif + #if defined(REAPERAPI_WANT_IsMediaExtension) || !defined(REAPERAPI_MINIMAL) + {(void**)&IsMediaExtension,"IsMediaExtension"}, + #endif + #if defined(REAPERAPI_WANT_IsMediaItemSelected) || !defined(REAPERAPI_MINIMAL) + {(void**)&IsMediaItemSelected,"IsMediaItemSelected"}, + #endif + #if defined(REAPERAPI_WANT_IsProjectDirty) || !defined(REAPERAPI_MINIMAL) + {(void**)&IsProjectDirty,"IsProjectDirty"}, + #endif + #if defined(REAPERAPI_WANT_IsREAPER) || !defined(REAPERAPI_MINIMAL) + {(void**)&IsREAPER,"IsREAPER"}, + #endif + #if defined(REAPERAPI_WANT_IsTrackSelected) || !defined(REAPERAPI_MINIMAL) + {(void**)&IsTrackSelected,"IsTrackSelected"}, + #endif + #if defined(REAPERAPI_WANT_IsTrackVisible) || !defined(REAPERAPI_MINIMAL) + {(void**)&IsTrackVisible,"IsTrackVisible"}, + #endif + #if defined(REAPERAPI_WANT_joystick_create) || !defined(REAPERAPI_MINIMAL) + {(void**)&joystick_create,"joystick_create"}, + #endif + #if defined(REAPERAPI_WANT_joystick_destroy) || !defined(REAPERAPI_MINIMAL) + {(void**)&joystick_destroy,"joystick_destroy"}, + #endif + #if defined(REAPERAPI_WANT_joystick_enum) || !defined(REAPERAPI_MINIMAL) + {(void**)&joystick_enum,"joystick_enum"}, + #endif + #if defined(REAPERAPI_WANT_joystick_getaxis) || !defined(REAPERAPI_MINIMAL) + {(void**)&joystick_getaxis,"joystick_getaxis"}, + #endif + #if defined(REAPERAPI_WANT_joystick_getbuttonmask) || !defined(REAPERAPI_MINIMAL) + {(void**)&joystick_getbuttonmask,"joystick_getbuttonmask"}, + #endif + #if defined(REAPERAPI_WANT_joystick_getinfo) || !defined(REAPERAPI_MINIMAL) + {(void**)&joystick_getinfo,"joystick_getinfo"}, + #endif + #if defined(REAPERAPI_WANT_joystick_getpov) || !defined(REAPERAPI_MINIMAL) + {(void**)&joystick_getpov,"joystick_getpov"}, + #endif + #if defined(REAPERAPI_WANT_joystick_update) || !defined(REAPERAPI_MINIMAL) + {(void**)&joystick_update,"joystick_update"}, + #endif + #if defined(REAPERAPI_WANT_kbd_enumerateActions) || !defined(REAPERAPI_MINIMAL) + {(void**)&kbd_enumerateActions,"kbd_enumerateActions"}, + #endif + #if defined(REAPERAPI_WANT_kbd_formatKeyName) || !defined(REAPERAPI_MINIMAL) + {(void**)&kbd_formatKeyName,"kbd_formatKeyName"}, + #endif + #if defined(REAPERAPI_WANT_kbd_getCommandName) || !defined(REAPERAPI_MINIMAL) + {(void**)&kbd_getCommandName,"kbd_getCommandName"}, + #endif + #if defined(REAPERAPI_WANT_kbd_getTextFromCmd) || !defined(REAPERAPI_MINIMAL) + {(void**)&kbd_getTextFromCmd,"kbd_getTextFromCmd"}, + #endif + #if defined(REAPERAPI_WANT_KBD_OnMainActionEx) || !defined(REAPERAPI_MINIMAL) + {(void**)&KBD_OnMainActionEx,"KBD_OnMainActionEx"}, + #endif + #if defined(REAPERAPI_WANT_kbd_OnMidiEvent) || !defined(REAPERAPI_MINIMAL) + {(void**)&kbd_OnMidiEvent,"kbd_OnMidiEvent"}, + #endif + #if defined(REAPERAPI_WANT_kbd_OnMidiList) || !defined(REAPERAPI_MINIMAL) + {(void**)&kbd_OnMidiList,"kbd_OnMidiList"}, + #endif + #if defined(REAPERAPI_WANT_kbd_ProcessActionsMenu) || !defined(REAPERAPI_MINIMAL) + {(void**)&kbd_ProcessActionsMenu,"kbd_ProcessActionsMenu"}, + #endif + #if defined(REAPERAPI_WANT_kbd_processMidiEventActionEx) || !defined(REAPERAPI_MINIMAL) + {(void**)&kbd_processMidiEventActionEx,"kbd_processMidiEventActionEx"}, + #endif + #if defined(REAPERAPI_WANT_kbd_reprocessMenu) || !defined(REAPERAPI_MINIMAL) + {(void**)&kbd_reprocessMenu,"kbd_reprocessMenu"}, + #endif + #if defined(REAPERAPI_WANT_kbd_RunCommandThroughHooks) || !defined(REAPERAPI_MINIMAL) + {(void**)&kbd_RunCommandThroughHooks,"kbd_RunCommandThroughHooks"}, + #endif + #if defined(REAPERAPI_WANT_kbd_translateAccelerator) || !defined(REAPERAPI_MINIMAL) + {(void**)&kbd_translateAccelerator,"kbd_translateAccelerator"}, + #endif + #if defined(REAPERAPI_WANT_kbd_translateMouse) || !defined(REAPERAPI_MINIMAL) + {(void**)&kbd_translateMouse,"kbd_translateMouse"}, + #endif + + + #ifndef REAPERAPI_NO_LICE + #if defined(REAPERAPI_WANT_LICE__Destroy) || !defined(REAPERAPI_MINIMAL) + {(void**)&LICE__Destroy,"LICE__Destroy"}, + #endif + #if defined(REAPERAPI_WANT_LICE__DestroyFont) || !defined(REAPERAPI_MINIMAL) + {(void**)&LICE__DestroyFont,"LICE__DestroyFont"}, + #endif + #if defined(REAPERAPI_WANT_LICE__DrawText) || !defined(REAPERAPI_MINIMAL) + {(void**)&LICE__DrawText,"LICE__DrawText"}, + #endif + #if defined(REAPERAPI_WANT_LICE__GetBits) || !defined(REAPERAPI_MINIMAL) + {(void**)&LICE__GetBits,"LICE__GetBits"}, + #endif + #if defined(REAPERAPI_WANT_LICE__GetDC) || !defined(REAPERAPI_MINIMAL) + {(void**)&LICE__GetDC,"LICE__GetDC"}, + #endif + #if defined(REAPERAPI_WANT_LICE__GetHeight) || !defined(REAPERAPI_MINIMAL) + {(void**)&LICE__GetHeight,"LICE__GetHeight"}, + #endif + #if defined(REAPERAPI_WANT_LICE__GetRowSpan) || !defined(REAPERAPI_MINIMAL) + {(void**)&LICE__GetRowSpan,"LICE__GetRowSpan"}, + #endif + #if defined(REAPERAPI_WANT_LICE__GetWidth) || !defined(REAPERAPI_MINIMAL) + {(void**)&LICE__GetWidth,"LICE__GetWidth"}, + #endif + #if defined(REAPERAPI_WANT_LICE__IsFlipped) || !defined(REAPERAPI_MINIMAL) + {(void**)&LICE__IsFlipped,"LICE__IsFlipped"}, + #endif + #if defined(REAPERAPI_WANT_LICE__resize) || !defined(REAPERAPI_MINIMAL) + {(void**)&LICE__resize,"LICE__resize"}, + #endif + #if defined(REAPERAPI_WANT_LICE__SetBkColor) || !defined(REAPERAPI_MINIMAL) + {(void**)&LICE__SetBkColor,"LICE__SetBkColor"}, + #endif + #if defined(REAPERAPI_WANT_LICE__SetFromHFont) || !defined(REAPERAPI_MINIMAL) + {(void**)&LICE__SetFromHFont,"LICE__SetFromHFont"}, + #endif + #if defined(REAPERAPI_WANT_LICE__SetTextColor) || !defined(REAPERAPI_MINIMAL) + {(void**)&LICE__SetTextColor,"LICE__SetTextColor"}, + #endif + #if defined(REAPERAPI_WANT_LICE__SetTextCombineMode) || !defined(REAPERAPI_MINIMAL) + {(void**)&LICE__SetTextCombineMode,"LICE__SetTextCombineMode"}, + #endif + #if defined(REAPERAPI_WANT_LICE_Arc) || !defined(REAPERAPI_MINIMAL) + {(void**)&LICE_Arc,"LICE_Arc"}, + #endif + #if defined(REAPERAPI_WANT_LICE_Blit) || !defined(REAPERAPI_MINIMAL) + {(void**)&LICE_Blit,"LICE_Blit"}, + #endif + #if defined(REAPERAPI_WANT_LICE_Blur) || !defined(REAPERAPI_MINIMAL) + {(void**)&LICE_Blur,"LICE_Blur"}, + #endif + #if defined(REAPERAPI_WANT_LICE_BorderedRect) || !defined(REAPERAPI_MINIMAL) + {(void**)&LICE_BorderedRect,"LICE_BorderedRect"}, + #endif + #if defined(REAPERAPI_WANT_LICE_Circle) || !defined(REAPERAPI_MINIMAL) + {(void**)&LICE_Circle,"LICE_Circle"}, + #endif + #if defined(REAPERAPI_WANT_LICE_Clear) || !defined(REAPERAPI_MINIMAL) + {(void**)&LICE_Clear,"LICE_Clear"}, + #endif + #if defined(REAPERAPI_WANT_LICE_ClearRect) || !defined(REAPERAPI_MINIMAL) + {(void**)&LICE_ClearRect,"LICE_ClearRect"}, + #endif + #if defined(REAPERAPI_WANT_LICE_ClipLine) || !defined(REAPERAPI_MINIMAL) + {(void**)&LICE_ClipLine,"LICE_ClipLine"}, + #endif + #if defined(REAPERAPI_WANT_LICE_Copy) || !defined(REAPERAPI_MINIMAL) + {(void**)&LICE_Copy,"LICE_Copy"}, + #endif + #if defined(REAPERAPI_WANT_LICE_CreateBitmap) || !defined(REAPERAPI_MINIMAL) + {(void**)&LICE_CreateBitmap,"LICE_CreateBitmap"}, + #endif + #if defined(REAPERAPI_WANT_LICE_CreateFont) || !defined(REAPERAPI_MINIMAL) + {(void**)&LICE_CreateFont,"LICE_CreateFont"}, + #endif + #if defined(REAPERAPI_WANT_LICE_DrawCBezier) || !defined(REAPERAPI_MINIMAL) + {(void**)&LICE_DrawCBezier,"LICE_DrawCBezier"}, + #endif + #if defined(REAPERAPI_WANT_LICE_DrawChar) || !defined(REAPERAPI_MINIMAL) + {(void**)&LICE_DrawChar,"LICE_DrawChar"}, + #endif + #if defined(REAPERAPI_WANT_LICE_DrawGlyph) || !defined(REAPERAPI_MINIMAL) + {(void**)&LICE_DrawGlyph,"LICE_DrawGlyph"}, + #endif + #if defined(REAPERAPI_WANT_LICE_DrawRect) || !defined(REAPERAPI_MINIMAL) + {(void**)&LICE_DrawRect,"LICE_DrawRect"}, + #endif + #if defined(REAPERAPI_WANT_LICE_DrawText) || !defined(REAPERAPI_MINIMAL) + {(void**)&LICE_DrawText,"LICE_DrawText"}, + #endif + #if defined(REAPERAPI_WANT_LICE_FillCBezier) || !defined(REAPERAPI_MINIMAL) + {(void**)&LICE_FillCBezier,"LICE_FillCBezier"}, + #endif + #if defined(REAPERAPI_WANT_LICE_FillCircle) || !defined(REAPERAPI_MINIMAL) + {(void**)&LICE_FillCircle,"LICE_FillCircle"}, + #endif + #if defined(REAPERAPI_WANT_LICE_FillConvexPolygon) || !defined(REAPERAPI_MINIMAL) + {(void**)&LICE_FillConvexPolygon,"LICE_FillConvexPolygon"}, + #endif + #if defined(REAPERAPI_WANT_LICE_FillRect) || !defined(REAPERAPI_MINIMAL) + {(void**)&LICE_FillRect,"LICE_FillRect"}, + #endif + #if defined(REAPERAPI_WANT_LICE_FillTrapezoid) || !defined(REAPERAPI_MINIMAL) + {(void**)&LICE_FillTrapezoid,"LICE_FillTrapezoid"}, + #endif + #if defined(REAPERAPI_WANT_LICE_FillTriangle) || !defined(REAPERAPI_MINIMAL) + {(void**)&LICE_FillTriangle,"LICE_FillTriangle"}, + #endif + #if defined(REAPERAPI_WANT_LICE_GetPixel) || !defined(REAPERAPI_MINIMAL) + {(void**)&LICE_GetPixel,"LICE_GetPixel"}, + #endif + #if defined(REAPERAPI_WANT_LICE_GradRect) || !defined(REAPERAPI_MINIMAL) + {(void**)&LICE_GradRect,"LICE_GradRect"}, + #endif + #if defined(REAPERAPI_WANT_LICE_Line) || !defined(REAPERAPI_MINIMAL) + {(void**)&LICE_Line,"LICE_Line"}, + #endif + #if defined(REAPERAPI_WANT_LICE_LineInt) || !defined(REAPERAPI_MINIMAL) + {(void**)&LICE_LineInt,"LICE_LineInt"}, + #endif + #if defined(REAPERAPI_WANT_LICE_LoadPNG) || !defined(REAPERAPI_MINIMAL) + {(void**)&LICE_LoadPNG,"LICE_LoadPNG"}, + #endif + #if defined(REAPERAPI_WANT_LICE_LoadPNGFromResource) || !defined(REAPERAPI_MINIMAL) + {(void**)&LICE_LoadPNGFromResource,"LICE_LoadPNGFromResource"}, + #endif + #if defined(REAPERAPI_WANT_LICE_MeasureText) || !defined(REAPERAPI_MINIMAL) + {(void**)&LICE_MeasureText,"LICE_MeasureText"}, + #endif + #if defined(REAPERAPI_WANT_LICE_MultiplyAddRect) || !defined(REAPERAPI_MINIMAL) + {(void**)&LICE_MultiplyAddRect,"LICE_MultiplyAddRect"}, + #endif + #if defined(REAPERAPI_WANT_LICE_PutPixel) || !defined(REAPERAPI_MINIMAL) + {(void**)&LICE_PutPixel,"LICE_PutPixel"}, + #endif + #if defined(REAPERAPI_WANT_LICE_RotatedBlit) || !defined(REAPERAPI_MINIMAL) + {(void**)&LICE_RotatedBlit,"LICE_RotatedBlit"}, + #endif + #if defined(REAPERAPI_WANT_LICE_RoundRect) || !defined(REAPERAPI_MINIMAL) + {(void**)&LICE_RoundRect,"LICE_RoundRect"}, + #endif + #if defined(REAPERAPI_WANT_LICE_ScaledBlit) || !defined(REAPERAPI_MINIMAL) + {(void**)&LICE_ScaledBlit,"LICE_ScaledBlit"}, + #endif + #if defined(REAPERAPI_WANT_LICE_SimpleFill) || !defined(REAPERAPI_MINIMAL) + {(void**)&LICE_SimpleFill,"LICE_SimpleFill"}, + #endif + #if defined(REAPERAPI_WANT_LICE_ThickFLine) || !defined(REAPERAPI_MINIMAL) + {(void**)&LICE_ThickFLine,"LICE_ThickFLine"}, + #endif + + #endif // !REAPERAPI_NO_LICE + + #if defined(REAPERAPI_WANT_LocalizeString) || !defined(REAPERAPI_MINIMAL) + {(void**)&LocalizeString,"LocalizeString"}, + #endif + #if defined(REAPERAPI_WANT_Loop_OnArrow) || !defined(REAPERAPI_MINIMAL) + {(void**)&Loop_OnArrow,"Loop_OnArrow"}, + #endif + #if defined(REAPERAPI_WANT_Main_OnCommand) || !defined(REAPERAPI_MINIMAL) + {(void**)&Main_OnCommand,"Main_OnCommand"}, + #endif + #if defined(REAPERAPI_WANT_Main_OnCommandEx) || !defined(REAPERAPI_MINIMAL) + {(void**)&Main_OnCommandEx,"Main_OnCommandEx"}, + #endif + #if defined(REAPERAPI_WANT_Main_openProject) || !defined(REAPERAPI_MINIMAL) + {(void**)&Main_openProject,"Main_openProject"}, + #endif + #if defined(REAPERAPI_WANT_Main_SaveProject) || !defined(REAPERAPI_MINIMAL) + {(void**)&Main_SaveProject,"Main_SaveProject"}, + #endif + #if defined(REAPERAPI_WANT_Main_UpdateLoopInfo) || !defined(REAPERAPI_MINIMAL) + {(void**)&Main_UpdateLoopInfo,"Main_UpdateLoopInfo"}, + #endif + #if defined(REAPERAPI_WANT_MarkProjectDirty) || !defined(REAPERAPI_MINIMAL) + {(void**)&MarkProjectDirty,"MarkProjectDirty"}, + #endif + #if defined(REAPERAPI_WANT_MarkTrackItemsDirty) || !defined(REAPERAPI_MINIMAL) + {(void**)&MarkTrackItemsDirty,"MarkTrackItemsDirty"}, + #endif + #if defined(REAPERAPI_WANT_Master_GetPlayRate) || !defined(REAPERAPI_MINIMAL) + {(void**)&Master_GetPlayRate,"Master_GetPlayRate"}, + #endif + #if defined(REAPERAPI_WANT_Master_GetPlayRateAtTime) || !defined(REAPERAPI_MINIMAL) + {(void**)&Master_GetPlayRateAtTime,"Master_GetPlayRateAtTime"}, + #endif + #if defined(REAPERAPI_WANT_Master_GetTempo) || !defined(REAPERAPI_MINIMAL) + {(void**)&Master_GetTempo,"Master_GetTempo"}, + #endif + #if defined(REAPERAPI_WANT_Master_NormalizePlayRate) || !defined(REAPERAPI_MINIMAL) + {(void**)&Master_NormalizePlayRate,"Master_NormalizePlayRate"}, + #endif + #if defined(REAPERAPI_WANT_Master_NormalizeTempo) || !defined(REAPERAPI_MINIMAL) + {(void**)&Master_NormalizeTempo,"Master_NormalizeTempo"}, + #endif + #if defined(REAPERAPI_WANT_MB) || !defined(REAPERAPI_MINIMAL) + {(void**)&MB,"MB"}, + #endif + #if defined(REAPERAPI_WANT_MediaItemDescendsFromTrack) || !defined(REAPERAPI_MINIMAL) + {(void**)&MediaItemDescendsFromTrack,"MediaItemDescendsFromTrack"}, + #endif + #if defined(REAPERAPI_WANT_MIDI_CountEvts) || !defined(REAPERAPI_MINIMAL) + {(void**)&MIDI_CountEvts,"MIDI_CountEvts"}, + #endif + #if defined(REAPERAPI_WANT_MIDI_DeleteCC) || !defined(REAPERAPI_MINIMAL) + {(void**)&MIDI_DeleteCC,"MIDI_DeleteCC"}, + #endif + #if defined(REAPERAPI_WANT_MIDI_DeleteEvt) || !defined(REAPERAPI_MINIMAL) + {(void**)&MIDI_DeleteEvt,"MIDI_DeleteEvt"}, + #endif + #if defined(REAPERAPI_WANT_MIDI_DeleteNote) || !defined(REAPERAPI_MINIMAL) + {(void**)&MIDI_DeleteNote,"MIDI_DeleteNote"}, + #endif + #if defined(REAPERAPI_WANT_MIDI_DeleteTextSysexEvt) || !defined(REAPERAPI_MINIMAL) + {(void**)&MIDI_DeleteTextSysexEvt,"MIDI_DeleteTextSysexEvt"}, + #endif + #if defined(REAPERAPI_WANT_MIDI_DisableSort) || !defined(REAPERAPI_MINIMAL) + {(void**)&MIDI_DisableSort,"MIDI_DisableSort"}, + #endif + #if defined(REAPERAPI_WANT_MIDI_EnumSelCC) || !defined(REAPERAPI_MINIMAL) + {(void**)&MIDI_EnumSelCC,"MIDI_EnumSelCC"}, + #endif + #if defined(REAPERAPI_WANT_MIDI_EnumSelEvts) || !defined(REAPERAPI_MINIMAL) + {(void**)&MIDI_EnumSelEvts,"MIDI_EnumSelEvts"}, + #endif + #if defined(REAPERAPI_WANT_MIDI_EnumSelNotes) || !defined(REAPERAPI_MINIMAL) + {(void**)&MIDI_EnumSelNotes,"MIDI_EnumSelNotes"}, + #endif + #if defined(REAPERAPI_WANT_MIDI_EnumSelTextSysexEvts) || !defined(REAPERAPI_MINIMAL) + {(void**)&MIDI_EnumSelTextSysexEvts,"MIDI_EnumSelTextSysexEvts"}, + #endif + #if defined(REAPERAPI_WANT_MIDI_eventlist_Create) || !defined(REAPERAPI_MINIMAL) + {(void**)&MIDI_eventlist_Create,"MIDI_eventlist_Create"}, + #endif + #if defined(REAPERAPI_WANT_MIDI_eventlist_Destroy) || !defined(REAPERAPI_MINIMAL) + {(void**)&MIDI_eventlist_Destroy,"MIDI_eventlist_Destroy"}, + #endif + #if defined(REAPERAPI_WANT_MIDI_GetAllEvts) || !defined(REAPERAPI_MINIMAL) + {(void**)&MIDI_GetAllEvts,"MIDI_GetAllEvts"}, + #endif + #if defined(REAPERAPI_WANT_MIDI_GetCC) || !defined(REAPERAPI_MINIMAL) + {(void**)&MIDI_GetCC,"MIDI_GetCC"}, + #endif + #if defined(REAPERAPI_WANT_MIDI_GetCCShape) || !defined(REAPERAPI_MINIMAL) + {(void**)&MIDI_GetCCShape,"MIDI_GetCCShape"}, + #endif + #if defined(REAPERAPI_WANT_MIDI_GetEvt) || !defined(REAPERAPI_MINIMAL) + {(void**)&MIDI_GetEvt,"MIDI_GetEvt"}, + #endif + #if defined(REAPERAPI_WANT_MIDI_GetGrid) || !defined(REAPERAPI_MINIMAL) + {(void**)&MIDI_GetGrid,"MIDI_GetGrid"}, + #endif + #if defined(REAPERAPI_WANT_MIDI_GetHash) || !defined(REAPERAPI_MINIMAL) + {(void**)&MIDI_GetHash,"MIDI_GetHash"}, + #endif + #if defined(REAPERAPI_WANT_MIDI_GetNote) || !defined(REAPERAPI_MINIMAL) + {(void**)&MIDI_GetNote,"MIDI_GetNote"}, + #endif + #if defined(REAPERAPI_WANT_MIDI_GetPPQPos_EndOfMeasure) || !defined(REAPERAPI_MINIMAL) + {(void**)&MIDI_GetPPQPos_EndOfMeasure,"MIDI_GetPPQPos_EndOfMeasure"}, + #endif + #if defined(REAPERAPI_WANT_MIDI_GetPPQPos_StartOfMeasure) || !defined(REAPERAPI_MINIMAL) + {(void**)&MIDI_GetPPQPos_StartOfMeasure,"MIDI_GetPPQPos_StartOfMeasure"}, + #endif + #if defined(REAPERAPI_WANT_MIDI_GetPPQPosFromProjQN) || !defined(REAPERAPI_MINIMAL) + {(void**)&MIDI_GetPPQPosFromProjQN,"MIDI_GetPPQPosFromProjQN"}, + #endif + #if defined(REAPERAPI_WANT_MIDI_GetPPQPosFromProjTime) || !defined(REAPERAPI_MINIMAL) + {(void**)&MIDI_GetPPQPosFromProjTime,"MIDI_GetPPQPosFromProjTime"}, + #endif + #if defined(REAPERAPI_WANT_MIDI_GetProjQNFromPPQPos) || !defined(REAPERAPI_MINIMAL) + {(void**)&MIDI_GetProjQNFromPPQPos,"MIDI_GetProjQNFromPPQPos"}, + #endif + #if defined(REAPERAPI_WANT_MIDI_GetProjTimeFromPPQPos) || !defined(REAPERAPI_MINIMAL) + {(void**)&MIDI_GetProjTimeFromPPQPos,"MIDI_GetProjTimeFromPPQPos"}, + #endif + #if defined(REAPERAPI_WANT_MIDI_GetRecentInputEvent) || !defined(REAPERAPI_MINIMAL) + {(void**)&MIDI_GetRecentInputEvent,"MIDI_GetRecentInputEvent"}, + #endif + #if defined(REAPERAPI_WANT_MIDI_GetScale) || !defined(REAPERAPI_MINIMAL) + {(void**)&MIDI_GetScale,"MIDI_GetScale"}, + #endif + #if defined(REAPERAPI_WANT_MIDI_GetTextSysexEvt) || !defined(REAPERAPI_MINIMAL) + {(void**)&MIDI_GetTextSysexEvt,"MIDI_GetTextSysexEvt"}, + #endif + #if defined(REAPERAPI_WANT_MIDI_GetTrackHash) || !defined(REAPERAPI_MINIMAL) + {(void**)&MIDI_GetTrackHash,"MIDI_GetTrackHash"}, + #endif + #if defined(REAPERAPI_WANT_MIDI_InsertCC) || !defined(REAPERAPI_MINIMAL) + {(void**)&MIDI_InsertCC,"MIDI_InsertCC"}, + #endif + #if defined(REAPERAPI_WANT_MIDI_InsertEvt) || !defined(REAPERAPI_MINIMAL) + {(void**)&MIDI_InsertEvt,"MIDI_InsertEvt"}, + #endif + #if defined(REAPERAPI_WANT_MIDI_InsertNote) || !defined(REAPERAPI_MINIMAL) + {(void**)&MIDI_InsertNote,"MIDI_InsertNote"}, + #endif + #if defined(REAPERAPI_WANT_MIDI_InsertTextSysexEvt) || !defined(REAPERAPI_MINIMAL) + {(void**)&MIDI_InsertTextSysexEvt,"MIDI_InsertTextSysexEvt"}, + #endif + #if defined(REAPERAPI_WANT_midi_reinit) || !defined(REAPERAPI_MINIMAL) + {(void**)&midi_reinit,"midi_reinit"}, + #endif + #if defined(REAPERAPI_WANT_MIDI_SelectAll) || !defined(REAPERAPI_MINIMAL) + {(void**)&MIDI_SelectAll,"MIDI_SelectAll"}, + #endif + #if defined(REAPERAPI_WANT_MIDI_SetAllEvts) || !defined(REAPERAPI_MINIMAL) + {(void**)&MIDI_SetAllEvts,"MIDI_SetAllEvts"}, + #endif + #if defined(REAPERAPI_WANT_MIDI_SetCC) || !defined(REAPERAPI_MINIMAL) + {(void**)&MIDI_SetCC,"MIDI_SetCC"}, + #endif + #if defined(REAPERAPI_WANT_MIDI_SetCCShape) || !defined(REAPERAPI_MINIMAL) + {(void**)&MIDI_SetCCShape,"MIDI_SetCCShape"}, + #endif + #if defined(REAPERAPI_WANT_MIDI_SetEvt) || !defined(REAPERAPI_MINIMAL) + {(void**)&MIDI_SetEvt,"MIDI_SetEvt"}, + #endif + #if defined(REAPERAPI_WANT_MIDI_SetItemExtents) || !defined(REAPERAPI_MINIMAL) + {(void**)&MIDI_SetItemExtents,"MIDI_SetItemExtents"}, + #endif + #if defined(REAPERAPI_WANT_MIDI_SetNote) || !defined(REAPERAPI_MINIMAL) + {(void**)&MIDI_SetNote,"MIDI_SetNote"}, + #endif + #if defined(REAPERAPI_WANT_MIDI_SetTextSysexEvt) || !defined(REAPERAPI_MINIMAL) + {(void**)&MIDI_SetTextSysexEvt,"MIDI_SetTextSysexEvt"}, + #endif + #if defined(REAPERAPI_WANT_MIDI_Sort) || !defined(REAPERAPI_MINIMAL) + {(void**)&MIDI_Sort,"MIDI_Sort"}, + #endif + #if defined(REAPERAPI_WANT_MIDIEditor_EnumTakes) || !defined(REAPERAPI_MINIMAL) + {(void**)&MIDIEditor_EnumTakes,"MIDIEditor_EnumTakes"}, + #endif + #if defined(REAPERAPI_WANT_MIDIEditor_GetActive) || !defined(REAPERAPI_MINIMAL) + {(void**)&MIDIEditor_GetActive,"MIDIEditor_GetActive"}, + #endif + #if defined(REAPERAPI_WANT_MIDIEditor_GetMode) || !defined(REAPERAPI_MINIMAL) + {(void**)&MIDIEditor_GetMode,"MIDIEditor_GetMode"}, + #endif + #if defined(REAPERAPI_WANT_MIDIEditor_GetSetting_int) || !defined(REAPERAPI_MINIMAL) + {(void**)&MIDIEditor_GetSetting_int,"MIDIEditor_GetSetting_int"}, + #endif + #if defined(REAPERAPI_WANT_MIDIEditor_GetSetting_str) || !defined(REAPERAPI_MINIMAL) + {(void**)&MIDIEditor_GetSetting_str,"MIDIEditor_GetSetting_str"}, + #endif + #if defined(REAPERAPI_WANT_MIDIEditor_GetTake) || !defined(REAPERAPI_MINIMAL) + {(void**)&MIDIEditor_GetTake,"MIDIEditor_GetTake"}, + #endif + #if defined(REAPERAPI_WANT_MIDIEditor_LastFocused_OnCommand) || !defined(REAPERAPI_MINIMAL) + {(void**)&MIDIEditor_LastFocused_OnCommand,"MIDIEditor_LastFocused_OnCommand"}, + #endif + #if defined(REAPERAPI_WANT_MIDIEditor_OnCommand) || !defined(REAPERAPI_MINIMAL) + {(void**)&MIDIEditor_OnCommand,"MIDIEditor_OnCommand"}, + #endif + #if defined(REAPERAPI_WANT_MIDIEditor_SetSetting_int) || !defined(REAPERAPI_MINIMAL) + {(void**)&MIDIEditor_SetSetting_int,"MIDIEditor_SetSetting_int"}, + #endif + #if defined(REAPERAPI_WANT_mkpanstr) || !defined(REAPERAPI_MINIMAL) + {(void**)&mkpanstr,"mkpanstr"}, + #endif + #if defined(REAPERAPI_WANT_mkvolpanstr) || !defined(REAPERAPI_MINIMAL) + {(void**)&mkvolpanstr,"mkvolpanstr"}, + #endif + #if defined(REAPERAPI_WANT_mkvolstr) || !defined(REAPERAPI_MINIMAL) + {(void**)&mkvolstr,"mkvolstr"}, + #endif + #if defined(REAPERAPI_WANT_MoveEditCursor) || !defined(REAPERAPI_MINIMAL) + {(void**)&MoveEditCursor,"MoveEditCursor"}, + #endif + #if defined(REAPERAPI_WANT_MoveMediaItemToTrack) || !defined(REAPERAPI_MINIMAL) + {(void**)&MoveMediaItemToTrack,"MoveMediaItemToTrack"}, + #endif + #if defined(REAPERAPI_WANT_MuteAllTracks) || !defined(REAPERAPI_MINIMAL) + {(void**)&MuteAllTracks,"MuteAllTracks"}, + #endif + #if defined(REAPERAPI_WANT_my_getViewport) || !defined(REAPERAPI_MINIMAL) + {(void**)&my_getViewport,"my_getViewport"}, + #endif + #if defined(REAPERAPI_WANT_NamedCommandLookup) || !defined(REAPERAPI_MINIMAL) + {(void**)&NamedCommandLookup,"NamedCommandLookup"}, + #endif + #if defined(REAPERAPI_WANT_OnPauseButton) || !defined(REAPERAPI_MINIMAL) + {(void**)&OnPauseButton,"OnPauseButton"}, + #endif + #if defined(REAPERAPI_WANT_OnPauseButtonEx) || !defined(REAPERAPI_MINIMAL) + {(void**)&OnPauseButtonEx,"OnPauseButtonEx"}, + #endif + #if defined(REAPERAPI_WANT_OnPlayButton) || !defined(REAPERAPI_MINIMAL) + {(void**)&OnPlayButton,"OnPlayButton"}, + #endif + #if defined(REAPERAPI_WANT_OnPlayButtonEx) || !defined(REAPERAPI_MINIMAL) + {(void**)&OnPlayButtonEx,"OnPlayButtonEx"}, + #endif + #if defined(REAPERAPI_WANT_OnStopButton) || !defined(REAPERAPI_MINIMAL) + {(void**)&OnStopButton,"OnStopButton"}, + #endif + #if defined(REAPERAPI_WANT_OnStopButtonEx) || !defined(REAPERAPI_MINIMAL) + {(void**)&OnStopButtonEx,"OnStopButtonEx"}, + #endif + #if defined(REAPERAPI_WANT_OpenColorThemeFile) || !defined(REAPERAPI_MINIMAL) + {(void**)&OpenColorThemeFile,"OpenColorThemeFile"}, + #endif + #if defined(REAPERAPI_WANT_OpenMediaExplorer) || !defined(REAPERAPI_MINIMAL) + {(void**)&OpenMediaExplorer,"OpenMediaExplorer"}, + #endif + #if defined(REAPERAPI_WANT_OscLocalMessageToHost) || !defined(REAPERAPI_MINIMAL) + {(void**)&OscLocalMessageToHost,"OscLocalMessageToHost"}, + #endif + #if defined(REAPERAPI_WANT_parse_timestr) || !defined(REAPERAPI_MINIMAL) + {(void**)&parse_timestr,"parse_timestr"}, + #endif + #if defined(REAPERAPI_WANT_parse_timestr_len) || !defined(REAPERAPI_MINIMAL) + {(void**)&parse_timestr_len,"parse_timestr_len"}, + #endif + #if defined(REAPERAPI_WANT_parse_timestr_pos) || !defined(REAPERAPI_MINIMAL) + {(void**)&parse_timestr_pos,"parse_timestr_pos"}, + #endif + #if defined(REAPERAPI_WANT_parsepanstr) || !defined(REAPERAPI_MINIMAL) + {(void**)&parsepanstr,"parsepanstr"}, + #endif + #if defined(REAPERAPI_WANT_PCM_Sink_Create) || !defined(REAPERAPI_MINIMAL) + {(void**)&PCM_Sink_Create,"PCM_Sink_Create"}, + #endif + #if defined(REAPERAPI_WANT_PCM_Sink_CreateEx) || !defined(REAPERAPI_MINIMAL) + {(void**)&PCM_Sink_CreateEx,"PCM_Sink_CreateEx"}, + #endif + #if defined(REAPERAPI_WANT_PCM_Sink_CreateMIDIFile) || !defined(REAPERAPI_MINIMAL) + {(void**)&PCM_Sink_CreateMIDIFile,"PCM_Sink_CreateMIDIFile"}, + #endif + #if defined(REAPERAPI_WANT_PCM_Sink_CreateMIDIFileEx) || !defined(REAPERAPI_MINIMAL) + {(void**)&PCM_Sink_CreateMIDIFileEx,"PCM_Sink_CreateMIDIFileEx"}, + #endif + #if defined(REAPERAPI_WANT_PCM_Sink_Enum) || !defined(REAPERAPI_MINIMAL) + {(void**)&PCM_Sink_Enum,"PCM_Sink_Enum"}, + #endif + #if defined(REAPERAPI_WANT_PCM_Sink_GetExtension) || !defined(REAPERAPI_MINIMAL) + {(void**)&PCM_Sink_GetExtension,"PCM_Sink_GetExtension"}, + #endif + #if defined(REAPERAPI_WANT_PCM_Sink_ShowConfig) || !defined(REAPERAPI_MINIMAL) + {(void**)&PCM_Sink_ShowConfig,"PCM_Sink_ShowConfig"}, + #endif + #if defined(REAPERAPI_WANT_PCM_Source_BuildPeaks) || !defined(REAPERAPI_MINIMAL) + {(void**)&PCM_Source_BuildPeaks,"PCM_Source_BuildPeaks"}, + #endif + #if defined(REAPERAPI_WANT_PCM_Source_CreateFromFile) || !defined(REAPERAPI_MINIMAL) + {(void**)&PCM_Source_CreateFromFile,"PCM_Source_CreateFromFile"}, + #endif + #if defined(REAPERAPI_WANT_PCM_Source_CreateFromFileEx) || !defined(REAPERAPI_MINIMAL) + {(void**)&PCM_Source_CreateFromFileEx,"PCM_Source_CreateFromFileEx"}, + #endif + #if defined(REAPERAPI_WANT_PCM_Source_CreateFromSimple) || !defined(REAPERAPI_MINIMAL) + {(void**)&PCM_Source_CreateFromSimple,"PCM_Source_CreateFromSimple"}, + #endif + #if defined(REAPERAPI_WANT_PCM_Source_CreateFromType) || !defined(REAPERAPI_MINIMAL) + {(void**)&PCM_Source_CreateFromType,"PCM_Source_CreateFromType"}, + #endif + #if defined(REAPERAPI_WANT_PCM_Source_Destroy) || !defined(REAPERAPI_MINIMAL) + {(void**)&PCM_Source_Destroy,"PCM_Source_Destroy"}, + #endif + #if defined(REAPERAPI_WANT_PCM_Source_GetPeaks) || !defined(REAPERAPI_MINIMAL) + {(void**)&PCM_Source_GetPeaks,"PCM_Source_GetPeaks"}, + #endif + #if defined(REAPERAPI_WANT_PCM_Source_GetSectionInfo) || !defined(REAPERAPI_MINIMAL) + {(void**)&PCM_Source_GetSectionInfo,"PCM_Source_GetSectionInfo"}, + #endif + #if defined(REAPERAPI_WANT_PeakBuild_Create) || !defined(REAPERAPI_MINIMAL) + {(void**)&PeakBuild_Create,"PeakBuild_Create"}, + #endif + #if defined(REAPERAPI_WANT_PeakBuild_CreateEx) || !defined(REAPERAPI_MINIMAL) + {(void**)&PeakBuild_CreateEx,"PeakBuild_CreateEx"}, + #endif + #if defined(REAPERAPI_WANT_PeakGet_Create) || !defined(REAPERAPI_MINIMAL) + {(void**)&PeakGet_Create,"PeakGet_Create"}, + #endif + #if defined(REAPERAPI_WANT_PitchShiftSubModeMenu) || !defined(REAPERAPI_MINIMAL) + {(void**)&PitchShiftSubModeMenu,"PitchShiftSubModeMenu"}, + #endif + #if defined(REAPERAPI_WANT_PlayPreview) || !defined(REAPERAPI_MINIMAL) + {(void**)&PlayPreview,"PlayPreview"}, + #endif + #if defined(REAPERAPI_WANT_PlayPreviewEx) || !defined(REAPERAPI_MINIMAL) + {(void**)&PlayPreviewEx,"PlayPreviewEx"}, + #endif + #if defined(REAPERAPI_WANT_PlayTrackPreview) || !defined(REAPERAPI_MINIMAL) + {(void**)&PlayTrackPreview,"PlayTrackPreview"}, + #endif + #if defined(REAPERAPI_WANT_PlayTrackPreview2) || !defined(REAPERAPI_MINIMAL) + {(void**)&PlayTrackPreview2,"PlayTrackPreview2"}, + #endif + #if defined(REAPERAPI_WANT_PlayTrackPreview2Ex) || !defined(REAPERAPI_MINIMAL) + {(void**)&PlayTrackPreview2Ex,"PlayTrackPreview2Ex"}, + #endif + #if defined(REAPERAPI_WANT_plugin_getapi) || !defined(REAPERAPI_MINIMAL) + {(void**)&plugin_getapi,"plugin_getapi"}, + #endif + #if defined(REAPERAPI_WANT_plugin_getFilterList) || !defined(REAPERAPI_MINIMAL) + {(void**)&plugin_getFilterList,"plugin_getFilterList"}, + #endif + #if defined(REAPERAPI_WANT_plugin_getImportableProjectFilterList) || !defined(REAPERAPI_MINIMAL) + {(void**)&plugin_getImportableProjectFilterList,"plugin_getImportableProjectFilterList"}, + #endif + #if defined(REAPERAPI_WANT_plugin_register) || !defined(REAPERAPI_MINIMAL) + {(void**)&plugin_register,"plugin_register"}, + #endif + #if defined(REAPERAPI_WANT_PluginWantsAlwaysRunFx) || !defined(REAPERAPI_MINIMAL) + {(void**)&PluginWantsAlwaysRunFx,"PluginWantsAlwaysRunFx"}, + #endif + #if defined(REAPERAPI_WANT_PreventUIRefresh) || !defined(REAPERAPI_MINIMAL) + {(void**)&PreventUIRefresh,"PreventUIRefresh"}, + #endif + #if defined(REAPERAPI_WANT_projectconfig_var_addr) || !defined(REAPERAPI_MINIMAL) + {(void**)&projectconfig_var_addr,"projectconfig_var_addr"}, + #endif + #if defined(REAPERAPI_WANT_projectconfig_var_getoffs) || !defined(REAPERAPI_MINIMAL) + {(void**)&projectconfig_var_getoffs,"projectconfig_var_getoffs"}, + #endif + #if defined(REAPERAPI_WANT_PromptForAction) || !defined(REAPERAPI_MINIMAL) + {(void**)&PromptForAction,"PromptForAction"}, + #endif + #if defined(REAPERAPI_WANT_realloc_cmd_ptr) || !defined(REAPERAPI_MINIMAL) + {(void**)&realloc_cmd_ptr,"realloc_cmd_ptr"}, + #endif + #if defined(REAPERAPI_WANT_ReaperGetPitchShiftAPI) || !defined(REAPERAPI_MINIMAL) + {(void**)&ReaperGetPitchShiftAPI,"ReaperGetPitchShiftAPI"}, + #endif + #if defined(REAPERAPI_WANT_ReaScriptError) || !defined(REAPERAPI_MINIMAL) + {(void**)&ReaScriptError,"ReaScriptError"}, + #endif + #if defined(REAPERAPI_WANT_RecursiveCreateDirectory) || !defined(REAPERAPI_MINIMAL) + {(void**)&RecursiveCreateDirectory,"RecursiveCreateDirectory"}, + #endif + #if defined(REAPERAPI_WANT_reduce_open_files) || !defined(REAPERAPI_MINIMAL) + {(void**)&reduce_open_files,"reduce_open_files"}, + #endif + #if defined(REAPERAPI_WANT_RefreshToolbar) || !defined(REAPERAPI_MINIMAL) + {(void**)&RefreshToolbar,"RefreshToolbar"}, + #endif + #if defined(REAPERAPI_WANT_RefreshToolbar2) || !defined(REAPERAPI_MINIMAL) + {(void**)&RefreshToolbar2,"RefreshToolbar2"}, + #endif + #if defined(REAPERAPI_WANT_relative_fn) || !defined(REAPERAPI_MINIMAL) + {(void**)&relative_fn,"relative_fn"}, + #endif + #if defined(REAPERAPI_WANT_RemoveTrackSend) || !defined(REAPERAPI_MINIMAL) + {(void**)&RemoveTrackSend,"RemoveTrackSend"}, + #endif + #if defined(REAPERAPI_WANT_RenderFileSection) || !defined(REAPERAPI_MINIMAL) + {(void**)&RenderFileSection,"RenderFileSection"}, + #endif + #if defined(REAPERAPI_WANT_ReorderSelectedTracks) || !defined(REAPERAPI_MINIMAL) + {(void**)&ReorderSelectedTracks,"ReorderSelectedTracks"}, + #endif + #if defined(REAPERAPI_WANT_Resample_EnumModes) || !defined(REAPERAPI_MINIMAL) + {(void**)&Resample_EnumModes,"Resample_EnumModes"}, + #endif + #if defined(REAPERAPI_WANT_Resampler_Create) || !defined(REAPERAPI_MINIMAL) + {(void**)&Resampler_Create,"Resampler_Create"}, + #endif + #if defined(REAPERAPI_WANT_resolve_fn) || !defined(REAPERAPI_MINIMAL) + {(void**)&resolve_fn,"resolve_fn"}, + #endif + #if defined(REAPERAPI_WANT_resolve_fn2) || !defined(REAPERAPI_MINIMAL) + {(void**)&resolve_fn2,"resolve_fn2"}, + #endif + #if defined(REAPERAPI_WANT_ResolveRenderPattern) || !defined(REAPERAPI_MINIMAL) + {(void**)&ResolveRenderPattern,"ResolveRenderPattern"}, + #endif + #if defined(REAPERAPI_WANT_ReverseNamedCommandLookup) || !defined(REAPERAPI_MINIMAL) + {(void**)&ReverseNamedCommandLookup,"ReverseNamedCommandLookup"}, + #endif + #if defined(REAPERAPI_WANT_ScaleFromEnvelopeMode) || !defined(REAPERAPI_MINIMAL) + {(void**)&ScaleFromEnvelopeMode,"ScaleFromEnvelopeMode"}, + #endif + #if defined(REAPERAPI_WANT_ScaleToEnvelopeMode) || !defined(REAPERAPI_MINIMAL) + {(void**)&ScaleToEnvelopeMode,"ScaleToEnvelopeMode"}, + #endif + #if defined(REAPERAPI_WANT_screenset_register) || !defined(REAPERAPI_MINIMAL) + {(void**)&screenset_register,"screenset_register"}, + #endif + #if defined(REAPERAPI_WANT_screenset_registerNew) || !defined(REAPERAPI_MINIMAL) + {(void**)&screenset_registerNew,"screenset_registerNew"}, + #endif + #if defined(REAPERAPI_WANT_screenset_unregister) || !defined(REAPERAPI_MINIMAL) + {(void**)&screenset_unregister,"screenset_unregister"}, + #endif + #if defined(REAPERAPI_WANT_screenset_unregisterByParam) || !defined(REAPERAPI_MINIMAL) + {(void**)&screenset_unregisterByParam,"screenset_unregisterByParam"}, + #endif + #if defined(REAPERAPI_WANT_screenset_updateLastFocus) || !defined(REAPERAPI_MINIMAL) + {(void**)&screenset_updateLastFocus,"screenset_updateLastFocus"}, + #endif + #if defined(REAPERAPI_WANT_SectionFromUniqueID) || !defined(REAPERAPI_MINIMAL) + {(void**)&SectionFromUniqueID,"SectionFromUniqueID"}, + #endif + #if defined(REAPERAPI_WANT_SelectAllMediaItems) || !defined(REAPERAPI_MINIMAL) + {(void**)&SelectAllMediaItems,"SelectAllMediaItems"}, + #endif + #if defined(REAPERAPI_WANT_SelectProjectInstance) || !defined(REAPERAPI_MINIMAL) + {(void**)&SelectProjectInstance,"SelectProjectInstance"}, + #endif + #if defined(REAPERAPI_WANT_SendLocalOscMessage) || !defined(REAPERAPI_MINIMAL) + {(void**)&SendLocalOscMessage,"SendLocalOscMessage"}, + #endif + #if defined(REAPERAPI_WANT_SetActiveTake) || !defined(REAPERAPI_MINIMAL) + {(void**)&SetActiveTake,"SetActiveTake"}, + #endif + #if defined(REAPERAPI_WANT_SetAutomationMode) || !defined(REAPERAPI_MINIMAL) + {(void**)&SetAutomationMode,"SetAutomationMode"}, + #endif + #if defined(REAPERAPI_WANT_SetCurrentBPM) || !defined(REAPERAPI_MINIMAL) + {(void**)&SetCurrentBPM,"SetCurrentBPM"}, + #endif + #if defined(REAPERAPI_WANT_SetCursorContext) || !defined(REAPERAPI_MINIMAL) + {(void**)&SetCursorContext,"SetCursorContext"}, + #endif + #if defined(REAPERAPI_WANT_SetEditCurPos) || !defined(REAPERAPI_MINIMAL) + {(void**)&SetEditCurPos,"SetEditCurPos"}, + #endif + #if defined(REAPERAPI_WANT_SetEditCurPos2) || !defined(REAPERAPI_MINIMAL) + {(void**)&SetEditCurPos2,"SetEditCurPos2"}, + #endif + #if defined(REAPERAPI_WANT_SetEnvelopePoint) || !defined(REAPERAPI_MINIMAL) + {(void**)&SetEnvelopePoint,"SetEnvelopePoint"}, + #endif + #if defined(REAPERAPI_WANT_SetEnvelopePointEx) || !defined(REAPERAPI_MINIMAL) + {(void**)&SetEnvelopePointEx,"SetEnvelopePointEx"}, + #endif + #if defined(REAPERAPI_WANT_SetEnvelopeStateChunk) || !defined(REAPERAPI_MINIMAL) + {(void**)&SetEnvelopeStateChunk,"SetEnvelopeStateChunk"}, + #endif + #if defined(REAPERAPI_WANT_SetExtState) || !defined(REAPERAPI_MINIMAL) + {(void**)&SetExtState,"SetExtState"}, + #endif + #if defined(REAPERAPI_WANT_SetGlobalAutomationOverride) || !defined(REAPERAPI_MINIMAL) + {(void**)&SetGlobalAutomationOverride,"SetGlobalAutomationOverride"}, + #endif + #if defined(REAPERAPI_WANT_SetItemStateChunk) || !defined(REAPERAPI_MINIMAL) + {(void**)&SetItemStateChunk,"SetItemStateChunk"}, + #endif + #if defined(REAPERAPI_WANT_SetMasterTrackVisibility) || !defined(REAPERAPI_MINIMAL) + {(void**)&SetMasterTrackVisibility,"SetMasterTrackVisibility"}, + #endif + #if defined(REAPERAPI_WANT_SetMediaItemInfo_Value) || !defined(REAPERAPI_MINIMAL) + {(void**)&SetMediaItemInfo_Value,"SetMediaItemInfo_Value"}, + #endif + #if defined(REAPERAPI_WANT_SetMediaItemLength) || !defined(REAPERAPI_MINIMAL) + {(void**)&SetMediaItemLength,"SetMediaItemLength"}, + #endif + #if defined(REAPERAPI_WANT_SetMediaItemPosition) || !defined(REAPERAPI_MINIMAL) + {(void**)&SetMediaItemPosition,"SetMediaItemPosition"}, + #endif + #if defined(REAPERAPI_WANT_SetMediaItemSelected) || !defined(REAPERAPI_MINIMAL) + {(void**)&SetMediaItemSelected,"SetMediaItemSelected"}, + #endif + #if defined(REAPERAPI_WANT_SetMediaItemTake_Source) || !defined(REAPERAPI_MINIMAL) + {(void**)&SetMediaItemTake_Source,"SetMediaItemTake_Source"}, + #endif + #if defined(REAPERAPI_WANT_SetMediaItemTakeInfo_Value) || !defined(REAPERAPI_MINIMAL) + {(void**)&SetMediaItemTakeInfo_Value,"SetMediaItemTakeInfo_Value"}, + #endif + #if defined(REAPERAPI_WANT_SetMediaTrackInfo_Value) || !defined(REAPERAPI_MINIMAL) + {(void**)&SetMediaTrackInfo_Value,"SetMediaTrackInfo_Value"}, + #endif + #if defined(REAPERAPI_WANT_SetMIDIEditorGrid) || !defined(REAPERAPI_MINIMAL) + {(void**)&SetMIDIEditorGrid,"SetMIDIEditorGrid"}, + #endif + #if defined(REAPERAPI_WANT_SetMixerScroll) || !defined(REAPERAPI_MINIMAL) + {(void**)&SetMixerScroll,"SetMixerScroll"}, + #endif + #if defined(REAPERAPI_WANT_SetMouseModifier) || !defined(REAPERAPI_MINIMAL) + {(void**)&SetMouseModifier,"SetMouseModifier"}, + #endif + #if defined(REAPERAPI_WANT_SetOnlyTrackSelected) || !defined(REAPERAPI_MINIMAL) + {(void**)&SetOnlyTrackSelected,"SetOnlyTrackSelected"}, + #endif + #if defined(REAPERAPI_WANT_SetProjectGrid) || !defined(REAPERAPI_MINIMAL) + {(void**)&SetProjectGrid,"SetProjectGrid"}, + #endif + #if defined(REAPERAPI_WANT_SetProjectMarker) || !defined(REAPERAPI_MINIMAL) + {(void**)&SetProjectMarker,"SetProjectMarker"}, + #endif + #if defined(REAPERAPI_WANT_SetProjectMarker2) || !defined(REAPERAPI_MINIMAL) + {(void**)&SetProjectMarker2,"SetProjectMarker2"}, + #endif + #if defined(REAPERAPI_WANT_SetProjectMarker3) || !defined(REAPERAPI_MINIMAL) + {(void**)&SetProjectMarker3,"SetProjectMarker3"}, + #endif + #if defined(REAPERAPI_WANT_SetProjectMarker4) || !defined(REAPERAPI_MINIMAL) + {(void**)&SetProjectMarker4,"SetProjectMarker4"}, + #endif + #if defined(REAPERAPI_WANT_SetProjectMarkerByIndex) || !defined(REAPERAPI_MINIMAL) + {(void**)&SetProjectMarkerByIndex,"SetProjectMarkerByIndex"}, + #endif + #if defined(REAPERAPI_WANT_SetProjectMarkerByIndex2) || !defined(REAPERAPI_MINIMAL) + {(void**)&SetProjectMarkerByIndex2,"SetProjectMarkerByIndex2"}, + #endif + #if defined(REAPERAPI_WANT_SetProjExtState) || !defined(REAPERAPI_MINIMAL) + {(void**)&SetProjExtState,"SetProjExtState"}, + #endif + #if defined(REAPERAPI_WANT_SetRegionRenderMatrix) || !defined(REAPERAPI_MINIMAL) + {(void**)&SetRegionRenderMatrix,"SetRegionRenderMatrix"}, + #endif + #if defined(REAPERAPI_WANT_SetRenderLastError) || !defined(REAPERAPI_MINIMAL) + {(void**)&SetRenderLastError,"SetRenderLastError"}, + #endif + #if defined(REAPERAPI_WANT_SetTakeMarker) || !defined(REAPERAPI_MINIMAL) + {(void**)&SetTakeMarker,"SetTakeMarker"}, + #endif + #if defined(REAPERAPI_WANT_SetTakeStretchMarker) || !defined(REAPERAPI_MINIMAL) + {(void**)&SetTakeStretchMarker,"SetTakeStretchMarker"}, + #endif + #if defined(REAPERAPI_WANT_SetTakeStretchMarkerSlope) || !defined(REAPERAPI_MINIMAL) + {(void**)&SetTakeStretchMarkerSlope,"SetTakeStretchMarkerSlope"}, + #endif + #if defined(REAPERAPI_WANT_SetTempoTimeSigMarker) || !defined(REAPERAPI_MINIMAL) + {(void**)&SetTempoTimeSigMarker,"SetTempoTimeSigMarker"}, + #endif + #if defined(REAPERAPI_WANT_SetThemeColor) || !defined(REAPERAPI_MINIMAL) + {(void**)&SetThemeColor,"SetThemeColor"}, + #endif + #if defined(REAPERAPI_WANT_SetToggleCommandState) || !defined(REAPERAPI_MINIMAL) + {(void**)&SetToggleCommandState,"SetToggleCommandState"}, + #endif + #if defined(REAPERAPI_WANT_SetTrackAutomationMode) || !defined(REAPERAPI_MINIMAL) + {(void**)&SetTrackAutomationMode,"SetTrackAutomationMode"}, + #endif + #if defined(REAPERAPI_WANT_SetTrackColor) || !defined(REAPERAPI_MINIMAL) + {(void**)&SetTrackColor,"SetTrackColor"}, + #endif + #if defined(REAPERAPI_WANT_SetTrackMIDILyrics) || !defined(REAPERAPI_MINIMAL) + {(void**)&SetTrackMIDILyrics,"SetTrackMIDILyrics"}, + #endif + #if defined(REAPERAPI_WANT_SetTrackMIDINoteName) || !defined(REAPERAPI_MINIMAL) + {(void**)&SetTrackMIDINoteName,"SetTrackMIDINoteName"}, + #endif + #if defined(REAPERAPI_WANT_SetTrackMIDINoteNameEx) || !defined(REAPERAPI_MINIMAL) + {(void**)&SetTrackMIDINoteNameEx,"SetTrackMIDINoteNameEx"}, + #endif + #if defined(REAPERAPI_WANT_SetTrackSelected) || !defined(REAPERAPI_MINIMAL) + {(void**)&SetTrackSelected,"SetTrackSelected"}, + #endif + #if defined(REAPERAPI_WANT_SetTrackSendInfo_Value) || !defined(REAPERAPI_MINIMAL) + {(void**)&SetTrackSendInfo_Value,"SetTrackSendInfo_Value"}, + #endif + #if defined(REAPERAPI_WANT_SetTrackSendUIPan) || !defined(REAPERAPI_MINIMAL) + {(void**)&SetTrackSendUIPan,"SetTrackSendUIPan"}, + #endif + #if defined(REAPERAPI_WANT_SetTrackSendUIVol) || !defined(REAPERAPI_MINIMAL) + {(void**)&SetTrackSendUIVol,"SetTrackSendUIVol"}, + #endif + #if defined(REAPERAPI_WANT_SetTrackStateChunk) || !defined(REAPERAPI_MINIMAL) + {(void**)&SetTrackStateChunk,"SetTrackStateChunk"}, + #endif + #if defined(REAPERAPI_WANT_ShowActionList) || !defined(REAPERAPI_MINIMAL) + {(void**)&ShowActionList,"ShowActionList"}, + #endif + #if defined(REAPERAPI_WANT_ShowConsoleMsg) || !defined(REAPERAPI_MINIMAL) + {(void**)&ShowConsoleMsg,"ShowConsoleMsg"}, + #endif + #if defined(REAPERAPI_WANT_ShowMessageBox) || !defined(REAPERAPI_MINIMAL) + {(void**)&ShowMessageBox,"ShowMessageBox"}, + #endif + #if defined(REAPERAPI_WANT_ShowPopupMenu) || !defined(REAPERAPI_MINIMAL) + {(void**)&ShowPopupMenu,"ShowPopupMenu"}, + #endif + #if defined(REAPERAPI_WANT_SLIDER2DB) || !defined(REAPERAPI_MINIMAL) + {(void**)&SLIDER2DB,"SLIDER2DB"}, + #endif + #if defined(REAPERAPI_WANT_SnapToGrid) || !defined(REAPERAPI_MINIMAL) + {(void**)&SnapToGrid,"SnapToGrid"}, + #endif + #if defined(REAPERAPI_WANT_SoloAllTracks) || !defined(REAPERAPI_MINIMAL) + {(void**)&SoloAllTracks,"SoloAllTracks"}, + #endif + #if defined(REAPERAPI_WANT_Splash_GetWnd) || !defined(REAPERAPI_MINIMAL) + {(void**)&Splash_GetWnd,"Splash_GetWnd"}, + #endif + #if defined(REAPERAPI_WANT_SplitMediaItem) || !defined(REAPERAPI_MINIMAL) + {(void**)&SplitMediaItem,"SplitMediaItem"}, + #endif + #if defined(REAPERAPI_WANT_StopPreview) || !defined(REAPERAPI_MINIMAL) + {(void**)&StopPreview,"StopPreview"}, + #endif + #if defined(REAPERAPI_WANT_StopTrackPreview) || !defined(REAPERAPI_MINIMAL) + {(void**)&StopTrackPreview,"StopTrackPreview"}, + #endif + #if defined(REAPERAPI_WANT_StopTrackPreview2) || !defined(REAPERAPI_MINIMAL) + {(void**)&StopTrackPreview2,"StopTrackPreview2"}, + #endif + #if defined(REAPERAPI_WANT_stringToGuid) || !defined(REAPERAPI_MINIMAL) + {(void**)&stringToGuid,"stringToGuid"}, + #endif + #if defined(REAPERAPI_WANT_StuffMIDIMessage) || !defined(REAPERAPI_MINIMAL) + {(void**)&StuffMIDIMessage,"StuffMIDIMessage"}, + #endif + #if defined(REAPERAPI_WANT_TakeFX_AddByName) || !defined(REAPERAPI_MINIMAL) + {(void**)&TakeFX_AddByName,"TakeFX_AddByName"}, + #endif + #if defined(REAPERAPI_WANT_TakeFX_CopyToTake) || !defined(REAPERAPI_MINIMAL) + {(void**)&TakeFX_CopyToTake,"TakeFX_CopyToTake"}, + #endif + #if defined(REAPERAPI_WANT_TakeFX_CopyToTrack) || !defined(REAPERAPI_MINIMAL) + {(void**)&TakeFX_CopyToTrack,"TakeFX_CopyToTrack"}, + #endif + #if defined(REAPERAPI_WANT_TakeFX_Delete) || !defined(REAPERAPI_MINIMAL) + {(void**)&TakeFX_Delete,"TakeFX_Delete"}, + #endif + #if defined(REAPERAPI_WANT_TakeFX_EndParamEdit) || !defined(REAPERAPI_MINIMAL) + {(void**)&TakeFX_EndParamEdit,"TakeFX_EndParamEdit"}, + #endif + #if defined(REAPERAPI_WANT_TakeFX_FormatParamValue) || !defined(REAPERAPI_MINIMAL) + {(void**)&TakeFX_FormatParamValue,"TakeFX_FormatParamValue"}, + #endif + #if defined(REAPERAPI_WANT_TakeFX_FormatParamValueNormalized) || !defined(REAPERAPI_MINIMAL) + {(void**)&TakeFX_FormatParamValueNormalized,"TakeFX_FormatParamValueNormalized"}, + #endif + #if defined(REAPERAPI_WANT_TakeFX_GetChainVisible) || !defined(REAPERAPI_MINIMAL) + {(void**)&TakeFX_GetChainVisible,"TakeFX_GetChainVisible"}, + #endif + #if defined(REAPERAPI_WANT_TakeFX_GetCount) || !defined(REAPERAPI_MINIMAL) + {(void**)&TakeFX_GetCount,"TakeFX_GetCount"}, + #endif + #if defined(REAPERAPI_WANT_TakeFX_GetEnabled) || !defined(REAPERAPI_MINIMAL) + {(void**)&TakeFX_GetEnabled,"TakeFX_GetEnabled"}, + #endif + #if defined(REAPERAPI_WANT_TakeFX_GetEnvelope) || !defined(REAPERAPI_MINIMAL) + {(void**)&TakeFX_GetEnvelope,"TakeFX_GetEnvelope"}, + #endif + #if defined(REAPERAPI_WANT_TakeFX_GetFloatingWindow) || !defined(REAPERAPI_MINIMAL) + {(void**)&TakeFX_GetFloatingWindow,"TakeFX_GetFloatingWindow"}, + #endif + #if defined(REAPERAPI_WANT_TakeFX_GetFormattedParamValue) || !defined(REAPERAPI_MINIMAL) + {(void**)&TakeFX_GetFormattedParamValue,"TakeFX_GetFormattedParamValue"}, + #endif + #if defined(REAPERAPI_WANT_TakeFX_GetFXGUID) || !defined(REAPERAPI_MINIMAL) + {(void**)&TakeFX_GetFXGUID,"TakeFX_GetFXGUID"}, + #endif + #if defined(REAPERAPI_WANT_TakeFX_GetFXName) || !defined(REAPERAPI_MINIMAL) + {(void**)&TakeFX_GetFXName,"TakeFX_GetFXName"}, + #endif + #if defined(REAPERAPI_WANT_TakeFX_GetIOSize) || !defined(REAPERAPI_MINIMAL) + {(void**)&TakeFX_GetIOSize,"TakeFX_GetIOSize"}, + #endif + #if defined(REAPERAPI_WANT_TakeFX_GetNamedConfigParm) || !defined(REAPERAPI_MINIMAL) + {(void**)&TakeFX_GetNamedConfigParm,"TakeFX_GetNamedConfigParm"}, + #endif + #if defined(REAPERAPI_WANT_TakeFX_GetNumParams) || !defined(REAPERAPI_MINIMAL) + {(void**)&TakeFX_GetNumParams,"TakeFX_GetNumParams"}, + #endif + #if defined(REAPERAPI_WANT_TakeFX_GetOffline) || !defined(REAPERAPI_MINIMAL) + {(void**)&TakeFX_GetOffline,"TakeFX_GetOffline"}, + #endif + #if defined(REAPERAPI_WANT_TakeFX_GetOpen) || !defined(REAPERAPI_MINIMAL) + {(void**)&TakeFX_GetOpen,"TakeFX_GetOpen"}, + #endif + #if defined(REAPERAPI_WANT_TakeFX_GetParam) || !defined(REAPERAPI_MINIMAL) + {(void**)&TakeFX_GetParam,"TakeFX_GetParam"}, + #endif + #if defined(REAPERAPI_WANT_TakeFX_GetParameterStepSizes) || !defined(REAPERAPI_MINIMAL) + {(void**)&TakeFX_GetParameterStepSizes,"TakeFX_GetParameterStepSizes"}, + #endif + #if defined(REAPERAPI_WANT_TakeFX_GetParamEx) || !defined(REAPERAPI_MINIMAL) + {(void**)&TakeFX_GetParamEx,"TakeFX_GetParamEx"}, + #endif + #if defined(REAPERAPI_WANT_TakeFX_GetParamFromIdent) || !defined(REAPERAPI_MINIMAL) + {(void**)&TakeFX_GetParamFromIdent,"TakeFX_GetParamFromIdent"}, + #endif + #if defined(REAPERAPI_WANT_TakeFX_GetParamIdent) || !defined(REAPERAPI_MINIMAL) + {(void**)&TakeFX_GetParamIdent,"TakeFX_GetParamIdent"}, + #endif + #if defined(REAPERAPI_WANT_TakeFX_GetParamName) || !defined(REAPERAPI_MINIMAL) + {(void**)&TakeFX_GetParamName,"TakeFX_GetParamName"}, + #endif + #if defined(REAPERAPI_WANT_TakeFX_GetParamNormalized) || !defined(REAPERAPI_MINIMAL) + {(void**)&TakeFX_GetParamNormalized,"TakeFX_GetParamNormalized"}, + #endif + #if defined(REAPERAPI_WANT_TakeFX_GetPinMappings) || !defined(REAPERAPI_MINIMAL) + {(void**)&TakeFX_GetPinMappings,"TakeFX_GetPinMappings"}, + #endif + #if defined(REAPERAPI_WANT_TakeFX_GetPreset) || !defined(REAPERAPI_MINIMAL) + {(void**)&TakeFX_GetPreset,"TakeFX_GetPreset"}, + #endif + #if defined(REAPERAPI_WANT_TakeFX_GetPresetIndex) || !defined(REAPERAPI_MINIMAL) + {(void**)&TakeFX_GetPresetIndex,"TakeFX_GetPresetIndex"}, + #endif + #if defined(REAPERAPI_WANT_TakeFX_GetUserPresetFilename) || !defined(REAPERAPI_MINIMAL) + {(void**)&TakeFX_GetUserPresetFilename,"TakeFX_GetUserPresetFilename"}, + #endif + #if defined(REAPERAPI_WANT_TakeFX_NavigatePresets) || !defined(REAPERAPI_MINIMAL) + {(void**)&TakeFX_NavigatePresets,"TakeFX_NavigatePresets"}, + #endif + #if defined(REAPERAPI_WANT_TakeFX_SetEnabled) || !defined(REAPERAPI_MINIMAL) + {(void**)&TakeFX_SetEnabled,"TakeFX_SetEnabled"}, + #endif + #if defined(REAPERAPI_WANT_TakeFX_SetNamedConfigParm) || !defined(REAPERAPI_MINIMAL) + {(void**)&TakeFX_SetNamedConfigParm,"TakeFX_SetNamedConfigParm"}, + #endif + #if defined(REAPERAPI_WANT_TakeFX_SetOffline) || !defined(REAPERAPI_MINIMAL) + {(void**)&TakeFX_SetOffline,"TakeFX_SetOffline"}, + #endif + #if defined(REAPERAPI_WANT_TakeFX_SetOpen) || !defined(REAPERAPI_MINIMAL) + {(void**)&TakeFX_SetOpen,"TakeFX_SetOpen"}, + #endif + #if defined(REAPERAPI_WANT_TakeFX_SetParam) || !defined(REAPERAPI_MINIMAL) + {(void**)&TakeFX_SetParam,"TakeFX_SetParam"}, + #endif + #if defined(REAPERAPI_WANT_TakeFX_SetParamNormalized) || !defined(REAPERAPI_MINIMAL) + {(void**)&TakeFX_SetParamNormalized,"TakeFX_SetParamNormalized"}, + #endif + #if defined(REAPERAPI_WANT_TakeFX_SetPinMappings) || !defined(REAPERAPI_MINIMAL) + {(void**)&TakeFX_SetPinMappings,"TakeFX_SetPinMappings"}, + #endif + #if defined(REAPERAPI_WANT_TakeFX_SetPreset) || !defined(REAPERAPI_MINIMAL) + {(void**)&TakeFX_SetPreset,"TakeFX_SetPreset"}, + #endif + #if defined(REAPERAPI_WANT_TakeFX_SetPresetByIndex) || !defined(REAPERAPI_MINIMAL) + {(void**)&TakeFX_SetPresetByIndex,"TakeFX_SetPresetByIndex"}, + #endif + #if defined(REAPERAPI_WANT_TakeFX_Show) || !defined(REAPERAPI_MINIMAL) + {(void**)&TakeFX_Show,"TakeFX_Show"}, + #endif + #if defined(REAPERAPI_WANT_TakeIsMIDI) || !defined(REAPERAPI_MINIMAL) + {(void**)&TakeIsMIDI,"TakeIsMIDI"}, + #endif + #if defined(REAPERAPI_WANT_ThemeLayout_GetLayout) || !defined(REAPERAPI_MINIMAL) + {(void**)&ThemeLayout_GetLayout,"ThemeLayout_GetLayout"}, + #endif + #if defined(REAPERAPI_WANT_ThemeLayout_GetParameter) || !defined(REAPERAPI_MINIMAL) + {(void**)&ThemeLayout_GetParameter,"ThemeLayout_GetParameter"}, + #endif + #if defined(REAPERAPI_WANT_ThemeLayout_RefreshAll) || !defined(REAPERAPI_MINIMAL) + {(void**)&ThemeLayout_RefreshAll,"ThemeLayout_RefreshAll"}, + #endif + #if defined(REAPERAPI_WANT_ThemeLayout_SetLayout) || !defined(REAPERAPI_MINIMAL) + {(void**)&ThemeLayout_SetLayout,"ThemeLayout_SetLayout"}, + #endif + #if defined(REAPERAPI_WANT_ThemeLayout_SetParameter) || !defined(REAPERAPI_MINIMAL) + {(void**)&ThemeLayout_SetParameter,"ThemeLayout_SetParameter"}, + #endif + #if defined(REAPERAPI_WANT_time_precise) || !defined(REAPERAPI_MINIMAL) + {(void**)&time_precise,"time_precise"}, + #endif + #if defined(REAPERAPI_WANT_TimeMap2_beatsToTime) || !defined(REAPERAPI_MINIMAL) + {(void**)&TimeMap2_beatsToTime,"TimeMap2_beatsToTime"}, + #endif + #if defined(REAPERAPI_WANT_TimeMap2_GetDividedBpmAtTime) || !defined(REAPERAPI_MINIMAL) + {(void**)&TimeMap2_GetDividedBpmAtTime,"TimeMap2_GetDividedBpmAtTime"}, + #endif + #if defined(REAPERAPI_WANT_TimeMap2_GetNextChangeTime) || !defined(REAPERAPI_MINIMAL) + {(void**)&TimeMap2_GetNextChangeTime,"TimeMap2_GetNextChangeTime"}, + #endif + #if defined(REAPERAPI_WANT_TimeMap2_QNToTime) || !defined(REAPERAPI_MINIMAL) + {(void**)&TimeMap2_QNToTime,"TimeMap2_QNToTime"}, + #endif + #if defined(REAPERAPI_WANT_TimeMap2_timeToBeats) || !defined(REAPERAPI_MINIMAL) + {(void**)&TimeMap2_timeToBeats,"TimeMap2_timeToBeats"}, + #endif + #if defined(REAPERAPI_WANT_TimeMap2_timeToQN) || !defined(REAPERAPI_MINIMAL) + {(void**)&TimeMap2_timeToQN,"TimeMap2_timeToQN"}, + #endif + #if defined(REAPERAPI_WANT_TimeMap_curFrameRate) || !defined(REAPERAPI_MINIMAL) + {(void**)&TimeMap_curFrameRate,"TimeMap_curFrameRate"}, + #endif + #if defined(REAPERAPI_WANT_TimeMap_GetDividedBpmAtTime) || !defined(REAPERAPI_MINIMAL) + {(void**)&TimeMap_GetDividedBpmAtTime,"TimeMap_GetDividedBpmAtTime"}, + #endif + #if defined(REAPERAPI_WANT_TimeMap_GetMeasureInfo) || !defined(REAPERAPI_MINIMAL) + {(void**)&TimeMap_GetMeasureInfo,"TimeMap_GetMeasureInfo"}, + #endif + #if defined(REAPERAPI_WANT_TimeMap_GetMetronomePattern) || !defined(REAPERAPI_MINIMAL) + {(void**)&TimeMap_GetMetronomePattern,"TimeMap_GetMetronomePattern"}, + #endif + #if defined(REAPERAPI_WANT_TimeMap_GetTimeSigAtTime) || !defined(REAPERAPI_MINIMAL) + {(void**)&TimeMap_GetTimeSigAtTime,"TimeMap_GetTimeSigAtTime"}, + #endif + #if defined(REAPERAPI_WANT_TimeMap_QNToMeasures) || !defined(REAPERAPI_MINIMAL) + {(void**)&TimeMap_QNToMeasures,"TimeMap_QNToMeasures"}, + #endif + #if defined(REAPERAPI_WANT_TimeMap_QNToTime) || !defined(REAPERAPI_MINIMAL) + {(void**)&TimeMap_QNToTime,"TimeMap_QNToTime"}, + #endif + #if defined(REAPERAPI_WANT_TimeMap_QNToTime_abs) || !defined(REAPERAPI_MINIMAL) + {(void**)&TimeMap_QNToTime_abs,"TimeMap_QNToTime_abs"}, + #endif + #if defined(REAPERAPI_WANT_TimeMap_timeToQN) || !defined(REAPERAPI_MINIMAL) + {(void**)&TimeMap_timeToQN,"TimeMap_timeToQN"}, + #endif + #if defined(REAPERAPI_WANT_TimeMap_timeToQN_abs) || !defined(REAPERAPI_MINIMAL) + {(void**)&TimeMap_timeToQN_abs,"TimeMap_timeToQN_abs"}, + #endif + #if defined(REAPERAPI_WANT_ToggleTrackSendUIMute) || !defined(REAPERAPI_MINIMAL) + {(void**)&ToggleTrackSendUIMute,"ToggleTrackSendUIMute"}, + #endif + #if defined(REAPERAPI_WANT_Track_GetPeakHoldDB) || !defined(REAPERAPI_MINIMAL) + {(void**)&Track_GetPeakHoldDB,"Track_GetPeakHoldDB"}, + #endif + #if defined(REAPERAPI_WANT_Track_GetPeakInfo) || !defined(REAPERAPI_MINIMAL) + {(void**)&Track_GetPeakInfo,"Track_GetPeakInfo"}, + #endif + #if defined(REAPERAPI_WANT_TrackCtl_SetToolTip) || !defined(REAPERAPI_MINIMAL) + {(void**)&TrackCtl_SetToolTip,"TrackCtl_SetToolTip"}, + #endif + #if defined(REAPERAPI_WANT_TrackFX_AddByName) || !defined(REAPERAPI_MINIMAL) + {(void**)&TrackFX_AddByName,"TrackFX_AddByName"}, + #endif + #if defined(REAPERAPI_WANT_TrackFX_CopyToTake) || !defined(REAPERAPI_MINIMAL) + {(void**)&TrackFX_CopyToTake,"TrackFX_CopyToTake"}, + #endif + #if defined(REAPERAPI_WANT_TrackFX_CopyToTrack) || !defined(REAPERAPI_MINIMAL) + {(void**)&TrackFX_CopyToTrack,"TrackFX_CopyToTrack"}, + #endif + #if defined(REAPERAPI_WANT_TrackFX_Delete) || !defined(REAPERAPI_MINIMAL) + {(void**)&TrackFX_Delete,"TrackFX_Delete"}, + #endif + #if defined(REAPERAPI_WANT_TrackFX_EndParamEdit) || !defined(REAPERAPI_MINIMAL) + {(void**)&TrackFX_EndParamEdit,"TrackFX_EndParamEdit"}, + #endif + #if defined(REAPERAPI_WANT_TrackFX_FormatParamValue) || !defined(REAPERAPI_MINIMAL) + {(void**)&TrackFX_FormatParamValue,"TrackFX_FormatParamValue"}, + #endif + #if defined(REAPERAPI_WANT_TrackFX_FormatParamValueNormalized) || !defined(REAPERAPI_MINIMAL) + {(void**)&TrackFX_FormatParamValueNormalized,"TrackFX_FormatParamValueNormalized"}, + #endif + #if defined(REAPERAPI_WANT_TrackFX_GetByName) || !defined(REAPERAPI_MINIMAL) + {(void**)&TrackFX_GetByName,"TrackFX_GetByName"}, + #endif + #if defined(REAPERAPI_WANT_TrackFX_GetChainVisible) || !defined(REAPERAPI_MINIMAL) + {(void**)&TrackFX_GetChainVisible,"TrackFX_GetChainVisible"}, + #endif + #if defined(REAPERAPI_WANT_TrackFX_GetCount) || !defined(REAPERAPI_MINIMAL) + {(void**)&TrackFX_GetCount,"TrackFX_GetCount"}, + #endif + #if defined(REAPERAPI_WANT_TrackFX_GetEnabled) || !defined(REAPERAPI_MINIMAL) + {(void**)&TrackFX_GetEnabled,"TrackFX_GetEnabled"}, + #endif + #if defined(REAPERAPI_WANT_TrackFX_GetEQ) || !defined(REAPERAPI_MINIMAL) + {(void**)&TrackFX_GetEQ,"TrackFX_GetEQ"}, + #endif + #if defined(REAPERAPI_WANT_TrackFX_GetEQBandEnabled) || !defined(REAPERAPI_MINIMAL) + {(void**)&TrackFX_GetEQBandEnabled,"TrackFX_GetEQBandEnabled"}, + #endif + #if defined(REAPERAPI_WANT_TrackFX_GetEQParam) || !defined(REAPERAPI_MINIMAL) + {(void**)&TrackFX_GetEQParam,"TrackFX_GetEQParam"}, + #endif + #if defined(REAPERAPI_WANT_TrackFX_GetFloatingWindow) || !defined(REAPERAPI_MINIMAL) + {(void**)&TrackFX_GetFloatingWindow,"TrackFX_GetFloatingWindow"}, + #endif + #if defined(REAPERAPI_WANT_TrackFX_GetFormattedParamValue) || !defined(REAPERAPI_MINIMAL) + {(void**)&TrackFX_GetFormattedParamValue,"TrackFX_GetFormattedParamValue"}, + #endif + #if defined(REAPERAPI_WANT_TrackFX_GetFXGUID) || !defined(REAPERAPI_MINIMAL) + {(void**)&TrackFX_GetFXGUID,"TrackFX_GetFXGUID"}, + #endif + #if defined(REAPERAPI_WANT_TrackFX_GetFXName) || !defined(REAPERAPI_MINIMAL) + {(void**)&TrackFX_GetFXName,"TrackFX_GetFXName"}, + #endif + #if defined(REAPERAPI_WANT_TrackFX_GetInstrument) || !defined(REAPERAPI_MINIMAL) + {(void**)&TrackFX_GetInstrument,"TrackFX_GetInstrument"}, + #endif + #if defined(REAPERAPI_WANT_TrackFX_GetIOSize) || !defined(REAPERAPI_MINIMAL) + {(void**)&TrackFX_GetIOSize,"TrackFX_GetIOSize"}, + #endif + #if defined(REAPERAPI_WANT_TrackFX_GetNamedConfigParm) || !defined(REAPERAPI_MINIMAL) + {(void**)&TrackFX_GetNamedConfigParm,"TrackFX_GetNamedConfigParm"}, + #endif + #if defined(REAPERAPI_WANT_TrackFX_GetNumParams) || !defined(REAPERAPI_MINIMAL) + {(void**)&TrackFX_GetNumParams,"TrackFX_GetNumParams"}, + #endif + #if defined(REAPERAPI_WANT_TrackFX_GetOffline) || !defined(REAPERAPI_MINIMAL) + {(void**)&TrackFX_GetOffline,"TrackFX_GetOffline"}, + #endif + #if defined(REAPERAPI_WANT_TrackFX_GetOpen) || !defined(REAPERAPI_MINIMAL) + {(void**)&TrackFX_GetOpen,"TrackFX_GetOpen"}, + #endif + #if defined(REAPERAPI_WANT_TrackFX_GetParam) || !defined(REAPERAPI_MINIMAL) + {(void**)&TrackFX_GetParam,"TrackFX_GetParam"}, + #endif + #if defined(REAPERAPI_WANT_TrackFX_GetParameterStepSizes) || !defined(REAPERAPI_MINIMAL) + {(void**)&TrackFX_GetParameterStepSizes,"TrackFX_GetParameterStepSizes"}, + #endif + #if defined(REAPERAPI_WANT_TrackFX_GetParamEx) || !defined(REAPERAPI_MINIMAL) + {(void**)&TrackFX_GetParamEx,"TrackFX_GetParamEx"}, + #endif + #if defined(REAPERAPI_WANT_TrackFX_GetParamFromIdent) || !defined(REAPERAPI_MINIMAL) + {(void**)&TrackFX_GetParamFromIdent,"TrackFX_GetParamFromIdent"}, + #endif + #if defined(REAPERAPI_WANT_TrackFX_GetParamIdent) || !defined(REAPERAPI_MINIMAL) + {(void**)&TrackFX_GetParamIdent,"TrackFX_GetParamIdent"}, + #endif + #if defined(REAPERAPI_WANT_TrackFX_GetParamName) || !defined(REAPERAPI_MINIMAL) + {(void**)&TrackFX_GetParamName,"TrackFX_GetParamName"}, + #endif + #if defined(REAPERAPI_WANT_TrackFX_GetParamNormalized) || !defined(REAPERAPI_MINIMAL) + {(void**)&TrackFX_GetParamNormalized,"TrackFX_GetParamNormalized"}, + #endif + #if defined(REAPERAPI_WANT_TrackFX_GetPinMappings) || !defined(REAPERAPI_MINIMAL) + {(void**)&TrackFX_GetPinMappings,"TrackFX_GetPinMappings"}, + #endif + #if defined(REAPERAPI_WANT_TrackFX_GetPreset) || !defined(REAPERAPI_MINIMAL) + {(void**)&TrackFX_GetPreset,"TrackFX_GetPreset"}, + #endif + #if defined(REAPERAPI_WANT_TrackFX_GetPresetIndex) || !defined(REAPERAPI_MINIMAL) + {(void**)&TrackFX_GetPresetIndex,"TrackFX_GetPresetIndex"}, + #endif + #if defined(REAPERAPI_WANT_TrackFX_GetRecChainVisible) || !defined(REAPERAPI_MINIMAL) + {(void**)&TrackFX_GetRecChainVisible,"TrackFX_GetRecChainVisible"}, + #endif + #if defined(REAPERAPI_WANT_TrackFX_GetRecCount) || !defined(REAPERAPI_MINIMAL) + {(void**)&TrackFX_GetRecCount,"TrackFX_GetRecCount"}, + #endif + #if defined(REAPERAPI_WANT_TrackFX_GetUserPresetFilename) || !defined(REAPERAPI_MINIMAL) + {(void**)&TrackFX_GetUserPresetFilename,"TrackFX_GetUserPresetFilename"}, + #endif + #if defined(REAPERAPI_WANT_TrackFX_NavigatePresets) || !defined(REAPERAPI_MINIMAL) + {(void**)&TrackFX_NavigatePresets,"TrackFX_NavigatePresets"}, + #endif + #if defined(REAPERAPI_WANT_TrackFX_SetEnabled) || !defined(REAPERAPI_MINIMAL) + {(void**)&TrackFX_SetEnabled,"TrackFX_SetEnabled"}, + #endif + #if defined(REAPERAPI_WANT_TrackFX_SetEQBandEnabled) || !defined(REAPERAPI_MINIMAL) + {(void**)&TrackFX_SetEQBandEnabled,"TrackFX_SetEQBandEnabled"}, + #endif + #if defined(REAPERAPI_WANT_TrackFX_SetEQParam) || !defined(REAPERAPI_MINIMAL) + {(void**)&TrackFX_SetEQParam,"TrackFX_SetEQParam"}, + #endif + #if defined(REAPERAPI_WANT_TrackFX_SetNamedConfigParm) || !defined(REAPERAPI_MINIMAL) + {(void**)&TrackFX_SetNamedConfigParm,"TrackFX_SetNamedConfigParm"}, + #endif + #if defined(REAPERAPI_WANT_TrackFX_SetOffline) || !defined(REAPERAPI_MINIMAL) + {(void**)&TrackFX_SetOffline,"TrackFX_SetOffline"}, + #endif + #if defined(REAPERAPI_WANT_TrackFX_SetOpen) || !defined(REAPERAPI_MINIMAL) + {(void**)&TrackFX_SetOpen,"TrackFX_SetOpen"}, + #endif + #if defined(REAPERAPI_WANT_TrackFX_SetParam) || !defined(REAPERAPI_MINIMAL) + {(void**)&TrackFX_SetParam,"TrackFX_SetParam"}, + #endif + #if defined(REAPERAPI_WANT_TrackFX_SetParamNormalized) || !defined(REAPERAPI_MINIMAL) + {(void**)&TrackFX_SetParamNormalized,"TrackFX_SetParamNormalized"}, + #endif + #if defined(REAPERAPI_WANT_TrackFX_SetPinMappings) || !defined(REAPERAPI_MINIMAL) + {(void**)&TrackFX_SetPinMappings,"TrackFX_SetPinMappings"}, + #endif + #if defined(REAPERAPI_WANT_TrackFX_SetPreset) || !defined(REAPERAPI_MINIMAL) + {(void**)&TrackFX_SetPreset,"TrackFX_SetPreset"}, + #endif + #if defined(REAPERAPI_WANT_TrackFX_SetPresetByIndex) || !defined(REAPERAPI_MINIMAL) + {(void**)&TrackFX_SetPresetByIndex,"TrackFX_SetPresetByIndex"}, + #endif + #if defined(REAPERAPI_WANT_TrackFX_Show) || !defined(REAPERAPI_MINIMAL) + {(void**)&TrackFX_Show,"TrackFX_Show"}, + #endif + #if defined(REAPERAPI_WANT_TrackList_AdjustWindows) || !defined(REAPERAPI_MINIMAL) + {(void**)&TrackList_AdjustWindows,"TrackList_AdjustWindows"}, + #endif + #if defined(REAPERAPI_WANT_TrackList_UpdateAllExternalSurfaces) || !defined(REAPERAPI_MINIMAL) + {(void**)&TrackList_UpdateAllExternalSurfaces,"TrackList_UpdateAllExternalSurfaces"}, + #endif + #if defined(REAPERAPI_WANT_Undo_BeginBlock) || !defined(REAPERAPI_MINIMAL) + {(void**)&Undo_BeginBlock,"Undo_BeginBlock"}, + #endif + #if defined(REAPERAPI_WANT_Undo_BeginBlock2) || !defined(REAPERAPI_MINIMAL) + {(void**)&Undo_BeginBlock2,"Undo_BeginBlock2"}, + #endif + #if defined(REAPERAPI_WANT_Undo_CanRedo2) || !defined(REAPERAPI_MINIMAL) + {(void**)&Undo_CanRedo2,"Undo_CanRedo2"}, + #endif + #if defined(REAPERAPI_WANT_Undo_CanUndo2) || !defined(REAPERAPI_MINIMAL) + {(void**)&Undo_CanUndo2,"Undo_CanUndo2"}, + #endif + #if defined(REAPERAPI_WANT_Undo_DoRedo2) || !defined(REAPERAPI_MINIMAL) + {(void**)&Undo_DoRedo2,"Undo_DoRedo2"}, + #endif + #if defined(REAPERAPI_WANT_Undo_DoUndo2) || !defined(REAPERAPI_MINIMAL) + {(void**)&Undo_DoUndo2,"Undo_DoUndo2"}, + #endif + #if defined(REAPERAPI_WANT_Undo_EndBlock) || !defined(REAPERAPI_MINIMAL) + {(void**)&Undo_EndBlock,"Undo_EndBlock"}, + #endif + #if defined(REAPERAPI_WANT_Undo_EndBlock2) || !defined(REAPERAPI_MINIMAL) + {(void**)&Undo_EndBlock2,"Undo_EndBlock2"}, + #endif + #if defined(REAPERAPI_WANT_Undo_OnStateChange) || !defined(REAPERAPI_MINIMAL) + {(void**)&Undo_OnStateChange,"Undo_OnStateChange"}, + #endif + #if defined(REAPERAPI_WANT_Undo_OnStateChange2) || !defined(REAPERAPI_MINIMAL) + {(void**)&Undo_OnStateChange2,"Undo_OnStateChange2"}, + #endif + #if defined(REAPERAPI_WANT_Undo_OnStateChange_Item) || !defined(REAPERAPI_MINIMAL) + {(void**)&Undo_OnStateChange_Item,"Undo_OnStateChange_Item"}, + #endif + #if defined(REAPERAPI_WANT_Undo_OnStateChangeEx) || !defined(REAPERAPI_MINIMAL) + {(void**)&Undo_OnStateChangeEx,"Undo_OnStateChangeEx"}, + #endif + #if defined(REAPERAPI_WANT_Undo_OnStateChangeEx2) || !defined(REAPERAPI_MINIMAL) + {(void**)&Undo_OnStateChangeEx2,"Undo_OnStateChangeEx2"}, + #endif + #if defined(REAPERAPI_WANT_update_disk_counters) || !defined(REAPERAPI_MINIMAL) + {(void**)&update_disk_counters,"update_disk_counters"}, + #endif + #if defined(REAPERAPI_WANT_UpdateArrange) || !defined(REAPERAPI_MINIMAL) + {(void**)&UpdateArrange,"UpdateArrange"}, + #endif + #if defined(REAPERAPI_WANT_UpdateItemInProject) || !defined(REAPERAPI_MINIMAL) + {(void**)&UpdateItemInProject,"UpdateItemInProject"}, + #endif + #if defined(REAPERAPI_WANT_UpdateTimeline) || !defined(REAPERAPI_MINIMAL) + {(void**)&UpdateTimeline,"UpdateTimeline"}, + #endif + #if defined(REAPERAPI_WANT_ValidatePtr) || !defined(REAPERAPI_MINIMAL) + {(void**)&ValidatePtr,"ValidatePtr"}, + #endif + #if defined(REAPERAPI_WANT_ValidatePtr2) || !defined(REAPERAPI_MINIMAL) + {(void**)&ValidatePtr2,"ValidatePtr2"}, + #endif + #if defined(REAPERAPI_WANT_ViewPrefs) || !defined(REAPERAPI_MINIMAL) + {(void**)&ViewPrefs,"ViewPrefs"}, + #endif + #if defined(REAPERAPI_WANT_WDL_VirtualWnd_ScaledBlitBG) || !defined(REAPERAPI_MINIMAL) + {(void**)&WDL_VirtualWnd_ScaledBlitBG,"WDL_VirtualWnd_ScaledBlitBG"}, + #endif + {NULL, NULL} + }; + int i,failcnt=0; + for (i=0;table[i].dest; i++) + failcnt += !(*table[i].dest = getAPI(table[i].name)); + return failcnt; + } +#else//REAPERAPI_IMPLEMENT + int REAPERAPI_LoadAPI(void *(*getAPI)(const char *)); +#endif +#endif // _REAPER_PLUGIN_FUNCTIONS_H_ + diff --git a/3rd/trompeloeil b/3rd/trompeloeil @@ -0,0 +1 @@ +Subproject commit 682a7278fba232e0101b4e224d4ce9c2c1ae697e diff --git a/CMakeLists.txt b/CMakeLists.txt @@ -0,0 +1,49 @@ +cmake_minimum_required(VERSION 3.22.0) + +project(WwiseTransfer_ALL VERSION 1.0.0) + +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(CMAKE_CXX_EXTENSIONS OFF) + +option(BUILD_TESTING "" OFF) + +if(APPLE) + set(CMAKE_OSX_ARCHITECTURES "x86_64;arm64") +endif() + +set(DEFAULT_BUILD_TYPE "Release") +if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) + message(STATUS "Setting build type to '${DEFAULT_BUILD_TYPE}' as none was specified.") + set(CMAKE_BUILD_TYPE "${DEFAULT_BUILD_TYPE}" CACHE + STRING "Choose the type of build." FORCE) + + # Set the possible values of build type for cmake-gui + set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS + "Debug" "Release" "MinSizeRel" "RelWithDebInfo") +endif() + +set(WWISESDK "" CACHE STRING "Path to wwise sdk") + +if(WWISESDK STREQUAL "") + if(DEFINED ENV{WWISESDK}) + set(WWISE_SDK $ENV{WWISESDK}) + else() + unset(WWISESDK CACHE) + message(FATAL_ERROR "Must pass in path to Wwise SDK (-DWWISESDK=\"...\") or setup WWISESDK as an environment variable...") + endif() +else() + set(WWISE_SDK ${WWISESDK}) +endif() + +unset(WWISESDK CACHE) + +list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake") + +add_subdirectory(3rd/JUCE) +add_subdirectory(3rd/Catch2) +add_subdirectory(3rd/trompeloeil) +add_subdirectory(src/shared) +add_subdirectory(src/extension) +add_subdirectory(src/standalone) +add_subdirectory(src/test) +\ No newline at end of file diff --git a/License.txt b/License.txt @@ -0,0 +1,120 @@ + AUDIOKINETIC + + ReaWwise™ END USER LICENSE AGREEMENT (EULA) + +1. License Grant. AUDIOKINETIC Inc. (“AUDIOKINETIC”) grants you a worldwide, + non-exclusive, revocable, non-sublicensable and non transferable license to: + (a) install, use and reproduce, by making a reasonable number of copies of, + ReaWwise on devices owned or controlled by you for the sole purpose of + facilitating integration between REAPER and AUDIOKINETIC Wwise Technology, and + (b) modify and create derivative works of ReaWwise and the ReaWwise source + code for the sole purpose of facilitating integration between REAPER and + AUDIOKINETIC Wwise Technology. + +2. Updates. After you have downloaded and installed ReaWwise, occasional prompts + will request to install updates. Although you will not have to run them + immediately, it is recommended to stay up to date. + +3. Exclusion of certain Open Source Components. If any portion of ReaWwise is + listed as a third party open source component in the ReaWwise documentation, + such portion of ReaWwise will be governed by and subject to the terms of the + relevant open source license reproduced in the documentation and not subject + to terms of this agreement. + +4. Other Software. ReaWwise is designed to work in conjunction with other third + party software. This agreement does not provide you with any rights to such + third party software, and you have the sole responsibility to acquire and + comply with any additional licenses to such third party software. + +5. Title. Title, ownership rights, and intellectual property rights in ReaWwise + shall remain with AUDIOKINETIC.  You are granted no rights in ReaWwise other + than the rights expressly set forth above.  ReaWwise is protected by + intellectual property rights include copyright and trade secret laws and + treaties. + +6. Restrictions. Except as provided herein, you may not (a) modify, translate, + or create derivative works based on ReaWwise; (b) rent, lease, grant a + security interest in, or otherwise transfer rights to ReaWwise; or (c) remove + any proprietary notices in ReaWwise or any software, documentation or other + materials in it or supplied with it. + +7. Support Services.  AUDIOKINETIC will not provide any technical support for + ReaWwise. + +8. Improvements to the Source Code. You will make reasonable efforts to share + information about the source code changes you make to the source code, in + order for AUDIOKINETIC to be able to improve ReaWwise. + +9. Title to the Source Code Changes. Title to your source code changes, and all + rights in and to any intellectual property right therein, shall at all times + remain with you. Delivery by you to AUDIOKINETIC of your source code changes + shall be deemed to include an assignment to AUDIOKINETIC of all of your + rights, title and interest therein, pursuant to which AUDIOKINETIC may + incorporate such changes in the public version of ReaWwise at its sole + discretion. Nothing herein shall affect or impair AUDIOKINETIC’s ownership + rights in the ReaWwise. + +10. No Patent or other Exclusive Rights. You may not file any patent + application (either standalone or as part of a broader application) or + otherwise seek protection for any source code change (including without + limitation any derivative works of the ReaWwise source code such as or + forming part of a plug-in application) which could prevent either + AUDIOKINETIC or another licensee of ReaWwise to use or, solely in case of + AUDIOKINETIC, commercialize changes made by AUDIOKINETIC or such other + licensee to the source code which are the same or similar to your source + code changes. + +11. Disclaimer of Warranty. ReaWwise is provided on an “AS IS” basis, without + warranty of any kind, including without limitation the warranties of + merchantability, fitness fora particular purpose and non-infringement. + AUDIOKINETIC does not warrant that ReaWwise will be error-free or that it + will work without interruption. The entire risk as to the quality, + performance and non-infringement of ReaWwise is borne by You. This + disclaimer of warranty constitutes an essential part of this agreement. SOME + JURISDICTIONS DO NOT ALLOW EXCLUSIONS OF AN IMPLIED WARRANTY, SO THIS + DISCLAIMER MAY NOT APPLY TO YOU AND YOU MAYHAVE OTHER LEGAL RIGHTS THAT VARY + BY JURISDICTION. + +12. Termination. AUDIOKINETIC, in its sole discretion, has the right to + terminate this license. This license will terminate automatically if you + fail to comply with the restrictions described herein. On termination, you + must destroy all copies of ReaWwise in your possession. + +13. Export and Sanctions. You agree to comply with all export laws, + restrictions, national security controls and regulations of the Canada, + United States, or other applicable national or foreign agency or authority, + and not to export or re-export, or allow the export or re-export of any + proprietary information or any copy or direct product thereof in violation + of any such restrictions, laws or regulations. If you are the subject of + economic sanctions of the Canadian or United States government, you cannot + use ReaWwise. If you become the subject of economic sanctions of the + Canadian or United States government during, we have the right to terminate + this license. + +14. LIMITATION OF LIABILITY. IN NO EVENT WILL AUDIOKINETIC'S LIABILITY ARISING + OUT OF OR RELATED TO THIS AGREEMENT OR REAWWISE EXCEED ONE HUNDRED DOLLARS. + IN NO EVENT WILL EITHER PARTY HAVE ANY LIABILITY FOR ANY INDIRECT, + INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES, HOWEVER CAUSED AND BASED ON + ANY THEORY OF LIABILITY, WHETHER FOR BREACH OF CONTRACT, + TORT (INCLUDING NEGLIGENCE) OR OTHERWISE, ARISING OUT OF OR RELATED TO THIS + AGREEMENT, INCLUDING BUT NOT LIMITED TO LOSS OF ANTICIPATED PROFITS OR + BUSINESS INTERRUPTION, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + THESE LIMITATIONS WILL APPLY NOTWITHSTANDING ANY FAILURE OF ESSENTIAL + PURPOSE OF ANY LIMITED REMEDY. THE PARTIES AGREE THAT THE FOREGOING + LIMITATIONS REPRESENT A REASONABLE ALLOCATION OF RISK UNDER THIS AGREEMENT. + +15. Miscellaneous. This agreement represents the complete agreement concerning + this license and may be amended only by writing executed by both parties. + If any provision of this agreement is held to be unenforceable, such + provision shall be reformed only to the extent necessary to make it + enforceable. This agreement will be governed by and construed under the laws + of the province of Quebec and the laws of Canada applicable therein and the + parties hereto submit to the exclusive jurisdiction of the courts of Province + of Quebec, District of Montreal. + +16. Language. You confirm that a French version of this Agreement has been + remitted to you. It is the express wish of the parties to be bound only by + the English version of such agreement. Vous confirmez que la version + française de cette entente vous a été remise. Les parties expriment leur + volonté expresse d’être liées seulement par la version anglaise de cette + entente. diff --git a/Package.distribute b/Package.distribute @@ -0,0 +1,38 @@ +<?xml version="1.0" encoding="UTF-8"?> +<distribute rootdir="../../Installers" + xmlns:tar="attrib://tar" + xmlns:zip="attrib://7z"> + + <tasks> + <task name="ReaperWwiseTransfer.Mac" export-path="${MAC_NAS_PATH}/ReaperWwiseTransfer/${VERSION}/${WWISE_VERSION}.${REAPER_WWISE_TRANSFER_VERSION}/Artifacts" zip:archive-name="ReaperWwiseTransfer_MacOS_${CONFIG}"> + <includegroup>Binary</includegroup> + </task> + <task name="ReaperWwiseTransfer.Windows" export-path="${WINDOWS_NAS_PATH}\ReaperWwiseTransfer\${VERSION}\${WWISE_VERSION}.${REAPER_WWISE_TRANSFER_VERSION}\Artifacts" zip:archive-name="ReaperWwiseTransfer_Windows_${CONFIG}"> + <includegroup>Binary</includegroup> + </task> + <task name="ReaperWwiseTransferBinaryBundles.Windows" export-path="${WINDOWS_NAS_PATH}\ReaperWwiseTransfer\${VERSION}\${WWISE_VERSION}.${REAPER_WWISE_TRANSFER_VERSION}\Bundles" zip:archive-name="ReaperWwiseTransfer_${VERSION}_Build${BUILD_NUMBER}_Windows"> + <includegroup>BinaryBundlesWindows</includegroup> + </task> + <task name="ReaperWwiseTransferBinaryBundles.Mac" export-path="${MAC_NAS_PATH}/ReaperWwiseTransfer/${VERSION}/${WWISE_VERSION}.${REAPER_WWISE_TRANSFER_VERSION}/Bundles" zip:archive-name="ReaperWwiseTransfer_${VERSION}_Build${BUILD_NUMBER}_MacOS"> + <includegroup>BinaryBundlesMac</includegroup> + </task> + </tasks> + + <groups> + <group name="Binary"> + <path source="." > + <include value="*" /> + </path> + </group> + <group name="BinaryBundlesWindows"> + <path source="."> + <include value="*.dll" /> + </path> + </group> + <group name="BinaryBundlesMac"> + <path source="."> + <include value="*.dylib" /> + </path> + </group> + </groups> +</distribute> diff --git a/Package.instrument b/Package.instrument @@ -0,0 +1,108 @@ +<?xml version="1.0" encoding="ISO-8859-1"?> +<instrument rootdir="../" + xmlns:ak="file://instrument/tasks/ak" + xmlns:wwise="file://instrument/tasks/wwise" + xmlns:scripts="file://instrument/tasks/scripts"> + + <!-- Predefined filepaths. --> + <property name="PKG_DISTRIBUTE_PATH" value="ReaperWwiseTransfer/Package.distribute" /> + + <target name="build_reaper_wwise_transfer"> + <fail message="Requires the 'WWISE_BUILD_NUMBER' property to be set." if="${WWISE_BUILD_NUMBER is None}" /> + <fail message="Requires the 'WWISE_VERSION' property to be set." if="${WWISE_VERSION is None}" /> + <fail message="Requires the 'VERSION' property to be set." if="${VERSION is None}" /> + <fail message="Requires the 'BUILD_NUMBER' property to be set." if="${BUILD_NUMBER is None}" /> + + <exec path="mkdir" verbose="true" workingdir="${_ROOT_DIRECTORY_}/ReaperWwiseTransfer"> + <arg value="build"/> + </exec> + + <setenv name="WWISESDK" value="${_ROOT_DIRECTORY_}/Wwise/SDK"/> + + <if condition="${platform.is_darwin()}"> + <exec path="cmake" verbose="true" workingdir="${_ROOT_DIRECTORY_}/ReaperWwiseTransfer/build"> + <arg value='-GXcode'/> + <arg value='..'/> + </exec> + </if> + <if condition="${not platform.is_darwin()}"> + <exec path="cmake" verbose="true" workingdir="${_ROOT_DIRECTORY_}/ReaperWwiseTransfer/build"> + <arg value='-G'/> + <arg value='Visual Studio 16 2019'/> + <arg value='..'/> + </exec> + </if> + + <property name="CONFIGS" value="Release Debug" /> + <foreach property="CONFIG" items="${CONFIGS.split(' ')}"> + <exec path="cmake" verbose="true" workingdir="${_ROOT_DIRECTORY_}/ReaperWwiseTransfer/build"> + <arg value='--build'/> + <arg value='.'/> + <arg value='--target'/> + <arg value='ReaWwise'/> + <arg value='--config'/> + <arg value='${CONFIG}'/> + </exec> + <exec path="cmake" verbose="true" workingdir="${_ROOT_DIRECTORY_}/ReaperWwiseTransfer/build"> + <arg value='--build'/> + <arg value='.'/> + <arg value='--target'/> + <arg value='WwiseTransfer_Test'/> + <arg value='--config'/> + <arg value='${CONFIG}'/> + </exec> + </foreach> + </target> + + <target name="distribute_artifacts"> + <fail message="Requires the 'REAPER_WWISE_TRANSFER_PLATFORM' property to be set." if="${REAPER_WWISE_TRANSFER_PLATFORM is None}" /> + <fail message="Requires the 'WWISE_BUILD_NUMBER' property to be set." if="${WWISE_BUILD_NUMBER is None}" /> + <fail message="Requires the 'BUILD_NUMBER' property to be set." if="${BUILD_NUMBER is None}" /> + <fail message="Requires the 'WWISE_VERSION' property to be set." if="${WWISE_VERSION is None}" /> + <fail message="Requires the 'VERSION' property to be set." if="${VERSION is None}" /> + <fail message="Requires the 'MAC_NAS_PATH' property to be set." if="${MAC_NAS_PATH is None}" /> + <fail message="Requires the 'WINDOWS_NAS_PATH' property to be set." if="${WINDOWS_NAS_PATH is None}" /> + + <property name="REAPER_WWISE_TRANSFER_VERSION" value="${WWISE_BUILD_NUMBER}.${BUILD_NUMBER}" /> + + <property name="CONFIGS" value="Release Debug" /> + <foreach property="CONFIG" items="${CONFIGS.split(' ')}"> + <distribute + file="${PKG_DISTRIBUTE_PATH}" + override-rootpath="${_root_directory_}/ReaperWwiseTransfer/Build/src/extension/${CONFIG}" + tasks="ReaperWwiseTransfer.${REAPER_WWISE_TRANSFER_PLATFORM}" + tool="7z" + mode="export" + /> + </foreach> + </target> + + <target name="distribute_bundles"> + <fail message="Requires the 'REAPER_WWISE_TRANSFER_PLATFORM' property to be set." if="${REAPER_WWISE_TRANSFER_PLATFORM is None}" /> + <fail message="Requires the 'WWISE_BUILD_NUMBER' property to be set." if="${WWISE_BUILD_NUMBER is None}" /> + <fail message="Requires the 'BUILD_NUMBER' property to be set." if="${BUILD_NUMBER is None}" /> + <fail message="Requires the 'WWISE_VERSION' property to be set." if="${WWISE_VERSION is None}" /> + <fail message="Requires the 'VERSION' property to be set." if="${VERSION is None}" /> + <fail message="Requires the 'MAC_NAS_PATH' property to be set." if="${MAC_NAS_PATH is None}" /> + <fail message="Requires the 'WINDOWS_NAS_PATH' property to be set." if="${WINDOWS_NAS_PATH is None}" /> + + <property name="REAPER_WWISE_TRANSFER_VERSION" value="${WWISE_BUILD_NUMBER}.${BUILD_NUMBER}" /> + <property name="CONFIG" value="Release" /> + <distribute + file="${PKG_DISTRIBUTE_PATH}" + override-rootpath="${_root_directory_}/ReaperWwiseTransfer" + tasks="ReaperWwiseTransfer.${REAPER_WWISE_TRANSFER_PLATFORM}" + tool="7z" + mode="import" + /> + + <distribute + file="${PKG_DISTRIBUTE_PATH}" + override-rootpath="${_root_directory_}/ReaperWwiseTransfer" + tasks="ReaperWwiseTransferBinaryBundles.${REAPER_WWISE_TRANSFER_PLATFORM}" + tool="7z" + mode="export" + /> + </target> + +</instrument> diff --git a/Readme.md b/Readme.md @@ -0,0 +1,17 @@ +# ReaperWwiseTransfer + +## Pre-requisites +- cmake 3.22.0 +- git +- Wwise (with SDK source) + +## Building the project +- git clone {repo-url} +- cd ReaperWwiseTransfer +- git submodule update --init +- mkdir build +- cd build +- cmake .. + +<hr> +Inspired by the work of [Karl Davis](https://github.com/karltechno) +\ No newline at end of file diff --git a/cmake/FindAkAutobahn.cmake b/cmake/FindAkAutobahn.cmake @@ -0,0 +1,31 @@ + +file(GLOB AK_AUTOBAHN_SOURCES + "${WWISE_SDK}/samples/WwiseAuthoringAPI/cpp/SampleClient/AkAutobahn/*.h" + "${WWISE_SDK}/samples/WwiseAuthoringAPI/cpp/SampleClient/AkAutobahn/*.cpp" +) + +add_library(AkAutobahn) + +set_property(TARGET AkAutobahn PROPERTY CXX_STANDARD 14) + +target_sources(AkAutobahn PRIVATE ${AK_AUTOBAHN_SOURCES}) + +target_include_directories(AkAutobahn + PUBLIC + ${WWISE_SDK}/samples/WwiseAuthoringAPI/cpp/SampleClient/AkAutobahn/ +) + +find_package(RapidJSON REQUIRED) + +target_link_libraries(AkAutobahn + PRIVATE + RapidJSON + Wwise +) + +target_compile_definitions(AkAutobahn + PRIVATE + WIN32_LEAN_AND_MEAN=1 + USE_WEBSOCKET=1 + _CRT_SECURE_NO_WARNINGS=1 +) +\ No newline at end of file diff --git a/cmake/FindRapidJSON.cmake b/cmake/FindRapidJSON.cmake @@ -0,0 +1,3 @@ +add_library(RapidJSON INTERFACE) + +target_include_directories(RapidJSON INTERFACE ${CMAKE_SOURCE_DIR}/3rd/rapidjson/include/) +\ No newline at end of file diff --git a/cmake/FindReaper.cmake b/cmake/FindReaper.cmake @@ -0,0 +1,3 @@ +add_library(Reaper INTERFACE) + +target_include_directories(Reaper INTERFACE ${CMAKE_SOURCE_DIR}/3rd/reaper-sdk/sdk/) +\ No newline at end of file diff --git a/cmake/FindSwell.cmake b/cmake/FindSwell.cmake @@ -0,0 +1,20 @@ +add_library(Swell STATIC) + +target_sources(Swell PRIVATE "${CMAKE_SOURCE_DIR}/3rd/WDL/WDL/swell/swell-modstub.mm") + +#Add a symlink to WDL inside of reaper-sdk +add_custom_command(TARGET Swell PRE_BUILD + COMMAND ${CMAKE_COMMAND} -E create_symlink ${CMAKE_SOURCE_DIR}/3rd/WDL/WDL ${CMAKE_SOURCE_DIR}/3rd/reaper-sdk/WDL +) + +target_compile_definitions(Swell + PUBLIC + SWELL_PROVIDED_BY_APP +) + +find_library(APPKIT_LIB AppKit) + +target_link_libraries(Swell + PUBLIC + ${APPKIT_LIB} +) +\ No newline at end of file diff --git a/cmake/FindWwise.cmake b/cmake/FindWwise.cmake @@ -0,0 +1,3 @@ +add_library(Wwise INTERFACE) + +target_include_directories(Wwise INTERFACE ${WWISE_SDK}/include/) +\ No newline at end of file diff --git a/cmake/Helpers.cmake b/cmake/Helpers.cmake @@ -0,0 +1,10 @@ +function(build_juce_source_groups) + get_property(all_modules GLOBAL PROPERTY _juce_module_names) + foreach(module_name IN LISTS all_modules) + get_target_property(path ${module_name} INTERFACE_JUCE_MODULE_PATH) + get_target_property(header_files ${module_name} INTERFACE_JUCE_MODULE_HEADERS) + get_target_property(source_files ${module_name} INTERFACE_JUCE_MODULE_SOURCES) + source_group(TREE ${path} PREFIX "JUCE Modules" FILES ${header_files} ${source_files}) + set_source_files_properties(${header_files} PROPERTIES HEADER_FILE_ONLY TRUE) + endforeach() +endfunction() +\ No newline at end of file diff --git a/src/extension/CMakeLists.txt b/src/extension/CMakeLists.txt @@ -0,0 +1,91 @@ +include(Helpers) + +if(APPLE) + macro (set_xcode_property TARGET XCODE_PROPERTY XCODE_VALUE) + set_property (TARGET ${TARGET} PROPERTY XCODE_ATTRIBUTE_${XCODE_PROPERTY} ${XCODE_VALUE}) + endmacro (set_xcode_property) +endif() + +project(ReaWwise) + +file(GLOB_RECURSE EXTENSION_SOURCES + "${PROJECT_SOURCE_DIR}/*.h" + "${PROJECT_SOURCE_DIR}/*.cpp") + +add_library(${PROJECT_NAME} SHARED) + +if(NOT DEFINED ENV{BUILD_NUMBER}) + if(APPLE) + set(EXTENSION_OUTPUT_DIR "~/Library/Application Support/Reaper/UserPlugins") + + set_target_properties(${PROJECT_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${EXTENSION_OUTPUT_DIR}) + set_target_properties(${PROJECT_NAME} PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${EXTENSION_OUTPUT_DIR}) + set_target_properties(${PROJECT_NAME} PROPERTIES ARCHIVE_OUTPUT_DIRECTORY ${EXTENSION_OUTPUT_DIR}) + elseif(WIN32) + set(EXTENSION_OUTPUT_DIR "$ENV{APPDATA}\\REAPER\\UserPlugins") + + foreach(OUTPUTCONFIG ${CMAKE_CONFIGURATION_TYPES}) + string(TOUPPER ${OUTPUTCONFIG} OUTPUTCONFIG) + set_target_properties(${PROJECT_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY_${OUTPUTCONFIG} ${EXTENSION_OUTPUT_DIR}) + set_target_properties(${PROJECT_NAME} PROPERTIES LIBRARY_OUTPUT_DIRECTORY_${OUTPUTCONFIG} ${EXTENSION_OUTPUT_DIR}) + set_target_properties(${PROJECT_NAME} PROPERTIES ARCHIVE_OUTPUT_DIRECTORY_${OUTPUTCONFIG} ${EXTENSION_OUTPUT_DIR}) + endforeach(OUTPUTCONFIG CMAKE_CONFIGURATION_TYPES) + + set_target_properties(${PROJECT_NAME} PROPERTIES VS_DEBUGGER_COMMAND "C:\\Program Files\\REAPER (x64)\\reaper.exe") + endif() +endif() + +set_target_properties(${PROJECT_NAME} PROPERTIES PREFIX "") +set_target_properties(${PROJECT_NAME} PROPERTIES OUTPUT_NAME reaper_reawwise) + +target_sources(${PROJECT_NAME} PRIVATE ${EXTENSION_SOURCES}) + +find_package(Reaper REQUIRED) + +target_link_libraries(${PROJECT_NAME} + PRIVATE + WwiseTransfer_Shared + Reaper +) + +if(APPLE) + if(DEFINED ENV{CODE_SIGN_IDENTITY_ID} AND DEFINED ENV{DEVELOPMENT_TEAM_ID}) + SET_XCODE_PROPERTY(${PROJECT_NAME} CODE_SIGN_IDENTITY $ENV{CODE_SIGN_IDENTITY_ID}) + SET_XCODE_PROPERTY(${PROJECT_NAME} DEVELOPMENT_TEAM $ENV{DEVELOPMENT_TEAM_ID}) + endif() + + find_package(Swell REQUIRED) + + target_link_libraries(${PROJECT_NAME} + PRIVATE + Swell + ) +endif() + +target_compile_definitions(${PROJECT_NAME} + PRIVATE + REAPERAPI_MINIMAL + REAPERAPI_WANT_GetMainHwnd + REAPERAPI_WANT_ShowConsoleMsg + REAPERAPI_WANT_AddExtensionsMainMenu + REAPERAPI_WANT_EnumProjects + REAPERAPI_WANT_GetSetProjectInfo_String + REAPERAPI_WANT_GetProjectName + REAPERAPI_WANT_ResolveRenderPattern + REAPERAPI_WANT_EnumProjectMarkers2 + REAPERAPI_WANT_EnumRegionRenderMatrix + REAPERAPI_WANT_GetParentTrack + REAPERAPI_WANT_GetTrackName + REAPERAPI_WANT_Main_OnCommand + REAPERAPI_WANT_GetProjectPathEx + REAPERAPI_WANT_ShowMessageBox + REAPERAPI_WANT_GetProjExtState + REAPERAPI_WANT_SetProjExtState + REAPERAPI_WANT_MarkProjectDirty + JUCE_APPLICATION_NAME_STRING="${PROJECT_NAME}" + JUCE_STANDALONE_APPLICATION=0 +) + +source_group(TREE ${PROJECT_SOURCE_DIR} PREFIX "Source Files" FILES ${EXTENSION_SOURCES}) + +build_juce_source_groups() diff --git a/src/extension/Extension.cpp b/src/extension/Extension.cpp @@ -0,0 +1,767 @@ +#define REAPERAPI_IMPLEMENT + +#include "ExtensionWindow.h" +#include "ReaperContext.h" + +#include <JSONHelpers.h> +#include <juce_events/juce_events.h> +#include <memory> +#include <reaper_plugin_functions.h> +#include <tuple> +#include <variant> + +namespace AK::ReaWwise +{ + static bool juceInitialised = false; + static std::unique_ptr<ExtensionWindow> mainWindow; + static std::unique_ptr<ReaperContext> reaperContext; + static std::string returnString; + static std::string emptyReturnString; + static double returnDouble; + static int openReaperWwiseTransferCommandId = 0; + + static void onHookCustomMenu(const char* menuName, HMENU menuHandle, int flag) + { + if(flag == 0 && juce::String(menuName) == "Main extensions" && openReaperWwiseTransferCommandId) + { + MENUITEMINFO mi = {sizeof(MENUITEMINFO)}; + mi.fMask = MIIM_TYPE | MIIM_ID; + mi.fType = MFT_STRING; + mi.wID = openReaperWwiseTransferCommandId; + mi.dwTypeData = (char*)"ReaWwise"; + InsertMenuItem(menuHandle, 0, true, &mi); + } + } + + static bool onHookCommand(int command, int flag) + { + if(command == openReaperWwiseTransferCommandId) + { + if(!juceInitialised) + { + juce::initialiseJuce_GUI(); + juceInitialised = true; + } + + if(!mainWindow) + { + mainWindow = std::make_unique<ExtensionWindow>(*reaperContext); +#ifdef WIN32 + mainWindow->addToDesktop(mainWindow->getDesktopWindowStyleFlags(), reaperContext->getMainHwnd()); +#else + mainWindow->addToDesktop(mainWindow->getDesktopWindowStyleFlags(), 0); + juce::ComponentPeer* componentPeer = mainWindow->getPeer(); + componentPeer->setAlwaysOnTop(true); +#endif + } + + // TODO: There might be more stuff that needs to be done on visibility toggle, i.e. re-read app properties, keeping the extension alive + mainWindow->setVisible(!mainWindow->isVisible()); + + return true; + } + + return false; + } + + namespace Scripting + { + using namespace AK::WwiseAuthoringAPI; + + static std::unique_ptr<WwiseTransfer::WaapiClient> waapiClient; + + template <typename Type> + static bool isObjectValid(Type* object, const std::set<Type>& objectSet) + { + return object != nullptr && objectSet.find(*object) != objectSet.end(); + } + + static bool isWaapiClientConnected() + { + return waapiClient != nullptr && waapiClient->isConnected(); + } + + template <class T> + static T argCast(void* arg) + { + return (T)arg; + } + + template <> + double argCast<double>(void* arg) + { + return *(double*)arg; + } + + template <> + int argCast<int>(void* arg) + { + return (int)(intptr_t)arg; + } + + template <class... Types> + struct Arguments : public std::tuple<Types...> + { + Arguments(void** args) + { + populate(args); + } + + template <size_t I> + auto get() + { + return std::get<I>(*this); + } + + private: + template <size_t I = 0> + constexpr void populate(void** args) + { + if constexpr(I == sizeof...(Types)) + { + return; + } + else + { + using Type = typename std::tuple_element<I, std::tuple<Types...>>::type; + + std::get<I, Types...>(*this) = argCast<Type>(args[I]); + populate<I + 1>(args); + } + } + }; + + struct AkJsonRef + { + typedef std::map<std::string, std::shared_ptr<AkJsonRef>> Map; + typedef std::vector<std::shared_ptr<AkJsonRef>> Array; + + std::variant<AkVariant, Map, Array> data; + + AkJsonRef() = default; + + AkJsonRef(const std::variant<AkVariant, Map, Array>& data) + : data(data) + { + } + + virtual ~AkJsonRef() + { + } + + bool isMap() const + { + return std::holds_alternative<Map>(data); + } + + bool isArray() const + { + return std::holds_alternative<Array>(data); + } + + bool isVariant() const + { + return std::holds_alternative<AkVariant>(data); + } + }; + + static AkJsonRef AkJsonToAkJsonRef(const AkJson& akJson) + { + if(akJson.IsMap()) + { + AkJsonRef::Map map{}; + + for(auto& [key, value] : akJson.GetMap()) + { + map[key] = std::make_shared<AkJsonRef>(AkJsonToAkJsonRef(value)); + } + + return AkJsonRef{map}; + } + else if(akJson.IsArray()) + { + AkJsonRef::Array array{}; + + for(auto& value : akJson.GetArray()) + { + array.emplace_back(std::make_shared<AkJsonRef>(AkJsonToAkJsonRef(value))); + } + + return AkJsonRef{array}; + } + else if(akJson.IsVariant()) + { + return AkJsonRef{akJson.GetVariant()}; + } + + return AkJsonRef(); + } + + static AkJson AkJsonRefToAkJson(std::shared_ptr<AkJsonRef> akJsonRef) + { + if(akJsonRef->isMap()) + { + AkJson::Map mapAsAkJson{}; + + AkJsonRef::Map& map = std::get<AkJsonRef::Map>(akJsonRef->data); + for(auto& [key, value] : map) + { + mapAsAkJson.emplace(key, AkJsonRefToAkJson(value)); + } + + return AkJson(mapAsAkJson); + } + else if(akJsonRef->isArray()) + { + AkJson::Array arrayAsAkJson{}; + + AkJsonRef::Array& arr = std::get<AkJsonRef::Array>(akJsonRef->data); + for(auto& element : arr) + { + arrayAsAkJson.emplace_back(AkJsonRefToAkJson(element)); + } + + return AkJson(arrayAsAkJson); + } + else if(akJsonRef->isVariant()) + { + return AkJson(std::get<AkVariant>(akJsonRef->data)); + } + + return AkJson(); + } + + struct AkJsonRefWithStatus : public AkJsonRef + { + bool status; + }; + + static std::set<std::shared_ptr<AkJsonRef>> objects; + + ///////// Waapi ///////// + + static bool Waapi_Connect(const char* ipAddress, intptr_t port) + { + if(waapiClient == nullptr) + waapiClient.reset(new WwiseTransfer::WaapiClient()); + + if(!waapiClient->isConnected()) + return waapiClient->connect(ipAddress, port); + + return true; + } + + static void* Waapi_ConnectVarArg(void** argv, int argc) + { + juce::ignoreUnused(argc); + + return (void*)Waapi_Connect((const char*)argv[0], (intptr_t)argv[1]); + } + + static void Waapi_Disconnect() + { + if(waapiClient != nullptr) + { + if(waapiClient->isConnected()) + waapiClient->disconnect(); + + waapiClient.reset(nullptr); + } + } + + static void Waapi_DisconnectVarArg(void** argv, int argc) + { + Waapi_Disconnect(); + } + + static bool Waapi_IsConnected() + { + return waapiClient != nullptr && waapiClient->isConnected(); + } + + static void* Waapi_IsConnectedVarArg(void** argv, int argc) + { + juce::ignoreUnused(argc); + + return (void*)Waapi_IsConnected(); + } + + static void* Waapi_Call(const char* uri, std::shared_ptr<AkJsonRef>* args, std::shared_ptr<AkJsonRef>* options) + { + if(isWaapiClientConnected() && isObjectValid(args, objects) && isObjectValid(options, objects)) + { + AkJson result; + + AkJsonRefWithStatus akJsonResult; + akJsonResult.status = waapiClient->call(uri, AkJsonRefToAkJson(*args), AkJsonRefToAkJson(*options), result); + + akJsonResult.data = AkJsonToAkJsonRef(result).data; + + auto insert = objects.insert(std::make_shared<AkJsonRefWithStatus>(akJsonResult)); + + if(insert.second) + return (void*)&(*insert.first); + } + + return nullptr; + } + + static void* Waapi_CallVarArg(void** argv, int argc) + { + juce::ignoreUnused(argc); + + Arguments<const char*, std::shared_ptr<AkJsonRef>*, std::shared_ptr<AkJsonRef>*> arguments(argv); + + return Waapi_Call(arguments.get<0>(), arguments.get<1>(), arguments.get<2>()); + } + + ///////// AkJson_Any ///////// + + template <typename T> + static void* AkJson_Any() + { + auto result = objects.insert(std::make_shared<AkJsonRef>(T{})); + + if(result.second) + return (void*)&(*result.first); + + return nullptr; + } + + ///////// AkJson_Map ///////// + static void* AkJson_Map() + { + return AkJson_Any<AkJsonRef::Map>(); + } + + static void* AkJson_MapVarArg(void** argv, int argc) + { + juce::ignoreUnused(argc); + + return AkJson_Map(); + } + + static bool AkJson_Map_Set(std::shared_ptr<AkJsonRef>* akJsonRef, const char* key, std::shared_ptr<AkJsonRef>* value) + { + if(isObjectValid(akJsonRef, objects) && isObjectValid(value, objects) && (**akJsonRef).isMap()) + { + AkJsonRef::Map& map = std::get<AkJsonRef::Map>((**akJsonRef).data); + map[key] = *value; + + return true; + } + + return false; + } + + static void* AkJson_Map_SetVarArg(void** argv, int argc) + { + juce::ignoreUnused(argc); + + Arguments<std::shared_ptr<AkJsonRef>*, const char*, std::shared_ptr<AkJsonRef>*> arguments(argv); + + return (void*)AkJson_Map_Set(arguments.get<0>(), arguments.get<1>(), arguments.get<2>()); + } + + static void* AkJson_Map_Get(std::shared_ptr<AkJsonRef>* akJsonRef, const char* key) + { + if(isObjectValid(akJsonRef, objects) && (**akJsonRef).isMap()) + { + AkJsonRef::Map& map = std::get<AkJsonRef::Map>((**akJsonRef).data); + + if(map.find(key) != map.end()) + { + if(objects.find(map[key]) == objects.end()) + objects.insert(map[key]); + + return (void*)&map[key]; + } + } + + return nullptr; + } + + static void* AkJson_Map_GetVarArg(void** argv, int argc) + { + juce::ignoreUnused(argc); + + Arguments<std::shared_ptr<AkJsonRef>*, const char*> arguments(argv); + + return AkJson_Map_Get(arguments.get<0>(), arguments.get<1>()); + } + + ///////// AkJson_Array ///////// + static void* AkJson_Array() + { + return AkJson_Any<AkJsonRef::Array>(); + } + + static void* AkJson_ArrayVarArg(void** argv, int argc) + { + juce::ignoreUnused(argc); + + return AkJson_Array(); + } + + static bool AkJson_Array_Add(std::shared_ptr<AkJsonRef>* akJsonRef, std::shared_ptr<AkJsonRef>* value) + { + if(isObjectValid(akJsonRef, objects) && isObjectValid(value, objects) && (**akJsonRef).isArray()) + { + AkJsonRef::Array& array = std::get<AkJsonRef::Array>((**akJsonRef).data); + array.emplace_back(*value); + + return true; + } + + return false; + } + + static void* AkJson_Array_AddVarArg(void** argv, int argc) + { + juce::ignoreUnused(argc); + + Arguments<std::shared_ptr<AkJsonRef>*, std::shared_ptr<AkJsonRef>*> arguments(argv); + + return (void*)AkJson_Array_Add(arguments.get<0>(), arguments.get<1>()); + } + + static void* AkJson_Array_Get(std::shared_ptr<AkJsonRef>* akJsonRef, int index) + { + if(isObjectValid(akJsonRef, objects) && (**akJsonRef).isArray()) + { + AkJsonRef::Array& array = std::get<AkJsonRef::Array>((**akJsonRef).data); + + if(index < array.size()) + { + if(objects.find(array[index]) == objects.end()) + objects.insert(array[index]); + + return (void*)&array[index]; + } + } + + return nullptr; + } + + static void* AkJson_Array_GetVarArg(void** argv, int argc) + { + juce::ignoreUnused(argc); + + Arguments<std::shared_ptr<AkJsonRef>*, int> arguments(argv); + + return AkJson_Array_Get(arguments.get<0>(), arguments.get<1>()); + } + + static int AkJson_Array_Size(std::shared_ptr<AkJsonRef>* akJsonRef) + { + if(isObjectValid(akJsonRef, objects) && (**akJsonRef).isArray()) + { + AkJsonRef::Array& array = std::get<AkJsonRef::Array>((**akJsonRef).data); + return array.size(); + } + + return 0; + } + + static void* AkJson_Array_SizeVarArg(void** argv, int argc) + { + juce::ignoreUnused(argc); + + Arguments<std::shared_ptr<AkJsonRef>*> arguments(argv); + + return (void*)(intptr_t)AkJson_Array_Size(arguments.get<0>()); + } + + ///////// AkVariant ///////// + + template <typename T> + static void* AkVariant_Any(T value) + { + auto result = objects.insert(std::make_shared<AkJsonRef>(AkVariant(value))); + + if(result.second) + return (void*)&(*result.first); + + return nullptr; + } + + static void* AkVariant_Bool(bool value) + { + return AkVariant_Any(value); + } + + static void* AkVariant_BoolVarArg(void** argv, int argc) + { + juce::ignoreUnused(argc); + + Arguments<bool> arguments(argv); + + return AkVariant_Bool(arguments.get<0>()); + } + + static void* AkVariant_Int(int value) + { + return AkVariant_Any(value); + } + + static void* AkVariant_IntVarArg(void** argv, int argc) + { + juce::ignoreUnused(argc); + + Arguments<int> arguments(argv); + + return AkVariant_Int(arguments.get<0>()); + } + + static void* AkVariant_Double(double value) + { + return AkVariant_Any(value); + } + + static void* AkVariant_DoubleVarArg(void** argv, int argc) + { + juce::ignoreUnused(argc); + + Arguments<double> arguments(argv); + + return AkVariant_Double(arguments.get<0>()); + } + + static void* AkVariant_String(const char* value) + { + return AkVariant_Any(value); + } + + static void* AkVariant_StringVarArg(void** argv, int argc) + { + juce::ignoreUnused(argc); + + Arguments<const char*> arguments(argv); + + return AkVariant_String(arguments.get<0>()); + } + + template <typename T> + static T AkVariant_GetAny(std::shared_ptr<AkJsonRef>* akJsonRef) + { + if(isObjectValid(akJsonRef, objects) && (**akJsonRef).isVariant()) + { + AkVariant& variant = std::get<AkVariant>((**akJsonRef).data); + return (T)variant; + } + + return 0; + } + + template <> + const char* AkVariant_GetAny<const char*>(std::shared_ptr<AkJsonRef>* akJsonRef) + { + if(isObjectValid(akJsonRef, objects) && (**akJsonRef).isVariant()) + { + AkVariant& variant = std::get<AkVariant>((**akJsonRef).data); + returnString = variant.GetString(); + + return returnString.c_str(); + } + + return emptyReturnString.c_str(); + } + + static bool AkVariant_GetBool(std::shared_ptr<AkJsonRef>* akJsonRef) + { + return AkVariant_GetAny<bool>(akJsonRef); + } + + static void* AkVariant_GetBoolVarArg(void** argv, int argc) + { + Arguments<std::shared_ptr<AkJsonRef>*> arguments(argv); + + return (void*)AkVariant_GetBool(arguments.get<0>()); + } + + static int AkVariant_GetInt(std::shared_ptr<AkJsonRef>* akJsonRef) + { + return AkVariant_GetAny<int>(akJsonRef); + } + + static void* AkVariant_GetIntVarArg(void** argv, int argc) + { + juce::ignoreUnused(argc); + + Arguments<std::shared_ptr<AkJsonRef>*> arguments(argv); + + return (void*)(intptr_t)AkVariant_GetInt(arguments.get<0>()); + } + + static double AkVariant_GetDouble(std::shared_ptr<AkJsonRef>* akJsonRef) + { + return AkVariant_GetAny<double>(akJsonRef); + } + + static void* AkVariant_GetDoubleVarArg(void** argv, int argc) + { + juce::ignoreUnused(argc); + + Arguments<std::shared_ptr<AkJsonRef>*> arguments(argv); + + returnDouble = AkVariant_GetDouble(arguments.get<0>()); + return reinterpret_cast<void*>(&returnDouble); + } + + static const char* AkVariant_GetString(std::shared_ptr<AkJsonRef>* akJsonRef) + { + return AkVariant_GetAny<const char*>(akJsonRef); + } + + static void* AkVariant_GetStringVarArg(void** argv, int argc) + { + juce::ignoreUnused(argc); + + Arguments<std::shared_ptr<AkJsonRef>*> arguments(argv); + + return (void*)AkVariant_GetString(arguments.get<0>()); + } + + ///////// AkJsonRefWithStatus ///////// + + static const bool AkJson_GetStatus(std::shared_ptr<AkJsonRef>* akJsonRef) + { + if(isObjectValid(akJsonRef, objects)) + { + if(auto akJsonResult = std::dynamic_pointer_cast<AkJsonRefWithStatus>(*akJsonRef)) + { + return akJsonResult->status; + }; + } + + return false; + } + + static void* AkJson_GetStatusVarArg(void** argv, int argc) + { + juce::ignoreUnused(argc); + + Arguments<std::shared_ptr<AkJsonRef>*> arguments(argv); + + return (void*)AkJson_GetStatus(arguments.get<0>()); + } + + struct ApiFunctionDefinition + { + const char* Api; + const char* ApiVarArg; + const char* ApiDef; + const char* FunctionSignature; + void* FunctionPointer; + void* FunctionPointerVarArg; + }; + +#define AK_RWT_GENERATE_API_FUNC_DEF(functionName, output, inputs, inputNames, description) \ + ApiFunctionDefinition \ + { \ + "API_AK_" #functionName, \ + "APIvararg_AK_" #functionName, \ + "APIdef_AK_" #functionName, \ + output "\0" inputs "\0" inputNames "\0" description, \ + (void*)&functionName, \ + (void*)&functionName##VarArg \ + } + + static auto apiFunctionDefinitions = { + AK_RWT_GENERATE_API_FUNC_DEF(Waapi_Connect, "bool", "const char*,int", "ipAddress,port", "Ak: Connect to waapi (Returns connection status as bool)"), + AK_RWT_GENERATE_API_FUNC_DEF(Waapi_Disconnect, "void", "", "", "Ak: Disconnect from waapi"), + AK_RWT_GENERATE_API_FUNC_DEF(Waapi_Call, "*", "const char*,*,*", "uri,*,*", "Ak: Make a call to Waapi"), + + AK_RWT_GENERATE_API_FUNC_DEF(AkJson_Map, "*", "", "", "Ak: Create a map object"), + AK_RWT_GENERATE_API_FUNC_DEF(AkJson_Map_Get, "*", "*,const char*", "*,key", "Ak: Get a map object"), + AK_RWT_GENERATE_API_FUNC_DEF(AkJson_Map_Set, "bool", "*,const char*,*", "*,key,*", "Ak: Set a property on a map object"), + + AK_RWT_GENERATE_API_FUNC_DEF(AkJson_Array, "*", "", "", "Ak: Create an array object"), + AK_RWT_GENERATE_API_FUNC_DEF(AkJson_Array_Add, "bool", "*,*", "*,*", "Ak: Add element to an array object"), + AK_RWT_GENERATE_API_FUNC_DEF(AkJson_Array_Get, "*", "*,int", "*,index", "Ak: Get element at index of array object"), + AK_RWT_GENERATE_API_FUNC_DEF(AkJson_Array_Size, "int", "*", "*", "Ak: Get count of elements in array object"), + + AK_RWT_GENERATE_API_FUNC_DEF(AkJson_GetStatus, "bool", "*", "*", "Ak: Get the status of a result from a call to waapi"), + + AK_RWT_GENERATE_API_FUNC_DEF(AkVariant_Bool, "*", "bool", "bool", "Ak: Create a bool object"), + AK_RWT_GENERATE_API_FUNC_DEF(AkVariant_GetBool, "bool", "*", "*", "Ak: Extract raw boolean value from bool object"), + + AK_RWT_GENERATE_API_FUNC_DEF(AkVariant_String, "*", "const char*", "string", "Ak: Create a string object"), + AK_RWT_GENERATE_API_FUNC_DEF(AkVariant_GetString, "const char*", "*", "*", "Ak: Extract raw string value from string object"), + + AK_RWT_GENERATE_API_FUNC_DEF(AkVariant_Int, "*", "int", "int", "Ak: Create an int object"), + AK_RWT_GENERATE_API_FUNC_DEF(AkVariant_GetInt, "int", "*", "*", "Ak: Extract raw int value from int object"), + + AK_RWT_GENERATE_API_FUNC_DEF(AkVariant_Double, "*", "double", "double", "Ak: Create a double object"), + AK_RWT_GENERATE_API_FUNC_DEF(AkVariant_GetDouble, "double", "*", "*", "Ak: Extract raw double value from double object"), + }; + +#undef AK_RWT_GENERATE_API_FUNC_DEF + } // namespace Scripting + + static int initialize(reaper_plugin_info_t* pluginInfo) + { + reaperContext = std::make_unique<ReaperContext>(pluginInfo); + + // Should actually report errors to the user somehow + if(reaperContext->callerVersion() != REAPER_PLUGIN_VERSION) + { + return 0; + } + + // Checks that all function pointers needed from reaper are valid + if(!reaperContext->isValid()) + { + return 0; + } + + openReaperWwiseTransferCommandId = reaperContext->registerFunction("command_id", (void*)"openReaperWwiseTransferCommand"); + if(!openReaperWwiseTransferCommandId) + { + return 0; + } + + if(!reaperContext->registerFunction("hookcommand", (void*)onHookCommand)) + { + return 0; + }; + + if(!reaperContext->registerFunction("hookcustommenu", (void*)onHookCustomMenu)) + { + return 0; + } + + reaperContext->addExtensionsMainMenu(); + + for(const auto& apiFunctionDefinition : Scripting::apiFunctionDefinitions) + { + reaperContext->registerFunction(apiFunctionDefinition.Api, (void*)apiFunctionDefinition.FunctionPointer); + reaperContext->registerFunction(apiFunctionDefinition.ApiVarArg, (void*)apiFunctionDefinition.FunctionPointerVarArg); + reaperContext->registerFunction(apiFunctionDefinition.ApiDef, (void*)apiFunctionDefinition.FunctionSignature); + } + + return 1; + } + + static int cleanup() + { + if(juceInitialised) + { + mainWindow.reset(nullptr); + reaperContext.reset(nullptr); + + juce::shutdownJuce_GUI(); + juceInitialised = false; + } + + return 0; + } +} // namespace AK::ReaWwise + +extern "C" REAPER_PLUGIN_DLL_EXPORT int REAPER_PLUGIN_ENTRYPOINT( + REAPER_PLUGIN_HINSTANCE instance, reaper_plugin_info_t* pluginInfo) +{ + using namespace AK::ReaWwise; + + return pluginInfo ? initialize(pluginInfo) : cleanup(); +} diff --git a/src/extension/ExtensionWindow.cpp b/src/extension/ExtensionWindow.cpp @@ -0,0 +1,50 @@ +#include "ExtensionWindow.h" + +#include "UI/MainComponent.h" + +#include <limits> + +namespace AK::ReaWwise +{ + namespace ExtensionWindowConstants + { + constexpr int width = 600; + constexpr int height = 800; + constexpr int minWidth = 420; + constexpr int minHeight = 650; + constexpr int standardDPI = 96; + } // namespace ExtensionWindowConstants + + ExtensionWindow::ExtensionWindow(WwiseTransfer::DawContext& dawContext) + : juce::ResizableWindow(JUCE_APPLICATION_NAME_STRING, false) + { + using namespace ExtensionWindowConstants; + + juce::LookAndFeel::setDefaultLookAndFeel(&lookAndFeel); + + mainContentComponent.reset(new WwiseTransfer::MainComponent(dawContext, JUCE_APPLICATION_NAME_STRING)); + + if(!mainContentComponent->hasScaleFactorOverride()) + { + auto scaleFactor = juce::Desktop::getInstance().getDisplays().getMainDisplay().dpi / standardDPI; + juce::Desktop::getInstance().setGlobalScaleFactor(scaleFactor); + } + + setContentNonOwned(mainContentComponent.get(), true); + centreWithSize(width, height); + setResizable(true, true); + setResizeLimits(minWidth, minHeight, (std::numeric_limits<int>::max)(), (std::numeric_limits<int>::max)()); + } + + int ExtensionWindow::getDesktopWindowStyleFlags() const + { + return juce::ComponentPeer::windowHasCloseButton | juce::ComponentPeer::windowHasTitleBar | + juce::ComponentPeer::windowIsResizable | juce::ComponentPeer::windowHasMinimiseButton | + juce::ComponentPeer::windowAppearsOnTaskbar | juce::ComponentPeer::windowHasMaximiseButton; + } + + void ExtensionWindow::userTriedToCloseWindow() + { + setVisible(false); + } +} // namespace AK::ReaWwise diff --git a/src/extension/ExtensionWindow.h b/src/extension/ExtensionWindow.h @@ -0,0 +1,20 @@ +#pragma once + +#include "Core/DawContext.h" +#include "UI/MainComponent.h" + +namespace AK::ReaWwise +{ + class ExtensionWindow : public juce::ResizableWindow + { + public: + ExtensionWindow(WwiseTransfer::DawContext& dawContext); + + int getDesktopWindowStyleFlags() const override; + void userTriedToCloseWindow() override; + + private: + std::unique_ptr<WwiseTransfer::MainComponent> mainContentComponent; + WwiseTransfer::CustomLookAndFeel lookAndFeel; + }; +} // namespace AK::ReaWwise diff --git a/src/extension/ReaperContext.cpp b/src/extension/ReaperContext.cpp @@ -0,0 +1,347 @@ +#include "ReaperContext.h" + +#include "Helpers/WwiseHelper.h" +#include "Model/Wwise.h" + +#include <algorithm> +#include <cstdlib> +#include <map> +#include <memory> +#include <optional> + +namespace AK::ReaWwise +{ + namespace ReaperContextConstants + { + constexpr int defaultBufferSize = 4096; + const juce::String stateSizeKey = "stateSize"; + const juce::String stateKey = "state"; + const juce::String applicationKey = "ReaWwise"; + } // namespace ReaperContextConstants + + struct RenderInfo + { + juce::String resolvedRenderPath; + juce::String resolvedRenderPathWithOriginalsSubfolder; + juce::String finalRenderPath; + }; + + struct TimeRange + { + double start{}; + double end{}; + + bool overlaps(const TimeRange& other) + { + return start <= other.end && end >= other.start; + } + }; + + struct ReaperMarker + { + const char* name; + bool isRegion; + TimeRange timeRange; + int index; + }; + + ReaperContext::ReaperContext(reaper_plugin_info_t* pluginInfo) + : pluginInfo(pluginInfo) + , defaultRenderDirectory(juce::File::getSpecialLocation(juce::File::userDocumentsDirectory).getChildFile("REAPER Media")) + , defaultRenderPattern("untitled") + { + getMainHwnd = decltype(GetMainHwnd)(pluginInfo->GetFunc("GetMainHwnd")); + showConsoleMsg = decltype(ShowConsoleMsg)(pluginInfo->GetFunc("ShowConsoleMsg")); + addExtensionsMainMenu = decltype(AddExtensionsMainMenu)(pluginInfo->GetFunc("AddExtensionsMainMenu")); + enumProjects = decltype(EnumProjects)(pluginInfo->GetFunc("EnumProjects")); + getSetProjectInfo_String = decltype(GetSetProjectInfo_String)(pluginInfo->GetFunc("GetSetProjectInfo_String")); + getProjectName = decltype(GetProjectName)(pluginInfo->GetFunc("GetProjectName")); + resolveRenderPattern = decltype(ResolveRenderPattern)(pluginInfo->GetFunc("ResolveRenderPattern")); + enumProjectMarkers2 = decltype(EnumProjectMarkers2)(pluginInfo->GetFunc("EnumProjectMarkers2")); + enumRegionRenderMatrix = decltype(EnumRegionRenderMatrix)(pluginInfo->GetFunc("EnumRegionRenderMatrix")); + getParentTrack = decltype(GetParentTrack)(pluginInfo->GetFunc("GetParentTrack")); + getTrackName = decltype(GetTrackName)(pluginInfo->GetFunc("GetTrackName")); + main_OnCommand = decltype(Main_OnCommand)(pluginInfo->GetFunc("Main_OnCommand")); + getProjectPathEx = decltype(GetProjectPathEx)(pluginInfo->GetFunc("GetProjectPathEx")); + showMessageBox = decltype(ShowMessageBox)(pluginInfo->GetFunc("ShowMessageBox")); + getProjExtState = decltype(GetProjExtState)(pluginInfo->GetFunc("GetProjExtState")); + setProjExtState = decltype(SetProjExtState)(pluginInfo->GetFunc("SetProjExtState")); + markProjectDirty = decltype(MarkProjectDirty)(pluginInfo->GetFunc("MarkProjectDirty")); + } + + juce::String ReaperContext::getSessionName() + { + auto projectInfo = getProjectInfo(); + return projectInfo.projectPath; + } + + bool ReaperContext::saveState(juce::ValueTree applicationState) + { + using namespace ReaperContextConstants; + + auto projectInfo = getProjectInfo(); + + auto applicationStateString = applicationState.toXmlString(); + auto applicationStateStringSize = juce::String(applicationStateString.getNumBytesAsUTF8()); + + if(setProjExtState(projectInfo.projectReference, applicationKey.toUTF8(), stateSizeKey.toUTF8(), applicationStateStringSize.toUTF8()) && + setProjExtState(projectInfo.projectReference, applicationKey.toUTF8(), stateKey.toUTF8(), applicationStateString.toUTF8())) + { + markProjectDirty(projectInfo.projectReference); + return true; + } + + return false; + } + + juce::ValueTree ReaperContext::retrieveState() + { + using namespace ReaperContextConstants; + + juce::ValueTree state; + + auto projectInfo = getProjectInfo(); + + std::string buffer(ReaperContextConstants::defaultBufferSize, '\0'); + getProjExtState(projectInfo.projectReference, applicationKey.toUTF8(), stateSizeKey.toUTF8(), &buffer[0], buffer.size()); + + auto stateSize = std::strtoll(&buffer[0], nullptr, 10); + + if(stateSize != 0) + { + buffer.resize(stateSize); + + if(getProjExtState(projectInfo.projectReference, applicationKey.toUTF8(), stateKey.toUTF8(), &buffer[0], buffer.size())) + { + auto valueTree = juce::ValueTree::fromXml(buffer); + state = valueTree; + } + } + + return state; + } + + int ReaperContext::callerVersion() + { + return pluginInfo->caller_version; + } + + int ReaperContext::registerFunction(const char* command, void* function) + { + return pluginInfo->Register(command, function); + } + + std::vector<juce::String> ReaperContext::splitDoubleNullTerminatedString(const char* buffer) + { + std::vector<juce::String> result; + + for(const char* current = buffer; current && *current; current += result.back().length() + 1) + { + result.emplace_back(current); + } + + return result; + } + + bool ReaperContext::isValid() + { + if(getMainHwnd && + showConsoleMsg && + addExtensionsMainMenu && + enumProjects && + getSetProjectInfo_String && + getProjectName && + resolveRenderPattern && + enumProjectMarkers2 && + enumRegionRenderMatrix && + getParentTrack && + getTrackName && + main_OnCommand && + getProjectPathEx && + showMessageBox && + getProjExtState && + setProjExtState && + markProjectDirty) + return true; + + return false; + } + + void ReaperContext::renderImportItems() + { + main_OnCommand(42230, 0); + } + + std::vector<WwiseTransfer::Import::Item> ReaperContext::getImportItems(WwiseTransfer::Import::Options options) + { + using namespace ReaperContextConstants; + + auto projectInfo = getProjectInfo(); + + auto renderDirectoryPath = getProjectString(projectInfo.projectReference, "RENDER_FILE", defaultBufferSize); + auto renderPattern = getProjectString(projectInfo.projectReference, "RENDER_PATTERN", defaultBufferSize); + + // There are several scenarios where the render pattern could be empty + // 1. When the project hasn't been saved (reaper uses "untitled") + // 2. When the project has been saved (reaper uses the project name) + if(renderPattern.isEmpty()) + { + if(projectInfo.projectPath.isEmpty()) + { + renderPattern = defaultRenderPattern; + } + else + { + renderPattern = projectInfo.projectName; + } + } + + juce::File renderDirectory; + if(juce::File::isAbsolutePath(renderDirectoryPath)) + { + renderDirectory = juce::File(renderDirectoryPath); + } + else if(projectInfo.projectPath.isNotEmpty()) + { + renderDirectory = juce::File(projectInfo.projectPath).getParentDirectory().getChildFile(renderDirectoryPath); + } + else + { + // If the project wasnt saved, reaper uses a general render directory + renderDirectory = defaultRenderDirectory.getChildFile(renderDirectoryPath); + } + + auto renderDirectoryPathPart = renderDirectoryPath.isNotEmpty() ? renderDirectoryPath + juce::File::getSeparatorString() : ""; + auto originalsSubfolderPathPart = options.originalsSubfolder.isNotEmpty() ? options.originalsSubfolder + juce::File::getSeparatorString() : ""; + + auto resolvedRenderPaths = getItemListFromRenderPattern(projectInfo.projectReference, renderDirectoryPathPart + renderPattern); + auto resolvedRenderPathsWithOriginalsSubfolder = getItemListFromRenderPattern(projectInfo.projectReference, renderDirectoryPathPart + originalsSubfolderPathPart + renderPattern); + + if(resolvedRenderPaths.size() != resolvedRenderPathsWithOriginalsSubfolder.size()) + { + juce::Logger::writeToLog("Reaper: Mismatch between resolvedRenderPaths and resolvedRenderPathsWithOriginalsSubfolder"); + return {}; + } + + // Estimate the size of render stats so we can pass reaper the propper buffer size + int totalBufferSize = 0; + int extra = 150; // Each path may come with aditional render statistics (peak information). + for(const auto& resolvedRenderPath : resolvedRenderPaths) + { + totalBufferSize += resolvedRenderPath.length() + extra; + } + + // Get list of files that where rendered during the last render run using the current render settings and render pattern + // These file names may differ from the resolved render paths due to silent renaming. + juce::StringArray finalRenderPaths; + + if(totalBufferSize > 0) + { + juce::String renderStats = getProjectString(projectInfo.projectReference, "RENDER_STATS", totalBufferSize); + + juce::StringArray temp; + temp.addTokens(renderStats, ";", ""); + + // Not all items in here are paths. Paths are prefixed with "FILE:" + for(auto item : temp) + { + if(item.startsWith("FILE:")) + finalRenderPaths.add(item.trimCharactersAtStart("FILE:")); + } + } + + std::vector<WwiseTransfer::Import::Item> importItems; + + auto resolvePattern = options.importDestination + options.hierarchyMappingPath; + + std::vector<juce::String> resolvedObjectPaths = getItemListFromRenderPattern(projectInfo.projectReference, resolvePattern, false); + + if(resolvedObjectPaths.size() != resolvedRenderPaths.size() || resolvedObjectPaths.size() != resolvedRenderPathsWithOriginalsSubfolder.size()) + { + juce::Logger::writeToLog("Reaper: Mismatch between resolvedObjectPaths, resolvedRenderPaths and resolvedRenderPathsWithOriginalsSubfolder"); + return {}; + } + + for(int i = 0; i < resolvedObjectPaths.size(); ++i) + { + juce::String objectPath(resolvedObjectPaths[i].upToLastOccurrenceOf(".", false, false)); + + juce::File parentDirectory = juce::File(resolvedRenderPathsWithOriginalsSubfolder[i]) + .getParentDirectory(); + + juce::String currentOriginalsSubfolder = parentDirectory == renderDirectory ? "" : parentDirectory.getRelativePathFrom(renderDirectory); + + auto objectName = WwiseTransfer::WwiseHelper::pathToObjectName(objectPath); + + importItems.emplace_back(objectName, + WwiseTransfer::Wwise::ObjectType::SoundSFX, + objectPath, + currentOriginalsSubfolder, + resolvedRenderPaths[i], + finalRenderPaths[i]); + } + + return importItems; + } + + juce::String ReaperContext::getProjectString(ReaProject* project, const char* key, int bufferSize) + { + std::string buffer(bufferSize, '\0'); + + if(getSetProjectInfo_String(project, key, &buffer[0], false)) + { + auto end = buffer.find('\0'); + buffer.resize(end); + return buffer; + } + + return juce::String(); + } + + ProjectInfo ReaperContext::getProjectInfo() + { + std::string buffer(ReaperContextConstants::defaultBufferSize, '\0'); + + ReaProject* projectReference; + + // The buffer sent to enumProjects will contain the project path. It is a requirement that a project file ends with the .rpp (case insensitive) file extension. + while((projectReference = enumProjects(-1, &buffer[0], buffer.size())) && !juce::String(buffer).endsWithIgnoreCase(".rpp")) + { + if(buffer.size() > 10 << 20 || buffer.empty()) + { + jassertfalse; + + return {}; + } + else + { + try + { + buffer.resize(2 * buffer.size()); + } + catch(std::bad_alloc&) + { + jassertfalse; + + return {}; + } + } + } + + juce::File projectFile(buffer); + + return { + projectReference, + projectFile.getFileNameWithoutExtension(), + projectFile.getFullPathName()}; + } + + std::vector<juce::String> ReaperContext::getItemListFromRenderPattern(ReaProject* project, const juce::String& pattern, bool suppressIllegalPaths) + { + int bufferLength = resolveRenderPattern(project, suppressIllegalPaths ? "" : nullptr, pattern.toUTF8(), nullptr, 0); + std::string buffer(bufferLength, '\0'); + + resolveRenderPattern(project, suppressIllegalPaths ? "" : nullptr, pattern.toUTF8(), &buffer[0], bufferLength); + return splitDoubleNullTerminatedString(&buffer[0]); + } +} // namespace AK::ReaWwise diff --git a/src/extension/ReaperContext.h b/src/extension/ReaperContext.h @@ -0,0 +1,62 @@ +#pragma once + +#include "Core/DawContext.h" +#include "Model/Import.h" + +#include <reaper_plugin_functions.h> + +namespace AK::ReaWwise +{ + struct ProjectInfo + { + ReaProject* projectReference; + juce::String projectName; + juce::String projectPath; + }; + + class ReaperContext + : public WwiseTransfer::DawContext + { + public: + ReaperContext(reaper_plugin_info_t* pluginInfo); + + juce::String getSessionName() override; + bool saveState(juce::ValueTree applicationState) override; + juce::ValueTree retrieveState() override; + void renderImportItems() override; + std::vector<WwiseTransfer::Import::Item> getImportItems(WwiseTransfer::Import::Options options) override; + + // Reaper api for public use + bool isValid(); + int callerVersion(); + decltype(GetMainHwnd) getMainHwnd; + decltype(ShowConsoleMsg) showConsoleMsg; + decltype(AddExtensionsMainMenu) addExtensionsMainMenu; + decltype(EnumProjects) enumProjects; + decltype(GetSetProjectInfo_String) getSetProjectInfo_String; + decltype(GetProjectName) getProjectName; + decltype(ResolveRenderPattern) resolveRenderPattern; + decltype(EnumProjectMarkers2) enumProjectMarkers2; + decltype(EnumRegionRenderMatrix) enumRegionRenderMatrix; + decltype(GetParentTrack) getParentTrack; + decltype(GetTrackName) getTrackName; + decltype(Main_OnCommand) main_OnCommand; + decltype(GetProjectPathEx) getProjectPathEx; + decltype(ShowMessageBox) showMessageBox; + decltype(GetProjExtState) getProjExtState; + decltype(SetProjExtState) setProjExtState; + decltype(MarkProjectDirty) markProjectDirty; + int registerFunction(const char* command, void* function); + + private: + std::vector<juce::String> splitDoubleNullTerminatedString(const char*); + std::vector<juce::String> getItemListFromRenderPattern(ReaProject* project, const juce::String& pattern, bool suppressIllegalPaths = true); + juce::String getProjectString(ReaProject* project, const char* key, int bufferSize); + ProjectInfo getProjectInfo(); + + juce::File defaultRenderDirectory; + juce::String defaultRenderPattern; + + reaper_plugin_info_t* pluginInfo; + }; +} // namespace AK::ReaWwise diff --git a/src/shared/CMakeLists.txt b/src/shared/CMakeLists.txt @@ -0,0 +1,83 @@ +include(Helpers) + +project(WwiseTransfer_Shared) + +file(GLOB_RECURSE SHARED_SOURCES + "${PROJECT_SOURCE_DIR}/*.h" + "${PROJECT_SOURCE_DIR}/*.cpp") + +add_library(${PROJECT_NAME}) + +find_package(Git REQUIRED) +if(Git_FOUND) + execute_process( + COMMAND ${GIT_EXECUTABLE} rev-parse --short HEAD + RESULT_VARIABLE result + OUTPUT_VARIABLE COMMIT_HASH) + + execute_process( + COMMAND ${GIT_EXECUTABLE} rev-parse --abbrev-ref HEAD + RESULT_VARIABLE result + OUTPUT_VARIABLE BRANCH_NAME) + + string(REPLACE "\n" "" COMMIT_HASH ${COMMIT_HASH}) + string(REPLACE "\n" "" BRANCH_NAME ${BRANCH_NAME}) +endif() + +if(DEFINED ENV{VERSION}) + set(VERSION $ENV{VERSION}) +else() + set(VERSION "Unofficial") +endif() + +if(DEFINED ENV{BUILD_NUMBER}) + set(BUILD_NUMBER $ENV{BUILD_NUMBER}) +else() + set(BUILD_NUMBER "Local") +endif() + +set(VERSION_STRING "${VERSION} ${COMMIT_HASH}") + +string(TIMESTAMP year "%Y") +add_compile_definitions(YEAR="${year}") + +target_sources(${PROJECT_NAME} PRIVATE ${SHARED_SOURCES}) + +target_include_directories(${PROJECT_NAME} + PUBLIC + ${PROJECT_SOURCE_DIR}/ +) + +find_package(Wwise REQUIRED) +find_package(AkAutobahn REQUIRED) + +file(GLOB RESOURCES "${PROJECT_SOURCE_DIR}/Theme/*/*.*") + +juce_add_binary_data(WwiseTransfer_BinaryData + SOURCES ${RESOURCES}) + +target_link_libraries(${PROJECT_NAME} + PUBLIC + WwiseTransfer_BinaryData + RapidJSON + AkAutobahn + juce::juce_gui_basics + Wwise +) + +target_compile_definitions(${PROJECT_NAME} + PRIVATE + JUCE_STANDALONE_APPLICATION=0 + PUBLIC + JUCE_MANUFACTURER_NAME_STRING="Audiokinetic" + JUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1 + JUCE_DISPLAY_SPLASH_SCREEN=0 + JUCE_APPLICATION_VERSION_STRING="${VERSION}" + BRANCH_NAME="${BRANCH_NAME}" + BUILD_NUMBER="${BUILD_NUMBER}" + COMMIT_HASH="${COMMIT_HASH}" +) + +source_group(TREE ${PROJECT_SOURCE_DIR} PREFIX "Source Files" FILES ${SHARED_SOURCES}) + +build_juce_source_groups() +\ No newline at end of file diff --git a/src/shared/Core/AssertHook.cpp b/src/shared/Core/AssertHook.cpp @@ -0,0 +1,20 @@ +#include "AK/Tools/Common/AkAssert.h" + +#include <cassert> +#include <stdio.h> + +#ifdef AK_ENABLE_ASSERTS + +namespace AK::WwiseTransfer +{ + void AssertHook(const char* in_pszExpression, const char* in_pszFileName, int in_lineNumber) + { + char buff[1024]; + snprintf(buff, sizeof(buff), "AKASSERT: %s, %s - %d", in_pszExpression, in_pszFileName, in_lineNumber); + assert(0 && buff); + } +} // namespace AK::WwiseTransfer + +AkAssertHook g_pAssertHook = AK::WwiseTransfer::AssertHook; + +#endif diff --git a/src/shared/Core/DawContext.h b/src/shared/Core/DawContext.h @@ -0,0 +1,21 @@ +#pragma once + +#include "Model/Import.h" + +#include <juce_gui_basics/juce_gui_basics.h> +#include <vector> + +namespace AK::WwiseTransfer +{ + class DawContext + { + public: + virtual ~DawContext() = default; + + virtual juce::String getSessionName() = 0; + virtual bool saveState(juce::ValueTree applicationState) = 0; + virtual juce::ValueTree retrieveState() = 0; + virtual void renderImportItems() = 0; + virtual std::vector<Import::Item> getImportItems(Import::Options options) = 0; + }; +} // namespace AK::WwiseTransfer diff --git a/src/shared/Core/DawWatcher.cpp b/src/shared/Core/DawWatcher.cpp @@ -0,0 +1,245 @@ +#include "DawWatcher.h" + +#include "Helpers/ImportHelper.h" +#include "Model/IDs.h" +#include "Model/Import.h" +#include "Model/Waapi.h" + +#include <juce_gui_basics/juce_gui_basics.h> +#include <optional> +#include <unordered_map> + +namespace AK::WwiseTransfer +{ + struct PreviewOptions + { + Import::ContainerNameExistsOption containerNameExists; + juce::String projectPath; + juce::String originalsFolder; + bool waqlEnabled; + juce::String languageSubfolder; + }; + + DawWatcher::DawWatcher(juce::ValueTree appState, WaapiClient& waapiClient, DawContext& dawContext, int refreshInterval) + : juce::Thread("DawWatcher") + , applicationState(appState) + , hierarchyMapping(appState.getChildWithName(IDs::hierarchyMapping)) + , importDestination(appState, IDs::importDestination, nullptr) + , originalsSubfolder(appState, IDs::originalsSubfolder, nullptr) + , containerNameExists(appState, IDs::containerNameExists, nullptr) + , wwiseObjectsChanged(appState, IDs::wwiseObjectsChanged, nullptr) + , previewLoading(appState, IDs::previewLoading, nullptr) + , dawContext(dawContext) + , waapiClient(waapiClient) + , previewItems(appState.getChildWithName(IDs::previewItems)) + , refreshInterval(refreshInterval) + , lastImportItemsFromDawHash(0) + , sessionName(appState, IDs::sessionName, nullptr) + , projectPath(appState, IDs::projectPath, nullptr) + , originalsFolder(appState, IDs::originalsFolder, nullptr) + , languageSubfolder(appState, IDs::languageSubfolder, nullptr) + { + auto featureSupport = appState.getChildWithName(IDs::featureSupport); + waqlEnabled.referTo(featureSupport, IDs::sessionName, nullptr); + + applicationState.addListener(this); + } + + DawWatcher::~DawWatcher() + { + applicationState.removeListener(this); + } + + void DawWatcher::start() + { + startThread(); + } + + void DawWatcher::stop() + { + stopThread(-1); + } + + void DawWatcher::run() + { + while(!threadShouldExit()) + { + updateSessionName(); + + std::optional<Import::Options> importOptions; + std::optional<PreviewOptions> previewOptions; + + { + juce::MessageManager::Lock l; + + auto hierarchyMappingPath = ImportHelper::hierarchyMappingToPath(ImportHelper::valueTreeToHierarchyMappingNodeList(hierarchyMapping)); + + importOptions = Import::Options(importDestination, originalsSubfolder, hierarchyMappingPath); + previewOptions = PreviewOptions{containerNameExists, projectPath, originalsFolder, waqlEnabled, languageSubfolder}; + } + + if(importOptions && previewOptions) + { + auto importItemsFromDaw = dawContext.getImportItems(*importOptions); + + auto currentImportItemsFromDawHash = ImportHelper::importItemsToHash(importItemsFromDaw); + + if(lastImportItemsFromDawHash != currentImportItemsFromDawHash || previewOptionsChanged) + { + setPreviewLoading(true); + previewOptionsChanged.store(false); + + lastImportItemsFromDawHash = currentImportItemsFromDawHash; + + std::set<juce::String> objectPaths; + std::unordered_map<juce::String, juce::ValueTree> pathToValueTreeMapping; + + juce::ValueTree rootNode(IDs::previewItems); + + // Build tree based on import items and their ancestors + for(const auto& importItem : importItemsFromDaw) + { + auto currentNode = rootNode; + + for(const auto& ancestorPath : WwiseHelper::pathToAncestorPaths(importItem.path)) + { + auto pathWithoutType = WwiseHelper::pathToPathWithoutObjectTypes(ancestorPath); + auto child = currentNode.getChildWithName(pathWithoutType); + + if(!child.isValid()) + { + objectPaths.insert(pathWithoutType); + + auto name = WwiseHelper::pathToObjectName(pathWithoutType); + auto type = WwiseHelper::pathToObjectType(ancestorPath); + + child = ImportHelper::previewItemToValueTree(pathWithoutType, {name, type, Import::ObjectStatus::New, "", Import::WavStatus::Unknown}); + + currentNode.appendChild(child, nullptr); + pathToValueTreeMapping[pathWithoutType] = child; + } + + currentNode = child; + } + + auto pathWithoutType = WwiseHelper::pathToPathWithoutObjectTypes(importItem.path); + objectPaths.insert(pathWithoutType); + + auto name = WwiseHelper::pathToObjectName(importItem.path); + auto type = WwiseHelper::pathToObjectType(importItem.path); + + auto originalsWav = previewOptions->languageSubfolder + juce::File::getSeparatorChar() + + (importItem.originalsSubFolder.isNotEmpty() ? importItem.originalsSubFolder + juce::File::getSeparatorChar() : "") + + juce::File(importItem.audioFilePath).getFileName(); + + auto wavStatus = Import::WavStatus::Unknown; + + if(previewOptions->originalsFolder.isNotEmpty()) + { + auto absoluteWavPath = juce::File(previewOptions->originalsFolder).getChildFile(originalsWav); + + if(absoluteWavPath.exists()) + wavStatus = Import::WavStatus::Replaced; + else + wavStatus = Import::WavStatus::New; + } + + auto child = ImportHelper::previewItemToValueTree(pathWithoutType, {name, type, Import::ObjectStatus::New, originalsWav, wavStatus}); + + currentNode.appendChild(child, nullptr); + pathToValueTreeMapping[pathWithoutType] = child; + } + + Waapi::Response<Waapi::ObjectResponseSet> response; + + if(importOptions->importDestination.isNotEmpty()) + { + if(previewOptions->waqlEnabled) + response = waapiClient.getObjectAncestorsAndDescendants(importOptions->importDestination); + else + response = waapiClient.getObjectAncestorsAndDescendantsLegacy(importOptions->importDestination); + } + + if(response.status) + { + auto pathToValueTreeMappingLocal = pathToValueTreeMapping; + + // Update original tree with information from existing objects + for(const auto& existingObject : response.result) + { + auto it = pathToValueTreeMappingLocal.find(existingObject.path); + + if(it != pathToValueTreeMappingLocal.end()) + { + auto previewItem = ImportHelper::valueTreeToPreviewItem(it->second); + + if(existingObject.type != Wwise::ObjectType::Sound || previewOptions->containerNameExists == Import::ContainerNameExistsOption::UseExisting) + previewItem.objectStatus = Import::ObjectStatus::NoChange; + else if(previewOptions->containerNameExists == Import::ContainerNameExistsOption::Replace) + previewItem.objectStatus = Import::ObjectStatus::Replaced; + else if(previewOptions->containerNameExists == Import::ContainerNameExistsOption::CreateNew) + previewItem.objectStatus = Import::ObjectStatus::NewRenamed; + + if(previewItem.type == Wwise::ObjectType::Unknown) + { + previewItem.type = existingObject.type; + } + + it->second.copyPropertiesFrom(ImportHelper::previewItemToValueTree(existingObject.path, previewItem), nullptr); + } + } + } + + // Update preview tree. This will cause the preview to update itself if there is new content + auto onCallAsync = [this, rootNode = rootNode] + { + if(!previewItems.isEquivalentTo(rootNode)) + previewItems.copyPropertiesAndChildrenFrom(rootNode, nullptr); + }; + + juce::MessageManager::callAsync(onCallAsync); + + setPreviewLoading(false); + } + } + + wait(refreshInterval); + } + } + + void DawWatcher::setPreviewLoading(bool isPreviewLoading) + { + auto onCallAsync = [this, isPreviewLoading] + { + previewLoading = isPreviewLoading; + }; + + juce::MessageManager::callAsync(onCallAsync); + } + + void DawWatcher::updateSessionName() + { + auto name = dawContext.getSessionName(); + + auto updateSessionName = [this, name = name] + { + sessionName = name; + }; + + juce::MessageManager::callAsync(updateSessionName); + } + + void DawWatcher::valueTreePropertyChanged(juce::ValueTree& treeWhosePropertyHasChanged, const juce::Identifier& property) + { + static std::initializer_list<juce::Identifier> properties{IDs::containerNameExists, IDs::projectPath, IDs::originalsFolder, + IDs::wwiseObjectsChanged, IDs::waqlEnabled, IDs::languageSubfolder}; + + if(treeWhosePropertyHasChanged == applicationState && std::find(properties.begin(), properties.end(), property) != properties.end()) + { + previewOptionsChanged.store(true); + + if(property == IDs::wwiseObjectsChanged) + wwiseObjectsChanged = false; + } + } +} // namespace AK::WwiseTransfer diff --git a/src/shared/Core/DawWatcher.h b/src/shared/Core/DawWatcher.h @@ -0,0 +1,53 @@ +#pragma once + +#include "Core/DawContext.h" +#include "WaapiClient.h" + +#include <juce_gui_basics/juce_gui_basics.h> + +namespace AK::WwiseTransfer +{ + class DawWatcher + : private juce::Thread + , private juce::ValueTree::Listener + { + public: + DawWatcher(juce::ValueTree appState, WaapiClient& waapiClient, DawContext& dawContext, int refreshInterval); + ~DawWatcher(); + + void start(); + void stop(); + + juce::ValueTree hierarchyMapping; + juce::CachedValue<juce::String> importDestination; + juce::CachedValue<juce::String> originalsSubfolder; + juce::CachedValue<Import::ContainerNameExistsOption> containerNameExists; + juce::CachedValue<bool> wwiseObjectsChanged; + juce::CachedValue<bool> previewLoading; + juce::CachedValue<juce::String> sessionName; + juce::CachedValue<bool> waqlEnabled; + juce::CachedValue<juce::String> projectPath; + juce::CachedValue<juce::String> originalsFolder; + juce::CachedValue<juce::String> languageSubfolder; + + juce::ValueTree previewItems; + + unsigned int lastImportItemsFromDawHash; + Import::ContainerNameExistsOption lastContainerNameExists; + juce::String lastProjectPath; + + private: + juce::ValueTree applicationState; + + std::atomic<bool> previewOptionsChanged; + + DawContext& dawContext; + WaapiClient& waapiClient; + int refreshInterval; + + void run() override; + void setPreviewLoading(bool isPreviewLoading); + void updateSessionName(); + void valueTreePropertyChanged(juce::ValueTree& treeWhosePropertyHasChanged, const juce::Identifier& property) override; + }; +} // namespace AK::WwiseTransfer diff --git a/src/shared/Core/ImportTask.h b/src/shared/Core/ImportTask.h @@ -0,0 +1,212 @@ +#pragma once + +#include "Helpers/ImportHelper.h" +#include "Model/Import.h" +#include "WaapiClient.h" + +#include <vector> + +namespace AK::WwiseTransfer +{ + namespace ImportTaskContants + { + const juce::String defaultObjectLanguage = "SFX"; + } + + template <class Callback> + class ImportTask : public juce::ThreadWithProgressWindow + { + public: + ImportTask(WaapiClient& waapiClient, const Import::Task::Options& options, Callback callback) + : juce::ThreadWithProgressWindow("Importing...", true, false) + , waapiClient(waapiClient) + , options(options) + , callback(callback) + { + // Set progress to -1 one to show infinite progress bar + setProgress(-1); + } + + void run() override + { + using namespace AK::WwiseAuthoringAPI; + + using ObjectPath = juce::String; + using PropertyTemplatePath = juce::String; + + Import::Summary summary; + + auto containerNameExistsOptionAsString = ImportHelper::containerNameExistsOptionToString(options.containerNameExistsOption); + + std::vector<Waapi::ImportItemRequest> importItemRequests; + + // Holds all paths to objects defined in the extension (including ancestors) + std::set<ObjectPath> objectsInExtension; + + for(const auto& importItem : options.importItems) + { + importItemRequests.emplace_back(Waapi::ImportItemRequest{importItem.path, importItem.originalsSubFolder, importItem.renderFilePath}); + + auto pathWithoutObjectTypes = WwiseHelper::pathToPathWithoutObjectTypes(importItem.path); + objectsInExtension.insert(pathWithoutObjectTypes); + + for(auto ancestorPath : WwiseHelper::pathToAncestorPaths(pathWithoutObjectTypes)) + { + objectsInExtension.insert(ancestorPath); + } + } + + // Will be eventullay compared to the results of the import to figure out what was newly created + Waapi::Response<Waapi::ObjectResponseSet> existingObjectsResponse; + + if(options.waqlEnabled) + existingObjectsResponse = waapiClient.getObjectAncestorsAndDescendants(options.importDestination); + else + existingObjectsResponse = waapiClient.getObjectAncestorsAndDescendantsLegacy(options.importDestination); + + if(existingObjectsResponse.status) + { + for(const auto& object : existingObjectsResponse.result) + { + // We only care about objects defined in the extension + auto it = objectsInExtension.find(object.path); + + if(it != objectsInExtension.end()) + { + // Create an entry in the summary data structure (It will eventually be used to produce the import summary page) + // Ignore sounds that would be newly created. We need to get their paths from the import response because they may change. + if(options.containerNameExistsOption != Import::ContainerNameExistsOption::CreateNew || object.type != Wwise::ObjectType::Sound) + { + summary.objects[object.path].type = object.type; + summary.objects[object.path].newlyCreated = false; + } + } + }; + + if(options.undoGroupFeatureEnabled) + waapiClient.beginUndoGroup(); + + juce::String objectLanguage = ImportTaskContants::defaultObjectLanguage; + if(options.hierarchyMappingNodeList.back().type == Wwise::ObjectType::SoundVoice) + objectLanguage = options.hierarchyMappingNodeList.back().language; + + auto importResponse = waapiClient.import(importItemRequests, options.containerNameExistsOption, objectLanguage); + + if(importResponse.status) + { + // Anything that is returned here was newly created + for(const auto& object : importResponse.result) + { + summary.objectsCreated++; + + summary.objects[object.path].type = object.type; + summary.objects[object.path].newlyCreated = true; + + // Audio file sources represent imported wav files + if(object.type == Wwise::ObjectType::AudioFileSource) + { + summary.audioFilesImported++; + + summary.objects[object.path].originalWavFilePath = object.originalWavFilePath; + } + } + + // Applying templates only works in custom hierarchy mapping mode + if(options.applyTemplateFeatureEnabled) + { + // Will store node depth in relation to template property path + std::map<int, juce::String> depthToTemplatePropertyPathMap; + + int importDestinationDepth = WwiseHelper::pathToPathParts(options.importDestination).size(); + + for(int i = 0; i < options.hierarchyMappingNodeList.size(); ++i) + { + const auto& hierarchyMappingNode = options.hierarchyMappingNodeList[i]; + + if(hierarchyMappingNode.propertyTemplatePath.isNotEmpty() && + hierarchyMappingNode.propertyTemplatePathEnabled && + hierarchyMappingNode.propertyTemplatePathValid) + { + depthToTemplatePropertyPathMap[importDestinationDepth + i + 1] = hierarchyMappingNode.propertyTemplatePath; + } + } + + if(depthToTemplatePropertyPathMap.size() > 0) + { + std::map<PropertyTemplatePath, std::vector<ObjectPath>> propertyTemplatePathToObjectMapping; + + // Go through all objects and if their depth matches a hierarchy node that has a template defined in it, add it to propertyTemplatePathToObjectMapping + // We will eventually use this map to submit paste property requests in waaapi + for(const auto& [objectPath, object] : summary.objects) + { + const int depth = WwiseHelper::pathToPathParts(objectPath).size(); + + auto it = depthToTemplatePropertyPathMap.find(depth); + + if(it != depthToTemplatePropertyPathMap.end() && (options.applyTemplateOption == Import::ApplyTemplateOption::Always || object.newlyCreated)) + { + propertyTemplatePathToObjectMapping[it->second].emplace_back(objectPath); + } + } + + for(const auto& [source, targets] : propertyTemplatePathToObjectMapping) + { + auto response = waapiClient.pasteProperties({source, targets}); + + if(!response.status) + { + summary.errorMessage << juce::NewLine() << response.errorMessage; + } + else + { + for(const auto& target : targets) + { + summary.objectTemplatesApplied++; + + summary.objects[target].propertyTemplatePath = source; + } + } + } + } + } + + if(importResponse.result.size() > 0) + { + std::vector<juce::String> importedObjectPaths; + + // Assumes that importResponse.result is sorted by path + auto first = importResponse.result.begin()->path; + auto last = importResponse.result.rbegin()->path; + + importedObjectPaths.emplace_back(WwiseHelper::getCommonAncestor(first, last)); + + waapiClient.selectObjects(options.selectObjectsOnImportCommand, importedObjectPaths); + } + } + else + { + summary.errorMessage << juce::NewLine() << importResponse.errorMessage; + } + } + else + { + summary.errorMessage << juce::NewLine() << existingObjectsResponse.errorMessage; + } + + if(options.undoGroupFeatureEnabled) + waapiClient.endUndoGroup("Import and Apply Paste Properties"); + + auto onCallAsync = [this, summary = summary] + { + callback(summary); + }; + + juce::MessageManager::callAsync(onCallAsync); + } + + private: + WaapiClient& waapiClient; + Import::Task::Options options; + Callback callback; + }; +} // namespace AK::WwiseTransfer diff --git a/src/shared/Core/Logger.cpp b/src/shared/Core/Logger.cpp @@ -0,0 +1,41 @@ +#include "Logger.h" + +namespace AK::WwiseTransfer +{ + Logger::Logger(const juce::String& applicationName) + : juce::FileLogger(getSystemLogFileFolder().getChildFile(applicationName) +#ifdef WIN32 + .getChildFile("Logs") // System log file folder for windows is generic app data folder. Add subfolder for logs. +#endif + .getChildFile("Log_" + juce::Time::getCurrentTime().formatted("%Y-%m-%d")) + .withFileExtension(".txt"), + applicationName + " Log") + { + } + + void Logger::logMessage(const juce::String& message) + { + juce::String messageWithTimeStamp; + + messageWithTimeStamp << juce::Time::getCurrentTime().formatted("%Y-%m-%d %H:%M:%S") << " " << message; + + juce::FileLogger::logMessage(messageWithTimeStamp); + + auto onLogMessage = [&](IListener& listener) + { + listener.onLogMessage(messageWithTimeStamp); + }; + + listeners.call(onLogMessage); + } + + void Logger::addListener(IListener& listener) + { + listeners.add(&listener); + }; + + void Logger::removeListener(IListener& listener) + { + listeners.remove(&listener); + } +} // namespace AK::WwiseTransfer diff --git a/src/shared/Core/Logger.h b/src/shared/Core/Logger.h @@ -0,0 +1,29 @@ +#pragma once + +#include <juce_gui_basics/juce_gui_basics.h> + +namespace AK::WwiseTransfer +{ + class Logger : public juce::FileLogger + { + public: + Logger(const juce::String& applicationName); + + class IListener + { + public: + virtual ~IListener() = default; + + virtual void onLogMessage(const juce::String& message) = 0; + }; + + void addListener(IListener& listener); + void removeListener(IListener& listener); + + protected: + void logMessage(const juce::String& message) override; + + private: + juce::ListenerList<IListener> listeners; + }; +} // namespace AK::WwiseTransfer diff --git a/src/shared/Core/WaapiClient.cpp b/src/shared/Core/WaapiClient.cpp @@ -0,0 +1,950 @@ +#include "WaapiClient.h" + +#include "Helpers/ImportHelper.h" +#include "Model/IDs.h" + +#include <JSONHelpers.h> +#include <algorithm> +#include <juce_events/juce_events.h> +#include <memory> +#include <set> + +namespace AK::WwiseTransfer +{ + namespace WaapiCommands + { + static constexpr const char* const projectLoaded = "ak::wwise::core::project::loaded"; + static constexpr const char* const projectPostClosed = "ak::wwise::core::project::postClosed"; + static constexpr const char* const objectPostDeleted = "ak::wwise::core::object::postDeleted"; + static constexpr const char* const objectNameChanged = "ak::wwise::core::object::nameChanged"; + static constexpr const char* const objectCreated = "ak::wwise::core::object::created"; + static constexpr const char* const objectGet = "ak::wwise::core::object::get"; + static constexpr const char* const audioImport = "ak::wwise::core::audio::import"; + static constexpr const char* const getProjectInfo = "ak::wwise::core::getProjectInfo"; + static constexpr const char* const undoBeginGroup = "ak::wwise::core::undo::beginGroup"; + static constexpr const char* const undoCancelGroup = "ak::wwise::core::undo::cancelGroup"; + static constexpr const char* const undoEndGroup = "ak::wwise::core::undo::endGroup"; + static constexpr const char* const objectPasteProperties = "ak::wwise::core::object::pasteProperties"; + static constexpr const char* const getInfo = "ak::wwise::core::getInfo"; + static constexpr const char* const getSelectedObjects = "ak::wwise::ui::getSelectedObjects"; + static constexpr const char* const commandsExecute = "ak::wwise::ui::commands::execute"; + } // namespace WaapiCommands + + WaapiClientWatcher::WaapiClientWatcher(juce::ValueTree appState, WaapiClient& waapiClient, WaapiClientWatcherConfig waapiClientWatcherConfig) + : juce::Thread("WaapiService") + , applicationState(appState) + , projectId(applicationState, IDs::projectId, nullptr) + , waapiConnected(applicationState, IDs::waapiConnected, nullptr) + , wwiseObjectsChanged(applicationState, IDs::wwiseObjectsChanged, nullptr) + , waapiClient(waapiClient) + , waapiClientWatcherConfig(std::move(waapiClientWatcherConfig)) + , connectionRetryDelay(waapiClientWatcherConfig.MinConnectionRetryDelay) + , languages(applicationState.getChildWithName(IDs::languages)) + { + } + + void WaapiClientWatcher::start() + { + startThread(); + } + + void WaapiClientWatcher::stop() + { + stopThread(-1); + } + + void WaapiClientWatcher::run() + { + using namespace WwiseAuthoringAPI; + + auto onDisconnect = [this] + { + juce::Logger::writeToLog("Disconnected from waapi"); + + setWaapiConnected(false); + }; + + auto onProjectLoaded = [this](auto, auto) + { + juce::Logger::writeToLog("Received project loaded event"); + + setProjectId(""); + }; + + auto onProjectPostClosed = [this](auto, auto) + { + juce::Logger::writeToLog("Received project post close event"); + }; + + auto onObjectEvent = [this](auto, auto) + { + juce::Logger::writeToLog("Received object related event"); + + setWwiseObjectsChanged(true); + }; + + while(!threadShouldExit()) + { + int waitTime = waapiClientWatcherConfig.ConnectionMonitorDelay; + + if(!waapiClient.isConnected()) + { + if(waapiClient.connect(static_cast<const char*>(waapiClientWatcherConfig.Ip.toUTF8()), waapiClientWatcherConfig.Port, onDisconnect)) + { + juce::Logger::writeToLog("Connected to waapi"); + + connectionRetryDelay = waapiClientWatcherConfig.MinConnectionRetryDelay; + + AkJson subscribeResult; + if(waapiClient.subscribe(WaapiCommands::projectLoaded, AkJson::Map{}, onProjectLoaded, projectLoadedSubscriptionId, subscribeResult)) + { + juce::Logger::writeToLog("Subscribed to project loaded"); + } + else + { + juce::Logger::writeToLog("Failed to subscribed to project loaded"); + } + + if(waapiClient.subscribe(WaapiCommands::projectPostClosed, AkJson::Map{}, onProjectPostClosed, projectPostClosedSubscriptionId, subscribeResult)) + { + juce::Logger::writeToLog("Subscribed to project unloaded"); + } + else + { + juce::Logger::writeToLog("Failed to subscribed to project post closed"); + } + + if(waapiClient.subscribe(WaapiCommands::objectCreated, AkJson::Map{}, onObjectEvent, objectCreatedEventSubscriptionId, subscribeResult)) + { + juce::Logger::writeToLog("Subscribed to object created"); + } + else + { + juce::Logger::writeToLog("Failed to subscribed to object created"); + } + + if(waapiClient.subscribe(WaapiCommands::objectPostDeleted, AkJson::Map{}, onObjectEvent, objectPostDeletedEventSubscriptionId, subscribeResult)) + { + juce::Logger::writeToLog("Subscribed to object postDeleted"); + } + else + { + juce::Logger::writeToLog("Failed to subscribed to object postDeleted"); + } + + if(waapiClient.subscribe(WaapiCommands::objectNameChanged, AkJson::Map{}, onObjectEvent, objectNameChangedEventSubscriptionId, subscribeResult)) + { + juce::Logger::writeToLog("Subscribed to object nameChanged"); + } + else + { + juce::Logger::writeToLog("Failed to subscribed to object nameChanged"); + } + + setWaapiConnected(true); + } + else + { + waitTime = connectionRetryDelay; + connectionRetryDelay = juce::jmin(connectionRetryDelay * 2, waapiClientWatcherConfig.MaxConnectionRetryDelay); + + juce::String errorMessage("Error trying to connect to waapi ... Retrying in "); + + errorMessage << connectionRetryDelay << " ms"; + + juce::Logger::writeToLog(errorMessage); + } + } + + wait(waitTime); + } + if(waapiClient.isConnected()) + { + AkJson result; + if(waapiClient.unsubscribe(projectLoadedSubscriptionId, result)) + { + juce::Logger::writeToLog("Unsubscribed from project loaded"); + } + else + { + juce::Logger::writeToLog("Failed to unsubscribed from project unloaded"); + } + + if(waapiClient.unsubscribe(projectPostClosedSubscriptionId, result)) + { + juce::Logger::writeToLog("Unsubscribed from project post closed"); + } + else + { + juce::Logger::writeToLog("Failed to unsubscribed from project post closed"); + } + + if(waapiClient.unsubscribe(objectCreatedEventSubscriptionId, result)) + { + juce::Logger::writeToLog("Unsubscribed from object created"); + } + else + { + juce::Logger::writeToLog("Failed to unsubscribed from object created"); + } + + if(waapiClient.unsubscribe(objectPostDeletedEventSubscriptionId, result)) + { + juce::Logger::writeToLog("Unsubscribed from object postDeleted"); + } + else + { + juce::Logger::writeToLog("Failed to unsubscribed from object postDeleted"); + } + + if(waapiClient.unsubscribe(objectNameChangedEventSubscriptionId, result)) + { + juce::Logger::writeToLog("Unsubscribed from object postDeleted"); + } + else + { + juce::Logger::writeToLog("Failed to unsubscribed from object postDeleted"); + } + + setWaapiConnected(false); + + waapiClient.disconnect(); + } + } + void WaapiClientWatcher::setProjectId(const juce::String& id) + { + juce::Logger::writeToLog("Setting projectId"); + + auto onCallAsync = [this, id = id] + { + projectId = id; + // On the first run of the extension, the project ID will be empty. On project load we + // also explicetly set the id to empty so that Project Support knows it has to refresh the project data. + // The juce value tree will not send updates if the property doesnt change. Lets force it to send an update. + applicationState.sendPropertyChangeMessage(IDs::projectId); + }; + + juce::MessageManager::callAsync(onCallAsync); + } + + void WaapiClientWatcher::setWwiseObjectsChanged(bool changed) + { + juce::Logger::writeToLog("Setting wwise objects changed"); + + auto onCallAsync = [this, changed = changed] + { + wwiseObjectsChanged = changed; + }; + + juce::MessageManager::callAsync(onCallAsync); + } + + void WaapiClientWatcher::setWaapiConnected(bool connected) + { + juce::Logger::writeToLog("Setting waapi connected"); + + auto resetProjectInfo = [this, connected = connected] + { + waapiConnected = connected; + }; + + juce::MessageManager::callAsync(resetProjectInfo); + } + + WaapiClient::WaapiClient() + { + } + + bool WaapiClient::connect(const char* in_uri, unsigned int in_port, WwiseAuthoringAPI::disconnectHandler_t disconnectHandler, int in_timeoutMs) + { + return Connect(in_uri, in_port, disconnectHandler, in_timeoutMs); + } + + bool WaapiClient::subscribe(const char* in_uri, const WwiseAuthoringAPI::AkJson& in_options, WampEventCallback in_callback, uint64_t& out_subscriptionId, WwiseAuthoringAPI::AkJson& out_result, int in_timeoutMs) + { + return Subscribe(in_uri, in_options, in_callback, out_subscriptionId, out_result, in_timeoutMs); + } + + bool WaapiClient::unsubscribe(const uint64_t& in_subscriptionId, WwiseAuthoringAPI::AkJson& out_result, int in_timeoutMs) + { + return Unsubscribe(in_subscriptionId, out_result, in_timeoutMs); + } + + bool WaapiClient::isConnected() + { + return IsConnected(); + } + + void WaapiClient::disconnect() + { + Disconnect(); + } + + bool WaapiClient::call(const char* in_uri, const WwiseAuthoringAPI::AkJson& in_args, const WwiseAuthoringAPI::AkJson& in_options, WwiseAuthoringAPI::AkJson& out_result, int in_timeoutMs) + { + using namespace WwiseAuthoringAPI; + + auto status = Call(in_uri, in_args, in_options, out_result, in_timeoutMs); + + juce::Logger::writeToLog(juce::String(in_uri) + + juce::NewLine() + juce::String("args: ") + JSONHelpers::GetAkJsonString(in_args) + + juce::NewLine() + juce::String("options: ") + JSONHelpers::GetAkJsonString(in_options) + + juce::NewLine() + juce::String("result: ") + JSONHelpers::GetAkJsonString(out_result)); + + return status; + } + + bool WaapiClient::call(const char* in_uri, const char* in_args, const char* in_options, std::string& out_result, int in_timeoutMs) + { + auto status = Call(in_uri, in_args, in_options, out_result, in_timeoutMs); + + juce::Logger::writeToLog(juce::String(in_uri) + + juce::NewLine() + juce::String("args: ") + in_args + + juce::NewLine() + juce::String("options: ") + in_options + + juce::NewLine() + juce::String("result: ") + out_result); + + return status; + } + + Waapi::Response<Waapi::ObjectResponseSet> WaapiClient::getObjects(const std::set<juce::String>& objectPaths) + { + using namespace WwiseAuthoringAPI; + + Waapi::Response<Waapi::ObjectResponseSet> response; + + if(!objectPaths.empty()) + { + juce::String waql("where "); + + for(auto it = objectPaths.begin(); it != objectPaths.end(); ++it) + { + if(it != objectPaths.begin()) + waql << " or "; + waql << "path = \"" + << *it + << "\""; + } + + const auto args = AkJson::Map{ + { + "waql", + AkVariant{waql.toStdString()}, + }, + }; + + static const auto options = AkJson::Map{ + { + "return", + AkJson::Array{ + AkVariant{"id"}, + AkVariant{"name"}, + AkVariant{"type"}, + AkVariant{"path"}, + }, + }, + }; + + AkJson result; + response.status = call(WaapiCommands::objectGet, args, options, result); + + if(response.status) + { + if(result.HasKey("return")) + { + auto objects = result["return"].GetArray(); + + for(auto& object : objects) + { + response.result.emplace(object); + } + } + } + else + { + response.errorMessage << WaapiHelper::getErrorMessage(result); + } + } + + return response; + } + + Waapi::Response<Waapi::ObjectResponseSet> WaapiClient::import(const std::vector<Waapi::ImportItemRequest>& importItemsRequest, Import::ContainerNameExistsOption containerNameExistsOption, const juce::String& objectLanguage) + { + using namespace WwiseAuthoringAPI; + + Waapi::Response<Waapi::ObjectResponseSet> response; + + AkJson::Array importItemsAsJson; + for(const auto& importItemRequest : importItemsRequest) + { + auto importItemAsJson = AkJson(AkJson::Map{ + { + "audioFile", + AkVariant(importItemRequest.renderFilePath.toStdString()), + }, + { + "objectPath", + AkVariant(importItemRequest.path.toStdString()), + }, + { + "originalsSubFolder", + AkVariant(importItemRequest.originalsSubFolder.toStdString()), + }, + }); + + importItemsAsJson.push_back(importItemAsJson); + }; + + const auto args = AkJson::Map{ + { + "importOperation", + AkVariant(ImportHelper::containerNameExistsOptionToString(containerNameExistsOption).toStdString()), + }, + { + "default", + AkJson::Map{{"importLanguage", AkVariant(objectLanguage.toStdString())}}, + }, + { + "imports", + importItemsAsJson, + }, + { + "autoAddToSourceControl", + AkVariant(true), + }, + }; + + static const auto options = AkJson::Map{ + { + "return", + AkJson::Array{ + AkVariant{"id"}, + AkVariant{"name"}, + AkVariant{"type"}, + AkVariant{"path"}, + AkVariant{"sound:originalWavFilePath"}, + }, + }, + }; + + AkJson result; + response.status = call(WaapiCommands::audioImport, args, options, result); + + if(response.status) + { + if(result.HasKey("objects")) + { + auto objects = result["objects"].GetArray(); + + for(auto& object : objects) + { + response.result.emplace(object); + } + } + } + else + { + response.errorMessage << WaapiHelper::getErrorMessage(result); + } + + return response; + } + + bool WaapiClient::selectObjects(const juce::String& selectObjectsOnImportCommand, const std::vector<juce::String>& objectPaths) + { + using namespace WwiseAuthoringAPI; + + AkJson::Array objects; + for(const auto& objectPath : objectPaths) + { + objects.emplace_back(AkVariant(objectPath.toStdString())); + } + + const auto args = AkJson::Map{ + { + "command", + AkVariant(selectObjectsOnImportCommand.toStdString()), + }, + { + "objects", + objects, + }, + }; + + AkJson result; + return call(WaapiCommands::commandsExecute, args, AkJson::Map{}, result); + } + + Waapi::Response<Waapi::ObjectResponseSet> WaapiClient::getObjectAncestorsAndDescendants(const juce::String& objectPath) + { + using namespace WwiseAuthoringAPI; + + Waapi::Response<Waapi::ObjectResponseSet> response; + + auto waql = juce::String("\"" + objectPath + "\" select this, ancestors, descendants"); + + const auto args = AkJson::Map{ + { + "waql", + AkVariant{waql.toStdString()}, + }, + }; + + static const auto options = AkJson::Map{ + { + "return", + AkJson::Array{ + AkVariant{"id"}, + AkVariant{"name"}, + AkVariant{"type"}, + AkVariant{"path"}, + }, + }, + }; + + AkJson result; + response.status = call(WaapiCommands::objectGet, args, options, result); + + if(!response.status) + { + // The waql query above will fail if the object was not found. + // We still want to know if ancestors exist. + auto objectAncestors = WwiseHelper::pathToAncestorPaths(objectPath); + + for(int i = objectAncestors.size() - 1; i >= 0; --i) + { + auto waql = juce::String("\"" + objectAncestors[i] + "\" select this, ancestors"); + + const auto args = AkJson::Map{ + { + "waql", + AkVariant{waql.toStdString()}, + }, + }; + + response.status = call(WaapiCommands::objectGet, args, options, result); + + if(response.status) + break; + } + } + if(response.status) + { + if(result.HasKey("return")) + { + auto objects = result["return"].GetArray(); + + for(auto& object : objects) + { + response.result.emplace(object); + } + } + } + else + { + response.errorMessage << WaapiHelper::getErrorMessage(result); + } + + return response; + } + Waapi::Response<std::vector<juce::String>> WaapiClient::getProjectLanguages() + { + using namespace WwiseAuthoringAPI; + + Waapi::Response<std::vector<juce::String>> response; + + static const auto args(AkJson::Map{ + { + "from", + AkJson::Map{ + { + "ofType", + AkJson::Array{ + {AkVariant("Language")}, + }, + }, + }, + }, + }); + + static const auto options(AkJson::Map{ + { + "return", + AkJson::Array{ + {AkVariant("name")}, + }, + }, + }); + + AkJson result; + response.status = call(WaapiCommands::objectGet, args, options, result); + + static const std::set<juce::String> exceptions = { + "Mixed", + "SFX", + "External", + "SoundSeed Grain", + }; + + if(response.status) + { + if(result.HasKey("return")) + { + auto objects = result["return"].GetArray(); + + for(auto& object : objects) + { + auto language = juce::String(object["name"].GetVariant().GetString()); + + if(exceptions.find(language) == exceptions.end()) + response.result.emplace_back(language); + } + } + } + else + { + response.errorMessage << WaapiHelper::getErrorMessage(result); + } + + return response; + } + + Waapi::Response<Waapi::ObjectResponseSet> WaapiClient::getObjectAncestorsAndDescendantsLegacy(const juce::String& objectPath) + { + using namespace WwiseAuthoringAPI; + + Waapi::Response<Waapi::ObjectResponseSet> response; + + static auto buildArgs = [](const juce::String& path) + { + auto from = AkJson::Map{ + { + "from", + AkJson::Map{ + { + "path", + AkJson::Array{ + AkVariant{path.toStdString()}, + }, + }, + }, + }, + }; + + return from; + }; + + static auto addTransform = [](AkJson::Map& args, const juce::String& transform) + { + args["transform"] = AkJson::Array{ + AkJson::Map{ + { + "select", + AkJson::Array{ + AkVariant{transform.toStdString()}, + }, + }, + }, + }; + }; + + static auto fillResponse = [](auto& response, const auto& result) + { + if(result.HasKey("return")) + { + auto objects = result["return"].GetArray(); + + for(auto& object : objects) + { + response.result.emplace(object); + } + } + }; + + static const auto options = AkJson::Map{ + { + "return", + AkJson::Array{ + AkVariant{"id"}, + AkVariant{"name"}, + AkVariant{"type"}, + AkVariant{"path"}, + }, + }, + }; + + auto args = buildArgs(objectPath); + + AkJson result; + response.status = call(WaapiCommands::objectGet, args, options, result); + + if(response.status) + fillResponse(response, result); + + args = buildArgs(objectPath); + addTransform(args, "descendants"); + + response.status = call(WaapiCommands::objectGet, args, options, result); + + if(response.status) + fillResponse(response, result); + + args = buildArgs(objectPath); + addTransform(args, "ancestors"); + + response.status = call(WaapiCommands::objectGet, args, options, result); + + if(response.status) + fillResponse(response, result); + else + { + auto objectAncestors = WwiseHelper::pathToAncestorPaths(objectPath); + + for(int i = objectAncestors.size() - 1; i >= 0; --i) + { + args = buildArgs(objectAncestors[i]); + + response.status = call(WaapiCommands::objectGet, args, options, result); + + if(response.status) + { + fillResponse(response, result); + + args = buildArgs(objectAncestors[i]); + addTransform(args, "ancestors"); + + response.status = call(WaapiCommands::objectGet, args, options, result); + + if(response.status) + { + fillResponse(response, result); + break; + } + } + } + } + + if(!response.status) + response.errorMessage << WaapiHelper::getErrorMessage(result); + + return response; + } + + Waapi::Response<juce::String> WaapiClient::getOriginalsFolder() + { + using namespace WwiseAuthoringAPI; + + Waapi::Response<juce::String> response; + + AkJson result; + response.status = call(WaapiCommands::getProjectInfo, AkJson::Map{}, AkJson::Map{}, result); + + if(result.HasKey("directories") && result["directories"].HasKey("originals")) + { + auto originalsFolder = juce::String(result["directories"]["originals"].GetVariant().GetString()); + +#ifndef WIN32 + // Waapi returns the path as a windows path + originalsFolder = originalsFolder.replace("\\", juce::File::getSeparatorString()).replace("Y:", "~").replace("Z:", "/"); +#endif + + response.result = originalsFolder; + } + + return response; + } + + void WaapiClient::beginUndoGroup() + { + using namespace WwiseAuthoringAPI; + + AkJson result; + call(WaapiCommands::undoBeginGroup, AkJson::Map{}, AkJson::Map{}, result); + } + + void WaapiClient::cancelUndoGroup() + { + using namespace WwiseAuthoringAPI; + + AkJson result; + call(WaapiCommands::undoCancelGroup, AkJson::Map{}, AkJson::Map{}, result); + } + + void WaapiClient::endUndoGroup(const juce::String& displayName) + { + using namespace WwiseAuthoringAPI; + + auto arguments = AkJson::Map{ + { + "displayName", + AkVariant{displayName.toUTF8()}, + }, + }; + + AkJson result; + call(WaapiCommands::undoEndGroup, arguments, AkJson::Map{}, result); + } + + Waapi::Response<Waapi::ObjectResponseSet> WaapiClient::pasteProperties(const Waapi::PastePropertiesRequest& pastePropertiesRequest) + { + using namespace WwiseAuthoringAPI; + + Waapi::Response<Waapi::ObjectResponseSet> response; + + AkJson::Array targets; + for(auto& target : pastePropertiesRequest.targets) + { + targets.push_back(AkVariant(target.toStdString())); + } + + const auto args(AkJson::Map{ + { + "source", + AkVariant(pastePropertiesRequest.source.toStdString()), + }, + { + "targets", + targets, + }, + }); + + AkJson result; + response.status = call(WaapiCommands::objectPasteProperties, args, AkJson::Map{}, result); + + if(!response.status) + { + response.errorMessage << juce::NewLine() << WaapiHelper::getErrorMessage(result); + } + + return response; + } + + Waapi::Response<Wwise::Version> WaapiClient::getVersion() + { + using namespace WwiseAuthoringAPI; + + Waapi::Response<Wwise::Version> response; + + AkJson result; + response.status = call(WaapiCommands::getInfo, AkJson::Map{}, AkJson::Map{}, result); + + if(response.status) + { + if(result.HasKey("version") && result["version"].HasKey("displayName")) + { + response.result = { + result["version"]["year"].GetVariant().GetInt32(), + result["version"]["major"].GetVariant().GetInt32(), + result["version"]["minor"].GetVariant().GetInt32(), + result["version"]["build"].GetVariant().GetInt32(), + }; + } + } + else + { + response.errorMessage = WaapiHelper::getErrorMessage(result); + } + + return response; + } + + Waapi::Response<Waapi::ProjectInfo> WaapiClient::getProjectInfo() + { + using namespace WwiseAuthoringAPI; + + Waapi::Response<Waapi::ProjectInfo> response; + + static const auto args(AkJson::Map{ + { + "from", + AkJson::Map{ + { + "ofType", + AkJson::Array{ + {AkVariant("Project")}, + }, + }, + }, + }, + }); + + static const auto options(AkJson::Map{ + { + "return", + AkJson::Array{ + {AkVariant("filePath")}, + {AkVariant("id")}, + }, + }, + }); + + AkJson result; + response.status = call(WaapiCommands::objectGet, args, options, result); + + if(response.status) + { + if(result.HasKey("return")) + { + const auto& returnResult = result["return"]; + + if(!returnResult.GetArray().empty()) + { + auto projectPath = juce::String(returnResult[0]["filePath"].GetVariant().GetString()); + auto projectId = juce::String(returnResult[0]["id"].GetVariant().GetString()).removeCharacters("{}"); + +#ifndef WIN32 + // Waapi returns the path as a windows path + projectPath = projectPath.replace("\\", juce::File::getSeparatorString()).replace("Y:", "~").replace("Z:", "/"); +#endif + + response.result.projectPath = projectPath; + response.result.projectId = projectId; + } + } + } + else + { + response.errorMessage = WaapiHelper::getErrorMessage(result); + } + + return response; + } + Waapi::Response<Waapi::ObjectResponse> WaapiClient::getSelectedObject() + { + using namespace WwiseAuthoringAPI; + + Waapi::Response<Waapi::ObjectResponse> response; + + static const auto options = AkJson::Map{ + { + "return", + AkJson::Array{ + AkVariant{"id"}, + AkVariant{"name"}, + AkVariant{"type"}, + AkVariant{"path"}, + }, + }, + }; + + AkJson result; + response.status = call(WaapiCommands::getSelectedObjects, AkJson::Map{}, options, result); + + if(response.status) + { + if(result.HasKey("objects")) + { + const auto& returnObjects = result["objects"]; + + if(!returnObjects.GetArray().empty()) + response.result = Waapi::ObjectResponse(returnObjects.GetArray()[0]); + } + } + else + { + response.errorMessage = WaapiHelper::getErrorMessage(result); + } + + return response; + } +} // namespace AK::WwiseTransfer diff --git a/src/shared/Core/WaapiClient.h b/src/shared/Core/WaapiClient.h @@ -0,0 +1,224 @@ +#pragma once + +#include "AK/WwiseAuthoringAPI/AkAutobahn/AkJson.h" +#include "AK/WwiseAuthoringAPI/AkAutobahn/Client.h" +#include "AK/WwiseAuthoringAPI/waapi.h" +#include "Helpers/WaapiHelper.h" +#include "Model/Import.h" +#include "Model/Waapi.h" +#include "Model/Wwise.h" + +#include <juce_core/juce_core.h> +#include <juce_data_structures/juce_data_structures.h> +#include <juce_events/juce_events.h> +#include <optional> +#include <set> + +namespace AK::WwiseTransfer +{ + struct WaapiClientWatcherConfig + { + const juce::String Ip; + const int Port; + const int ConnectionMonitorDelay; + const int MinConnectionRetryDelay; + const int MaxConnectionRetryDelay; + }; + + template <class Function, class Callback> + class AsyncJob + : public juce::ThreadPoolJob + { + public: + AsyncJob(const Function& function, const Callback& callback) + : function(function) + , callback(callback) + , juce::ThreadPoolJob("AsyncJob") + { + } + + juce::ThreadPoolJob::JobStatus runJob() override + { + decltype(function()) response; + + auto onExecute = [this, &response]() + { + response = function(); + + return response.status || shouldExit(); + }; + + WaapiHelper::executeWithRetry(onExecute); + + auto onJobComplete = [callback = callback, response = std::move(response)] + { + callback(response); + }; + + juce::MessageManager::callAsync(onJobComplete); + + return juce::ThreadPoolJob::JobStatus::jobHasFinished; + } + + private: + Callback callback; + Function function; + }; + + class WaapiClient + : private WwiseAuthoringAPI::Client + { + public: + explicit WaapiClient(); + + bool connect(const char* in_uri, unsigned int in_port, WwiseAuthoringAPI::disconnectHandler_t disconnectHandler = nullptr, int in_timeoutMs = -1); + bool subscribe(const char* in_uri, const WwiseAuthoringAPI::AkJson& in_options, WampEventCallback in_callback, uint64_t& out_subscriptionId, WwiseAuthoringAPI::AkJson& out_result, int in_timeoutMs = -1); + bool unsubscribe(const uint64_t& in_subscriptionId, WwiseAuthoringAPI::AkJson& out_result, int in_timeoutMs = -1); + bool isConnected(); + void disconnect(); + bool call(const char* in_uri, const WwiseAuthoringAPI::AkJson& in_args, const WwiseAuthoringAPI::AkJson& in_options, WwiseAuthoringAPI::AkJson& out_result, int in_timeoutMs = -1); + bool call(const char* in_uri, const char* in_args, const char* in_options, std::string& out_result, int in_timeoutMs = -1); + + Waapi::Response<Wwise::Version> getVersion(); + Waapi::Response<Waapi::ProjectInfo> getProjectInfo(); + Waapi::Response<Waapi::ObjectResponse> getSelectedObject(); + Waapi::Response<Waapi::ObjectResponseSet> pasteProperties(const Waapi::PastePropertiesRequest& pastePropertiesRequest); + Waapi::Response<Waapi::ObjectResponseSet> getObjects(const std::set<juce::String>& objectPaths); + Waapi::Response<Waapi::ObjectResponseSet> import(const std::vector<Waapi::ImportItemRequest>& importItemsRequest, Import::ContainerNameExistsOption containerNameExistsOption, const juce::String& objectLanguage); + Waapi::Response<Waapi::ObjectResponseSet> getObjectAncestorsAndDescendants(const juce::String& objectPath); + Waapi::Response<Waapi::ObjectResponseSet> getObjectAncestorsAndDescendantsLegacy(const juce::String& objectPath); + Waapi::Response<std::vector<juce::String>> getProjectLanguages(); + Waapi::Response<juce::String> getOriginalsFolder(); + + bool selectObjects(const juce::String& selectObjectsCommand, const std::vector<juce::String>& objectPaths); + + void beginUndoGroup(); + void cancelUndoGroup(); + void endUndoGroup(const juce::String& displayName); + + template <typename Callback> + void getVersionAsync(const Callback& callback) + { + auto onJobExecute = [this]() + { + return getVersion(); + }; + + threadPool.addJob(new AsyncJob(onJobExecute, callback), true); + } + + template <typename Callback> + void getProjectInfoAsync(const Callback& callback) + { + auto onJobExecute = [this]() + { + return getProjectInfo(); + }; + + threadPool.addJob(new AsyncJob(onJobExecute, callback), true); + } + + template <typename Callback> + void getSelectedObjectAsync(const Callback& callback) + { + auto onJobExecute = [this]() + { + return getSelectedObject(); + }; + + threadPool.addJob(new AsyncJob(onJobExecute, callback), true); + } + + template <typename Callback> + void pastePropertiesAsync(const Waapi::PastePropertiesRequest& pastePropertiesRequest, const Callback& callback) + { + auto onJobExecute = [this, pastePropertiesRequest = pastePropertiesRequest]() + { + return pasteProperties(pastePropertiesRequest); + }; + + threadPool.addJob(new AsyncJob(onJobExecute, callback), true); + } + + template <typename Callback> + void getObjectsAsync(const std::set<juce::String>& objectPaths, const Callback& callback) + { + auto onJobExecute = [this, objectPaths = objectPaths]() + { + return getObjects(objectPaths); + }; + + threadPool.addJob(new AsyncJob(onJobExecute, callback), true); + } + + template <typename Callback> + void getProjectLanguagesAsync(const Callback& callback) + { + auto onJobExecute = [this]() + { + return getProjectLanguages(); + }; + + threadPool.addJob(new AsyncJob(onJobExecute, callback), true); + } + template <typename Callback> + void importAsync(const std::vector<Waapi::ImportItemRequest>& importItemsRequest, Import::ContainerNameExistsOption containerNameExistsOption, const juce::String& objectLanguage, const Callback& callback) + { + auto onJobExecute = [this, importItemsRequest = importItemsRequest, containerNameExistsOption = containerNameExistsOption, objectLanguage = objectLanguage]() + { + return import(importItemsRequest, containerNameExistsOption, objectLanguage); + }; + + threadPool.addJob(new AsyncJob(onJobExecute, callback), true); + } + + template <typename Callback> + void getOriginalsFolderAsync(Callback& callback) + { + auto onJobExecute = [this]() + { + return getOriginalsFolder(); + }; + + threadPool.addJob(new AsyncJob(onJobExecute, callback), true); + } + + private: + juce::ThreadPool threadPool; + }; + + class WaapiClientWatcher + : private juce::Thread + { + public: + WaapiClientWatcher(juce::ValueTree applicationState, WaapiClient& waapiClient, WaapiClientWatcherConfig waapiClientWatcherConfig); + + void start(); + void stop(); + + private: + juce::ValueTree applicationState; + juce::CachedValue<juce::String> projectId; + juce::CachedValue<bool> waapiConnected; + juce::CachedValue<bool> wwiseObjectsChanged; + + juce::ValueTree languages; + + WaapiClientWatcherConfig waapiClientWatcherConfig; + WaapiClient& waapiClient; + + int connectionRetryDelay; + + uint64_t projectLoadedSubscriptionId{0}; + uint64_t projectPostClosedSubscriptionId{0}; + uint64_t objectCreatedEventSubscriptionId{0}; + uint64_t objectPostDeletedEventSubscriptionId{0}; + uint64_t objectNameChangedEventSubscriptionId{0}; + + void run() override; + + void setProjectId(const juce::String& projectId); + void setWaapiConnected(bool connected); + void setWwiseObjectsChanged(bool changed); + }; +} // namespace AK::WwiseTransfer diff --git a/src/shared/Helpers/ImportHelper.h b/src/shared/Helpers/ImportHelper.h @@ -0,0 +1,221 @@ +#pragma once + +#include "Helpers/WwiseHelper.h" +#include "Model/IDs.h" +#include "Model/Import.h" + +#include <AK/Tools/Common/AkFNVHash.h> +#include <juce_gui_basics/juce_gui_basics.h> + +namespace AK::WwiseTransfer::ImportHelper +{ + inline juce::ValueTree hierarchyMappingNodeToValueTree(Import::HierarchyMappingNode hierarchyMappingNode) + { + juce::ValueTree valueTree(IDs::hierarchyMappingNode); + valueTree.setProperty(IDs::objectName, hierarchyMappingNode.name, nullptr); + valueTree.setProperty(IDs::objectNameValid, hierarchyMappingNode.nameValid, nullptr); + valueTree.setProperty(IDs::objectNameErrorMessage, hierarchyMappingNode.nameErrorMessage, nullptr); + valueTree.setProperty(IDs::objectType, juce::VariantConverter<Wwise::ObjectType>::toVar(hierarchyMappingNode.type), nullptr); + valueTree.setProperty(IDs::objectTypeValid, hierarchyMappingNode.typeValid, nullptr); + valueTree.setProperty(IDs::objectTypeErrorMessage, hierarchyMappingNode.typeErrorMessage, nullptr); + valueTree.setProperty(IDs::propertyTemplatePath, hierarchyMappingNode.propertyTemplatePath, nullptr); + valueTree.setProperty(IDs::propertyTemplatePathEnabled, hierarchyMappingNode.propertyTemplatePathEnabled, nullptr); + valueTree.setProperty(IDs::propertyTemplatePathValid, hierarchyMappingNode.propertyTemplatePathValid, nullptr); + valueTree.setProperty(IDs::propertyTemplatePathErrorMessage, hierarchyMappingNode.propertyTemplatePathErrorMessage, nullptr); + valueTree.setProperty(IDs::objectLanguage, hierarchyMappingNode.language, nullptr); + + return valueTree; + } + + inline juce::ValueTree hierachyMappingNodeListToValueTree(const std::vector<Import::HierarchyMappingNode>& hierarchyMappingNodeList) + { + juce::ValueTree valueTree(IDs::hierarchyMapping); + for(const auto& hierarchyMappingNode : hierarchyMappingNodeList) + { + valueTree.appendChild(hierarchyMappingNodeToValueTree(hierarchyMappingNode), nullptr); + } + + return valueTree; + } + + inline Import::HierarchyMappingNode valueTreeToHiarchyMappingNode(juce::ValueTree valueTree) + { + return Import::HierarchyMappingNode(valueTree[IDs::objectName], + valueTree[IDs::objectNameValid], + valueTree[IDs::objectNameErrorMessage], + juce::VariantConverter<Wwise::ObjectType>::fromVar(valueTree[IDs::objectType]), + valueTree[IDs::objectTypeValid], + valueTree[IDs::objectTypeErrorMessage], + valueTree[IDs::propertyTemplatePath], + valueTree[IDs::propertyTemplatePathEnabled], + valueTree[IDs::propertyTemplatePathValid], + valueTree[IDs::propertyTemplatePathErrorMessage], + valueTree[IDs::objectLanguage]); + } + + inline Import::PreviewItem valueTreeToPreviewItem(juce::ValueTree valueTree) + { + return Import::PreviewItem{ + valueTree[IDs::objectName], + juce::VariantConverter<Wwise::ObjectType>::fromVar(valueTree[IDs::objectType]), + juce::VariantConverter<Import::ObjectStatus>::fromVar(valueTree[IDs::objectStatus]), + valueTree[IDs::audioFilePath], + juce::VariantConverter<Import::WavStatus>::fromVar(valueTree[IDs::wavStatus]), + }; + } + + inline juce::ValueTree previewItemToValueTree(const juce::String& path, Import::PreviewItem previewItem) + { + juce::ValueTree valueTree(path); + valueTree.setProperty(IDs::objectName, previewItem.name, nullptr); + valueTree.setProperty(IDs::objectType, juce::VariantConverter<Wwise::ObjectType>::toVar(previewItem.type), nullptr); + valueTree.setProperty(IDs::objectStatus, juce::VariantConverter<Import::ObjectStatus>::toVar(previewItem.objectStatus), nullptr); + valueTree.setProperty(IDs::audioFilePath, previewItem.audioFilePath, nullptr); + valueTree.setProperty(IDs::wavStatus, juce::VariantConverter<Import::WavStatus>::toVar(previewItem.wavStatus), nullptr); + + return valueTree; + } + + inline std::vector<Import::HierarchyMappingNode> valueTreeToHierarchyMappingNodeList(juce::ValueTree hierarchyMappingValueTree) + { + std::vector<Import::HierarchyMappingNode> hierarchyMappingNodeList; + + for(int i = 0; i < hierarchyMappingValueTree.getNumChildren(); ++i) + { + auto hierarchyMappingNodeValueTree = hierarchyMappingValueTree.getChild(i); + + hierarchyMappingNodeList.emplace_back(ImportHelper::valueTreeToHiarchyMappingNode(hierarchyMappingNodeValueTree)); + } + + return hierarchyMappingNodeList; + } + + inline juce::String hierarchyMappingToPath(std::vector<Import::HierarchyMappingNode> hierachyMappingNodeList) + { + juce::String path; + + for(auto& hierarchyMappingNode : hierachyMappingNodeList) + { + if(hierarchyMappingNode.type != Wwise::ObjectType::Unknown) + path << WwiseHelper::buildObjectPathNode(hierarchyMappingNode.type, hierarchyMappingNode.name); + } + + return path; + } + + inline juce::String containerNameExistsOptionToString(Import::ContainerNameExistsOption option) + { + switch(option) + { + case Import::ContainerNameExistsOption::UseExisting: + return "useExisting"; + case Import::ContainerNameExistsOption::CreateNew: + return "createNew"; + case Import::ContainerNameExistsOption::Replace: + return "replaceExisting"; + default: + return "notImplemented"; + } + } + + inline Import::ContainerNameExistsOption stringToContainerNameExistsOption(const juce::String& option) + { + if(option == "useExisting") + return Import::ContainerNameExistsOption::UseExisting; + else if(option == "createNew") + return Import::ContainerNameExistsOption::CreateNew; + else if(option == "replace") + return Import::ContainerNameExistsOption::Replace; + else + return Import::ContainerNameExistsOption::Unknown; + } + + inline juce::String containerNameExistsOptionToReadableString(Import::ContainerNameExistsOption option) + { + switch(option) + { + case Import::ContainerNameExistsOption::UseExisting: + return "Use Existing"; + case Import::ContainerNameExistsOption::CreateNew: + return "Create New"; + case Import::ContainerNameExistsOption::Replace: + return "Replace"; + default: + return "Not Implemented"; + } + } + + inline juce::String audioFilenameExistsOptionToReadableString(Import::AudioFilenameExistsOption option) + { + switch(option) + { + case Import::AudioFilenameExistsOption::UseExisting: + return "Use Existing"; + case Import::AudioFilenameExistsOption::Replace: + return "Replace"; + default: + return "Not Implemented"; + } + } + + inline juce::String applyTemplateOptionToReadableString(Import::ApplyTemplateOption option) + { + switch(option) + { + case Import::ApplyTemplateOption::Always: + return "Always"; + case Import::ApplyTemplateOption::NewObjectCreationOnly: + return "New Object Creation Only"; + default: + return "Not Implemented"; + } + } + + inline juce::String objectStatusToReadableString(Import::ObjectStatus itemState) + { + switch(itemState) + { + case Import::ObjectStatus::Replaced: + return "Replaced"; + case Import::ObjectStatus::New: + return "New"; + case Import::ObjectStatus::NewRenamed: + return "New (Renamed)"; + case Import::ObjectStatus::NoChange: + return "No Change"; + default: + return ""; + } + } + + inline juce::String wavStatusToReadableString(Import::WavStatus itemState) + { + switch(itemState) + { + case Import::WavStatus::Replaced: + return "Replaced"; + case Import::WavStatus::New: + return "New"; + default: + return ""; + } + } + + inline unsigned int importItemsToHash(const std::vector<Import::Item>& importItems) + { + AK::FNVHash32 hash; + + for(const auto& importItem : importItems) + { + auto audioFilePathRaw = importItem.audioFilePath.toUTF8(); + hash.Compute(audioFilePathRaw, audioFilePathRaw.sizeInBytes()); + + auto originalsSubfolderRaw = importItem.originalsSubFolder.toUTF8(); + hash.Compute(originalsSubfolderRaw, originalsSubfolderRaw.sizeInBytes()); + + hash.Compute(AK::FNVHash32::ComputeLowerCase(importItem.path.toUTF8())); + } + + return hash.Get(); + } +} // namespace AK::WwiseTransfer::ImportHelper diff --git a/src/shared/Helpers/PersistanceHelper.h b/src/shared/Helpers/PersistanceHelper.h @@ -0,0 +1,57 @@ +#pragma once + +#include "Helpers/ImportHelper.h" +#include "Model/IDs.h" +#include "Model/Import.h" + +#include <juce_gui_basics/juce_gui_basics.h> + +namespace AK::WwiseTransfer::PersistanceHelper +{ + inline juce::String hierarchyMappingToPresetData(juce::ValueTree hierarchyMapping) + { + juce::ValueTree hierarchyMappingCopy = hierarchyMapping.createCopy(); + hierarchyMappingCopy.removeProperty(IDs::selectedRow, nullptr); + + for(int i = 0; i < hierarchyMappingCopy.getNumChildren(); ++i) + { + auto hierarchyMappingNodeCopy = hierarchyMappingCopy.getChild(i); + hierarchyMappingNodeCopy.removeProperty(IDs::objectTypeValid, nullptr); + hierarchyMappingNodeCopy.removeProperty(IDs::objectTypeErrorMessage, nullptr); + hierarchyMappingNodeCopy.removeProperty(IDs::propertyTemplatePathValid, nullptr); + hierarchyMappingNodeCopy.removeProperty(IDs::propertyTemplatePathErrorMessage, nullptr); + } + + return hierarchyMappingCopy.toXmlString(); + } + + inline juce::ValueTree presetDataToHierarchyMapping(const juce::String& presetData) + { + juce::ValueTree hierarchyMappingFromPresetData = juce::ValueTree::fromXml(presetData); + + if(!hierarchyMappingFromPresetData.isValid() || hierarchyMappingFromPresetData.getType() != IDs::hierarchyMapping) + return {}; + + std::vector<Import::HierarchyMappingNode> hierarchyMapping; + + for(int i = 0; i < hierarchyMappingFromPresetData.getNumChildren(); ++i) + { + auto hierarchyMappingNodeFromPresetData = hierarchyMappingFromPresetData.getChild(i); + + hierarchyMapping.emplace_back(hierarchyMappingNodeFromPresetData[IDs::objectName], + true, + "", + juce::VariantConverter<Wwise::ObjectType>::fromVar(hierarchyMappingNodeFromPresetData[IDs::objectType]), + true, + "", + hierarchyMappingNodeFromPresetData[IDs::propertyTemplatePath], + hierarchyMappingNodeFromPresetData[IDs::propertyTemplatePathEnabled], + true, + "", + hierarchyMappingNodeFromPresetData[IDs::objectLanguage]); + } + + auto hierarchyMappingValueTree = ImportHelper::hierachyMappingNodeListToValueTree(hierarchyMapping); + return hierarchyMappingValueTree; + } +} // namespace AK::WwiseTransfer::PersistanceHelper diff --git a/src/shared/Helpers/WaapiHelper.h b/src/shared/Helpers/WaapiHelper.h @@ -0,0 +1,38 @@ +#pragma once + +#include "AK/WwiseAuthoringAPI/AkAutobahn/AkJson.h" + +#include <juce_core/juce_core.h> + +namespace AK::WwiseTransfer::WaapiHelper +{ + template <class Function> + inline void executeWithRetry(Function function, int retryDelayMs = 500, int maxAttempts = 20) + { + for(int attempt{}; attempt < maxAttempts && !function(); ++attempt) + juce::Time::waitForMillisecondCounter(juce::Time::getMillisecondCounter() + retryDelayMs); + } + + inline juce::String getErrorMessage(AK::WwiseAuthoringAPI::AkJson result) + { + juce::String message; + + if(result.HasKey("message")) + { + message << "Error: "; + message << result["message"].GetVariant().GetString().c_str(); + + if(result.HasKey("details") && result["details"].HasKey("log")) + { + message << juce::NewLine() << "Details:" << juce::NewLine() << juce::NewLine(); + for(auto& item : result["details"]["log"].GetArray()) + { + if(item.HasKey("message")) + message << juce::NewLine() << item["message"].GetVariant().GetString(); + } + } + } + + return message; + } +} // namespace AK::WwiseTransfer::WaapiHelper diff --git a/src/shared/Helpers/WwiseHelper.h b/src/shared/Helpers/WwiseHelper.h @@ -0,0 +1,265 @@ +#pragma once + +#include "Model/IDs.h" +#include "Model/Import.h" +#include "Model/Wwise.h" + +#include <juce_gui_basics/juce_gui_basics.h> +#include <regex> + +namespace AK::WwiseTransfer::WwiseHelper +{ + inline bool validateObjectTypeParentChildRelationShip(Wwise::ObjectType parent, Wwise::ObjectType child) + { + using namespace Wwise; + + switch(parent) + { + case ObjectType::BlendContainer: + case ObjectType::RandomContainer: + case ObjectType::SequenceContainer: + case ObjectType::SwitchContainer: + { + static constexpr std::initializer_list<ObjectType> children{ + ObjectType::SwitchContainer, + ObjectType::RandomContainer, + ObjectType::SequenceContainer, + ObjectType::BlendContainer, + ObjectType::SoundSFX, + ObjectType::SoundVoice, + }; + + return std::find(children.begin(), children.end(), child) != children.end(); + }; + case ObjectType::ActorMixer: + case ObjectType::VirtualFolder: + case ObjectType::WorkUnit: + { + static constexpr std::initializer_list<ObjectType> children{ + ObjectType::WorkUnit, + ObjectType::VirtualFolder, + ObjectType::ActorMixer, + ObjectType::SwitchContainer, + ObjectType::RandomContainer, + ObjectType::SequenceContainer, + ObjectType::BlendContainer, + ObjectType::SoundSFX, + ObjectType::SoundVoice, + }; + + return std::find(children.begin(), children.end(), child) != children.end(); + }; + case ObjectType::PhysicalFolder: + { + static constexpr std::initializer_list<ObjectType> children{ + ObjectType::PhysicalFolder, + ObjectType::WorkUnit, + }; + + return std::find(children.begin(), children.end(), child) != children.end(); + }; + default: + return false; + } + }; + + inline juce::String objectTypeToReadableString(Wwise::ObjectType objectType) + { + using namespace Wwise; + + switch(objectType) + { + case ObjectType::ActorMixer: + return "Actor Mixer"; + case ObjectType::AudioFileSource: + return "Audio File Source"; + case ObjectType::BlendContainer: + return "Blend Container"; + case ObjectType::PhysicalFolder: + return "Physical Folder"; + case ObjectType::RandomContainer: + return "Random Container"; + case ObjectType::SequenceContainer: + return "Sequence Container"; + case ObjectType::SoundSFX: + return "Sound SFX"; + case ObjectType::SoundVoice: + return "Sound Voice"; + case ObjectType::SwitchContainer: + return "Switch Container"; + case ObjectType::VirtualFolder: + return "Virtual Folder"; + case ObjectType::WorkUnit: + return "Work Unit"; + case ObjectType::Sound: + return "Sound"; + default: + return "Unknown"; + } + }; + + inline Wwise::ObjectType stringToObjectType(const juce::String& objectTypeAsString) + { + using namespace Wwise; + + if(objectTypeAsString == "AudioFileSource" || objectTypeAsString == "Audio File Source") + return ObjectType::AudioFileSource; + else if(objectTypeAsString == "ActorMixer" || objectTypeAsString == "Actor Mixer") + return ObjectType::ActorMixer; + else if(objectTypeAsString == "BlendContainer" || objectTypeAsString == "Blend Container") + return ObjectType::BlendContainer; + else if(objectTypeAsString == "Folder") + return ObjectType::VirtualFolder; + else if(objectTypeAsString == "RandomSequenceContainer" || objectTypeAsString == "Random Container") + return ObjectType::RandomContainer; + else if(objectTypeAsString == "SequenceContainer" || objectTypeAsString == "Sequence Container") + return ObjectType::SequenceContainer; + else if(objectTypeAsString == "Sound") + return ObjectType::Sound; + else if(objectTypeAsString == "SoundSFX" || objectTypeAsString == "Sound SFX") + return ObjectType::SoundSFX; + else if(objectTypeAsString == "Sound Voice") + return ObjectType::SoundVoice; + else if(objectTypeAsString == "SwitchContainer" || objectTypeAsString == "Switch Container") + return ObjectType::SwitchContainer; + else if(objectTypeAsString == "WorkUnit" || objectTypeAsString == "Work Unit") + return ObjectType::WorkUnit; + else if(objectTypeAsString == "Virtual Folder") + return ObjectType::VirtualFolder; + else if(objectTypeAsString == "Physical Folder") + return ObjectType::PhysicalFolder; + else + return ObjectType::Unknown; + }; + + inline juce::String buildObjectPathNode(Wwise::ObjectType objectType, const juce::String& name) + { + return "\\<" + objectTypeToReadableString(objectType) + ">" + name; + } + + inline juce::String pathToPathWithoutObjectTypes(const juce::String& objectPath) + { + static std::regex pattern("<.+?>"); + auto result = std::regex_replace(objectPath.toStdString(), pattern, ""); + return juce::String(result); + } + + inline std::vector<juce::String> pathToPathParts(const juce::String& objectPath) + { + juce::StringArray parts; + parts.addTokens(objectPath, "\\", ""); + + std::vector<juce::String> objectPathParts; + for(auto& part : parts) + { + if(part.isNotEmpty()) + objectPathParts.emplace_back(part); + } + + return objectPathParts; + } + + inline std::vector<juce::String> pathToAncestorPaths(const juce::String& objectPath) + { + std::vector<juce::String> ancestors; + + auto parts = pathToPathParts(objectPath); + + juce::String current; + for(int i = 0; i < parts.size() - 1; ++i) + { + current << "\\" << parts[i]; + ancestors.emplace_back(current); + } + + return ancestors; + } + + inline juce::String pathToObjectName(const juce::String& objectPath) + { + auto lastIndexGreaterThan = objectPath.lastIndexOf(">"); + auto lastIndexOfPathSeperator = objectPath.lastIndexOf("\\"); + + if(lastIndexGreaterThan > lastIndexOfPathSeperator) + return objectPath.substring(lastIndexGreaterThan + 1); + else + return objectPath.substring(lastIndexOfPathSeperator + 1); + } + + inline Wwise::ObjectType pathToObjectType(const juce::String& objectPath) + { + if(objectPath == "\\Actor-Mixer Hierarchy") + return Wwise::ObjectType::ActorMixer; + + auto lastIndexLessThan = objectPath.lastIndexOf("<"); + auto lastIndexGreaterThan = objectPath.lastIndexOf(">"); + + return WwiseHelper::stringToObjectType(objectPath.substring(lastIndexLessThan + 1, lastIndexGreaterThan)); + } + + inline juce::ValueTree versionToValueTree(const Wwise::Version& version) + { + juce::ValueTree valueTree(IDs::version); + + valueTree.setProperty(IDs::year, version.year, nullptr); + valueTree.setProperty(IDs::major, version.major, nullptr); + valueTree.setProperty(IDs::minor, version.minor, nullptr); + valueTree.setProperty(IDs::build, version.build, nullptr); + + return valueTree; + } + + inline Wwise::Version valueTreeToVersion(juce::ValueTree valueTree) + { + return { + valueTree[IDs::year], + valueTree[IDs::major], + valueTree[IDs::minor], + valueTree[IDs::build], + }; + } + + inline juce::ValueTree languagesToValueTree(const std::vector<juce::String>& languages) + { + juce::ValueTree languagesValueTree(IDs::languages); + + for(const auto& language : languages) + { + juce::ValueTree languageValueTree(IDs::language); + languageValueTree.setProperty(IDs::languageName, language, nullptr); + + languagesValueTree.appendChild(languageValueTree, nullptr); + } + + return languagesValueTree; + } + + inline std::vector<juce::String> valueTreeToLanguages(juce::ValueTree valueTree) + { + std::vector<juce::String> languages; + + for(int i = 0; i < valueTree.getNumChildren(); ++i) + { + languages.emplace_back(valueTree.getChild(i)[IDs::languageName].toString()); + } + + return languages; + } + + inline juce::String getCommonAncestor(const juce::String& firstPath, const juce::String& secondPath) + { + auto firstAsParts = WwiseHelper::pathToPathParts(firstPath); + auto lastAsParts = WwiseHelper::pathToPathParts(secondPath); + + juce::String commonAncestorPath; + for(int i = 0; i < firstAsParts.size() && i < lastAsParts.size(); ++i) + { + if(firstAsParts[i] == lastAsParts[i]) + commonAncestorPath << "\\" << firstAsParts[i]; + else + break; + } + + return commonAncestorPath; + } +} // namespace AK::WwiseTransfer::WwiseHelper diff --git a/src/shared/Model/IDs.h b/src/shared/Model/IDs.h @@ -0,0 +1,78 @@ +#pragma once + +#include <juce_gui_basics/juce_gui_basics.h> + +namespace AK::WwiseTransfer::IDs +{ + inline const juce::Identifier application = "application"; + inline const juce::Identifier waapiConnected = "waapiConnected"; + inline const juce::Identifier projectPath = "projectPath"; + inline const juce::Identifier projectId = "projectId"; + + inline const juce::Identifier originalsFolder = "originalsFolder"; + inline const juce::Identifier originalsSubfolder = "originalsSubfolder"; + inline const juce::Identifier originalsSubfolderValid = "originalsSubfolderValid"; + inline const juce::Identifier originalsSubfolderErrorMessage = "originalsSubfolderErrorMessage"; + inline const juce::Identifier languageSubfolder = "languageSubfolder"; + + inline const juce::Identifier importDestination = "importDestination"; + inline const juce::Identifier importDestinationType = "importDestinationType"; + inline const juce::Identifier importDestinationValid = "importDestinationValid"; + inline const juce::Identifier importDestinationErrorMessage = "importDestinationErrorMessage"; + + inline const juce::Identifier previewItems = "previewItems"; + inline const juce::Identifier previewItem = "previewItem"; + + inline const juce::Identifier selectedRow = "selectedRow"; + inline const juce::Identifier hierarchyMapping = "hierarchyMapping"; + inline const juce::Identifier hierarchyMappingNode = "hierarchyMappingNode"; + + inline const juce::Identifier objectType = "objectType"; + inline const juce::Identifier objectTypeValid = "objectTypeValid"; + inline const juce::Identifier objectTypeErrorMessage = "objectTypeErrorMessage"; + inline const juce::Identifier objectPath = "objectPath"; + inline const juce::Identifier objectName = "objectName"; + inline const juce::Identifier objectNameValid = "objectNameValid"; + inline const juce::Identifier objectNameErrorMessage = "objectNameErrorMessage"; + inline const juce::Identifier objectStatus = "objectStatus"; + inline const juce::Identifier objectLanguage = "objectLanguage"; + + inline const juce::Identifier audioFilePath = "audioFilePath"; + inline const juce::Identifier renderFilePath = "renderFilePath"; + inline const juce::Identifier wavStatus = "wavStatus"; + + inline const juce::Identifier propertyTemplatePath = "propertyTemplatePath"; + inline const juce::Identifier propertyTemplatePathType = "propertyTemplatePathType"; + inline const juce::Identifier propertyTemplatePathValid = "propertyTemplatePathValid"; + inline const juce::Identifier propertyTemplatePathErrorMessage = "propertyTemplatePathErrorMessage"; + inline const juce::Identifier propertyTemplatePathEnabled = "propertyTemplatePathEnabled"; + + inline const juce::Identifier containerNameExists = "containerNameExists"; + inline const juce::Identifier audioFileNameExists = "audioFileNameExists"; + inline const juce::Identifier applyTemplate = "applyTemplate"; + + inline const juce::Identifier version = "version"; + inline const juce::Identifier year = "year"; + inline const juce::Identifier major = "major"; + inline const juce::Identifier minor = "minor"; + inline const juce::Identifier build = "build"; + + inline const juce::Identifier featureSupport = "featureSupport"; + inline const juce::Identifier selectObjectsOnImportCommand = "selectObjectsOnImportCommand"; + inline const juce::Identifier applyTemplateFeatureEnabled = "applyTemplateFeatureEnabled"; + inline const juce::Identifier undoGroupFeatureEnabled = "undoGroupFeatureEnabled"; + inline const juce::Identifier waqlEnabled = "waqlEnabled"; + inline const juce::Identifier originalsFolderLookupEnabled = "originalsFolderLookupEnabled"; + + inline const juce::Identifier wwiseObjectsChanged = "wwiseObjectsChanged"; + + inline const juce::Identifier previewLoading = "previewLoading"; + + inline const juce::Identifier sessionName = "sessionName"; + + inline const juce::Identifier collapsedUI = "collapsedUI"; + + inline const juce::Identifier languages = "languages"; + inline const juce::Identifier language = "language"; + inline const juce::Identifier languageName = "languageName"; +} // namespace AK::WwiseTransfer::IDs diff --git a/src/shared/Model/Import.h b/src/shared/Model/Import.h @@ -0,0 +1,242 @@ +#pragma once + +#include "Model/IDs.h" +#include "Model/Wwise.h" + +namespace AK::WwiseTransfer::Import +{ + enum class ContainerNameExistsOption : int + { + Unknown, + UseExisting, + CreateNew, + Replace + }; + + enum class AudioFilenameExistsOption + { + UseExisting = 1, + Replace + }; + + enum class ApplyTemplateOption + { + Always = 1, + NewObjectCreationOnly + }; + + enum class ObjectStatus + { + NoChange, + Replaced, + New, + NewRenamed + }; + + enum class WavStatus + { + Unknown, + Replaced, + New + }; + + struct Item + { + Item(const juce::String& name, Wwise::ObjectType type, const juce::String& path, const juce::String& originalsSubFolder, const juce::String& audioFilePath, const juce::String& renderFilePath) + : name(name) + , type(type) + , path(path) + , originalsSubFolder(originalsSubFolder) + , audioFilePath(audioFilePath) + , renderFilePath(renderFilePath) + { + } + + juce::String name; + Wwise::ObjectType type; + juce::String path; + juce::String originalsSubFolder; + juce::String audioFilePath; + juce::String renderFilePath; + }; + + struct PreviewItem + { + juce::String name; + Wwise::ObjectType type; + ObjectStatus objectStatus; + juce::String audioFilePath; + WavStatus wavStatus; + }; + + struct PreviewItemNode : public Item + { + PreviewItemNode(const Item& item) + : Item(item.name, item.type, item.path, item.originalsSubFolder, item.audioFilePath, item.renderFilePath) + { + } + + std::unordered_map<juce::String, PreviewItemNode> children; + }; + + struct HierarchyMappingNode + { + HierarchyMappingNode(const juce::String& name, bool nameValid, const juce::String& nameErrorMessage, Wwise::ObjectType type, bool typeValid, const juce::String& typeErrorMessage, + const juce::String& propertyTemplatePath, bool propertyTemplatePathEnabled, bool propertyTemplatePathValid, const juce::String& propertyTemplatePathErrorMessage, const juce::String& language) + : name(name) + , nameValid(nameValid) + , nameErrorMessage(nameErrorMessage) + , type(type) + , typeValid(typeValid) + , typeErrorMessage(typeErrorMessage) + , propertyTemplatePath(propertyTemplatePath) + , propertyTemplatePathEnabled(propertyTemplatePathEnabled) + , propertyTemplatePathValid(propertyTemplatePathValid) + , propertyTemplatePathErrorMessage(propertyTemplatePathErrorMessage) + , language(language) + { + } + + HierarchyMappingNode(juce::String name, Wwise::ObjectType type) + : name(name) + , nameValid(true) + , type(type) + , typeValid(true) + , propertyTemplatePathEnabled(false) + , propertyTemplatePathValid(true) + { + } + + juce::String name; + bool nameValid; + juce::String nameErrorMessage; + Wwise::ObjectType type; + bool typeValid; + juce::String typeErrorMessage; + juce::String propertyTemplatePath; + bool propertyTemplatePathEnabled; + bool propertyTemplatePathValid; + juce::String propertyTemplatePathErrorMessage; + juce::String language; + }; + + struct Options + { + Options(const juce::String& importDestination, const juce::String& originalsSubfolder, const juce::String& hierarchyMappingPath) + : importDestination(importDestination) + , originalsSubfolder(originalsSubfolder) + , hierarchyMappingPath(hierarchyMappingPath) + { + } + + juce::String importDestination; + juce::String originalsSubfolder; + juce::String hierarchyMappingPath; + }; + + struct Summary + { + struct Object + { + Wwise::ObjectType type; + juce::String originalWavFilePath; + juce::String propertyTemplatePath; + bool newlyCreated{false}; + }; + + std::map<juce::String, Object> objects; + + int objectsCreated{0}; + int audioFilesImported{0}; + int objectTemplatesApplied{0}; + + juce::String errorMessage; + }; + + namespace Task + { + struct Options + { + std::vector<Import::Item> importItems; + Import::ContainerNameExistsOption containerNameExistsOption; + Import::ApplyTemplateOption applyTemplateOption; + juce::String importDestination; + std::vector<Import::HierarchyMappingNode> hierarchyMappingNodeList; + juce::String selectObjectsOnImportCommand; + bool applyTemplateFeatureEnabled{false}; + bool undoGroupFeatureEnabled{false}; + bool waqlEnabled{false}; + juce::String objectLanguage; + }; + } // namespace Task +} // namespace AK::WwiseTransfer::Import + +template <> +struct juce::VariantConverter<AK::WwiseTransfer::Import::ContainerNameExistsOption> +{ + static AK::WwiseTransfer::Import::ContainerNameExistsOption fromVar(const juce::var& v) + { + return static_cast<AK::WwiseTransfer::Import::ContainerNameExistsOption>(int(v)); + } + + static juce::var toVar(AK::WwiseTransfer::Import::ContainerNameExistsOption option) + { + return int(option); + } +}; + +template <> +struct juce::VariantConverter<AK::WwiseTransfer::Import::AudioFilenameExistsOption> +{ + static AK::WwiseTransfer::Import::AudioFilenameExistsOption fromVar(const juce::var& v) + { + return static_cast<AK::WwiseTransfer::Import::AudioFilenameExistsOption>(int(v)); + } + + static juce::var toVar(AK::WwiseTransfer::Import::AudioFilenameExistsOption option) + { + return int(option); + } +}; + +template <> +struct juce::VariantConverter<AK::WwiseTransfer::Import::ApplyTemplateOption> +{ + static AK::WwiseTransfer::Import::ApplyTemplateOption fromVar(const juce::var& v) + { + return static_cast<AK::WwiseTransfer::Import::ApplyTemplateOption>(int(v)); + } + + static juce::var toVar(AK::WwiseTransfer::Import::ApplyTemplateOption option) + { + return int(option); + } +}; + +template <> +struct juce::VariantConverter<AK::WwiseTransfer::Import::ObjectStatus> +{ + static AK::WwiseTransfer::Import::ObjectStatus fromVar(const juce::var& v) + { + return static_cast<AK::WwiseTransfer::Import::ObjectStatus>(int(v)); + } + + static juce::var toVar(AK::WwiseTransfer::Import::ObjectStatus option) + { + return int(option); + } +}; + +template <> +struct juce::VariantConverter<AK::WwiseTransfer::Import::WavStatus> +{ + static AK::WwiseTransfer::Import::WavStatus fromVar(const juce::var& v) + { + return static_cast<AK::WwiseTransfer::Import::WavStatus>(int(v)); + } + + static juce::var toVar(AK::WwiseTransfer::Import::WavStatus option) + { + return int(option); + } +}; diff --git a/src/shared/Model/Waapi.h b/src/shared/Model/Waapi.h @@ -0,0 +1,70 @@ +#pragma once + +#include "AK/WwiseAuthoringAPI/AkAutobahn/AkJson.h" +#include "Helpers/WwiseHelper.h" +#include "Model/Wwise.h" + +#include <juce_gui_basics/juce_gui_basics.h> +#include <set> + +namespace AK::WwiseTransfer::Waapi +{ + struct ImportItemRequest + { + juce::String path; + juce::String originalsSubFolder; + juce::String renderFilePath; + }; + + struct ProjectInfo + { + juce::String projectPath; + juce::String projectId; + }; + + struct ObjectResponse + { + ObjectResponse(AK::WwiseAuthoringAPI::AkJson json) + : id(json.HasKey("id") ? juce::String(json["id"].GetVariant().GetString()) : "") + , name(json.HasKey("name") ? json["name"].GetVariant().GetString() : "") + , type(WwiseHelper::stringToObjectType(json.HasKey("type") ? json["type"].GetVariant().GetString() : "")) + , path(json.HasKey("path") ? json["path"].GetVariant().GetString() : "") + , originalWavFilePath(json.HasKey("sound:originalWavFilePath") ? json["sound:originalWavFilePath"].GetVariant().GetString() : "") + { + } + + ObjectResponse() = default; + + bool operator==(const ObjectResponse& other) const + { + return path == other.path && id == other.id; + } + + bool operator<(const ObjectResponse& other) const + { + return path + id < other.path + other.id; + } + + juce::String id; + juce::String name; + Wwise::ObjectType type; + juce::String path; + juce::String originalWavFilePath; + }; + + using ObjectResponseSet = std::set<ObjectResponse>; + + struct PastePropertiesRequest + { + juce::String source; + std::vector<juce::String> targets; + }; + + template <typename Result> + struct Response + { + bool status = false; + Result result; + juce::String errorMessage; + }; +} // namespace AK::WwiseTransfer::Waapi diff --git a/src/shared/Model/Wwise.h b/src/shared/Model/Wwise.h @@ -0,0 +1,98 @@ +#pragma once + +#include <juce_gui_basics/juce_gui_basics.h> + +namespace AK::WwiseTransfer::Wwise +{ + enum class ImportObjectType + { + SFX, + Voice, + Music + }; + + enum class ImportOperation + { + CreateNew, + UseExisting, + ReplaceExisting + }; + + enum class ObjectType + { + Unknown, + ActorMixer, + AudioFileSource, + BlendContainer, + PhysicalFolder, + RandomContainer, + SequenceContainer, + SoundSFX, + SoundVoice, + SwitchContainer, + VirtualFolder, + WorkUnit, + Sound + }; + + struct Version + { + int year{}; + int major{}; + int minor{}; + int build{}; + + bool operator<(const Version& other) const + { + return year < other.year || + (year == other.year && major < other.major) || + (year == other.year && major == other.major && minor < other.minor) || + (year == other.year && major == other.major && minor == other.minor && build < other.build); + } + + bool operator>(const Version& other) const + { + return other < *this; + } + + bool operator<=(const Version& other) const + { + return !(*this > other); + } + + bool operator>=(const Version& other) const + { + return !(*this < other); + } + + bool operator==(const Version& other) const + { + return year == other.year && major == other.major && minor == other.minor && build == other.build; + } + + bool operator!=(const Version& other) const + { + return !(*this == other); + } + + friend juce::String& operator<<(juce::String& out, const Version& v) + { + out << v.year << "." << v.major << "." << v.minor << "." << v.build; + return out; + } + }; +} // namespace AK::WwiseTransfer::Wwise + +template <> +struct juce::VariantConverter<AK::WwiseTransfer::Wwise::ObjectType> +{ + static AK::WwiseTransfer::Wwise::ObjectType fromVar(const juce::var v) + { + return static_cast<AK::WwiseTransfer::Wwise::ObjectType>(int(v)); + } + + static juce::var toVar(AK::WwiseTransfer::Wwise::ObjectType objectType) + { + return int(objectType); + } +}; diff --git a/src/shared/Persistance/ApplicationProperties.cpp b/src/shared/Persistance/ApplicationProperties.cpp @@ -0,0 +1,117 @@ +#include "ApplicationProperties.h" + +namespace AK::WwiseTransfer +{ + namespace ApplicationPropertyConstants + { + // Potentially grab from local install (future) + const juce::String waapiIpPropertyName = "waapiIp"; + const juce::String waapiIpDefaultPropertyValue = "127.0.0.1"; + + const juce::String waapiPortPropertyName = "waapiPort"; + constexpr int waapiPortDefaultPropertyValue = 8080; + + const juce::String previewRefreshIntervalPropertyName = "previewRefreshInterval"; + constexpr int previewRefreshIntervalValue = 100; + + const juce::String recentHierarchyMappingPresetsPropertyName = "recentHierarchyMappingPresets"; + const juce::String recentHierarchyMappingPresetsPropertyValue = ""; + + const juce::String scaleFactorOverridePropertyName = "scaleFactorOverride"; + constexpr double scaleFactorOverridePropertyValue = 0; + + const juce::String showSilentIncrementWarningName = "showSilentIncrementWarning"; + constexpr bool showSilentIncrementWarningValue = true; + } // namespace ApplicationPropertyConstants + + ApplicationProperties::ApplicationProperties(const juce::String& applicationName) + { + juce::PropertiesFile::Options opts; + opts.applicationName = applicationName; + opts.filenameSuffix = ".settings"; + opts.folderName = applicationName + "/Settings"; + opts.osxLibrarySubFolder = "Application Support"; + setStorageParameters(opts); + + // Create the settings file the first time. We might want to install a default one though + using namespace ApplicationPropertyConstants; + auto file = getUserSettings()->getFile(); + if(!file.exists()) + { + getUserSettings()->setValue(waapiIpPropertyName, waapiIpDefaultPropertyValue); + getUserSettings()->setValue(waapiPortPropertyName, waapiPortDefaultPropertyValue); + getUserSettings()->setValue(previewRefreshIntervalPropertyName, previewRefreshIntervalValue); + getUserSettings()->save(); + } + } + + juce::String ApplicationProperties::getWaapiIp() + { + using namespace ApplicationPropertyConstants; + return getUserSettings()->getValue(waapiIpPropertyName, waapiIpDefaultPropertyValue); + } + + int ApplicationProperties::getWaapiPort() + { + using namespace ApplicationPropertyConstants; + return getUserSettings()->getIntValue(waapiPortPropertyName, waapiPortDefaultPropertyValue); + } + + int ApplicationProperties::getPreviewRefreshInterval() + { + using namespace ApplicationPropertyConstants; + return getUserSettings()->getIntValue(previewRefreshIntervalPropertyName, previewRefreshIntervalValue); + } + + juce::StringArray ApplicationProperties::getRecentHierarchyMappingPresets() + { + using namespace ApplicationPropertyConstants; + auto recentHierarchyMappingPresetsAsString = getUserSettings()->getValue(recentHierarchyMappingPresetsPropertyName, recentHierarchyMappingPresetsPropertyValue); + + juce::StringArray recentHierarchyMappingPresets; + recentHierarchyMappingPresets.addTokens(recentHierarchyMappingPresetsAsString, ";", ""); + + return recentHierarchyMappingPresets; + } + void ApplicationProperties::addRecentHierarchyMappingPreset(const juce::String& path) + { + using namespace ApplicationPropertyConstants; + + auto recentHierarchyMappingPresets = getRecentHierarchyMappingPresets(); + + if(recentHierarchyMappingPresets.contains(path)) + { + recentHierarchyMappingPresets.removeString(path); + } + + recentHierarchyMappingPresets.insert(0, path); + + auto recentHierarchyMappingPresetsAsString = recentHierarchyMappingPresets.joinIntoString(";", 0, 10); + + getUserSettings()->setValue(recentHierarchyMappingPresetsPropertyName, recentHierarchyMappingPresetsAsString); + } + + void ApplicationProperties::clearRecentHierarchyMappingPresets() + { + using namespace ApplicationPropertyConstants; + getUserSettings()->setValue(recentHierarchyMappingPresetsPropertyName, ""); + } + + double ApplicationProperties::getScaleFactorOverride() + { + using namespace ApplicationPropertyConstants; + return getUserSettings()->getDoubleValue(scaleFactorOverridePropertyName, scaleFactorOverridePropertyValue); + } + + bool ApplicationProperties::getShowSilentIncrementWarning() + { + using namespace ApplicationPropertyConstants; + return getUserSettings()->getBoolValue(showSilentIncrementWarningName, showSilentIncrementWarningValue); + } + + void ApplicationProperties::setShowSilentIncrementWarning(bool value) + { + using namespace ApplicationPropertyConstants; + getUserSettings()->setValue(showSilentIncrementWarningName, value); + } +} // namespace AK::WwiseTransfer diff --git a/src/shared/Persistance/ApplicationProperties.h b/src/shared/Persistance/ApplicationProperties.h @@ -0,0 +1,25 @@ +#pragma once + +#include <juce_data_structures/juce_data_structures.h> + +namespace AK::WwiseTransfer +{ + class ApplicationProperties : juce::ApplicationProperties + { + public: + explicit ApplicationProperties(const juce::String& applicationName); + + juce::String getWaapiIp(); + int getWaapiPort(); + int getPreviewRefreshInterval(); + juce::StringArray getRecentHierarchyMappingPresets(); + void addRecentHierarchyMappingPreset(const juce::String& path); + void clearRecentHierarchyMappingPresets(); + double getScaleFactorOverride(); + bool getShowSilentIncrementWarning(); + void setShowSilentIncrementWarning(bool value); + + private: + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(ApplicationProperties) + }; +} // namespace AK::WwiseTransfer diff --git a/src/shared/Persistance/ApplicationState.h b/src/shared/Persistance/ApplicationState.h @@ -0,0 +1,77 @@ +#pragma once + +#include "FeatureSupport.h" +#include "Helpers/ImportHelper.h" +#include "Model/IDs.h" +#include "Model/Import.h" +#include "Model/Wwise.h" + +#include <juce_gui_basics/juce_gui_basics.h> + +namespace AK::WwiseTransfer::ApplicationState +{ + inline juce::ValueTree create() + { + auto applicationState = juce::ValueTree(IDs::application); + applicationState.setProperty(IDs::projectPath, "", nullptr); + applicationState.setProperty(IDs::projectId, "", nullptr); + applicationState.setProperty(IDs::originalsSubfolder, "", nullptr); + applicationState.setProperty(IDs::originalsSubfolderValid, true, nullptr); + applicationState.setProperty(IDs::originalsSubfolderErrorMessage, "", nullptr); + applicationState.setProperty(IDs::originalsFolder, "", nullptr); + applicationState.setProperty(IDs::languageSubfolder, "SFX", nullptr); + + applicationState.setProperty(IDs::importDestination, "\\Actor-Mixer Hierarchy\\Default Work Unit", nullptr); + applicationState.setProperty(IDs::importDestinationValid, true, nullptr); + applicationState.setProperty(IDs::importDestinationErrorMessage, "", nullptr); + applicationState.setProperty(IDs::importDestinationType, juce::VariantConverter<Wwise::ObjectType>::toVar(Wwise::ObjectType::WorkUnit), nullptr); + + applicationState.setProperty(IDs::containerNameExists, juce::VariantConverter<Import::ContainerNameExistsOption>::toVar(Import::ContainerNameExistsOption::UseExisting), nullptr); + applicationState.setProperty(IDs::audioFileNameExists, juce::VariantConverter<Import::AudioFilenameExistsOption>::toVar(Import::AudioFilenameExistsOption::Replace), nullptr); + applicationState.setProperty(IDs::applyTemplate, juce::VariantConverter<Import::ApplyTemplateOption>::toVar(Import::ApplyTemplateOption::NewObjectCreationOnly), nullptr); + + applicationState.setProperty(IDs::wwiseObjectsChanged, false, nullptr); + + auto version = juce::ValueTree(IDs::version); + version.setProperty(IDs::year, 0, nullptr); + version.setProperty(IDs::major, 0, nullptr); + version.setProperty(IDs::minor, 0, nullptr); + version.setProperty(IDs::build, 0, nullptr); + applicationState.appendChild(version, nullptr); + + auto featureSupport = juce::ValueTree(IDs::featureSupport); + + featureSupport.setProperty(IDs::selectObjectsOnImportCommand, FeatureSupportConstants::FindInProjectExplorerSelectionChannel1, nullptr); + featureSupport.setProperty(IDs::applyTemplateFeatureEnabled, false, nullptr); + featureSupport.setProperty(IDs::undoGroupFeatureEnabled, false, nullptr); + featureSupport.setProperty(IDs::waqlEnabled, false, nullptr); + featureSupport.setProperty(IDs::originalsFolderLookupEnabled, false, nullptr); + + applicationState.appendChild(featureSupport, nullptr); + + auto previewItems = juce::ValueTree(IDs::previewItems); + applicationState.appendChild(previewItems, nullptr); + + auto physicalFolder = Import::HierarchyMappingNode("$project", Wwise::ObjectType::PhysicalFolder); + auto soundSfx = Import::HierarchyMappingNode("$region", Wwise::ObjectType::SoundSFX); + + auto hierarchyMapping = juce::ValueTree(IDs::hierarchyMapping); + hierarchyMapping.setProperty(IDs::selectedRow, 0, nullptr); + hierarchyMapping.appendChild(ImportHelper::hierarchyMappingNodeToValueTree(physicalFolder), nullptr); + hierarchyMapping.appendChild(ImportHelper::hierarchyMappingNodeToValueTree(soundSfx), nullptr); + + applicationState.appendChild(hierarchyMapping, nullptr); + + applicationState.setProperty(IDs::previewLoading, false, nullptr); + + applicationState.setProperty(IDs::sessionName, "", nullptr); + + applicationState.setProperty(IDs::collapsedUI, false, nullptr); + + auto languages = juce::ValueTree(IDs::languages); + applicationState.appendChild(languages, nullptr); + + // Returning by value because juce::ValueTree uses value semantics. No internal copies are made when passing the tree around. + return applicationState; + }; +} // namespace AK::WwiseTransfer::ApplicationState diff --git a/src/shared/Persistance/ApplicationStateValidator.cpp b/src/shared/Persistance/ApplicationStateValidator.cpp @@ -0,0 +1,203 @@ +#include "ApplicationStateValidator.h" + +#include "Helpers/ImportHelper.h" +#include "Helpers/WwiseHelper.h" +#include "Model/IDs.h" + +namespace AK::WwiseTransfer::ApplicationState +{ + Validator::Validator(juce::ValueTree appState) + : applicationState(appState) + { + applicationState.addListener(this); + } + + Validator::~Validator() + { + applicationState.removeListener(this); + } + + void Validator::valueTreePropertyChanged(juce::ValueTree& valueTree, const juce::Identifier& property) + { + if(valueTree.getType() == IDs::application) + { + if(property == IDs::originalsSubfolder || property == IDs::languageSubfolder) + { + const juce::String originalsFolder = valueTree[IDs::originalsFolder]; + const juce::String originalsSubfolder = valueTree[IDs::originalsSubfolder]; + const juce::String languageSubfolder = valueTree[IDs::languageSubfolder]; + + auto isValid = validateOriginalsSubfolder(originalsFolder, languageSubfolder, originalsSubfolder); + juce::String errorMessage = isValid ? "" : "Invalid originals subfolder"; + + valueTree.setPropertyExcludingListener(this, IDs::originalsSubfolderValid, isValid, nullptr); + valueTree.setPropertyExcludingListener(this, IDs::originalsSubfolderErrorMessage, errorMessage, nullptr); + } + else if(property == IDs::importDestination || property == IDs::importDestinationType) + { + const juce::String importDestination = valueTree[IDs::importDestination]; + const auto importDestinationType = juce::VariantConverter<Wwise::ObjectType>::fromVar(valueTree[IDs::importDestinationType]); + + auto isValid = validateImportDestination(importDestination, importDestinationType); + juce::String errorMessage = isValid ? "" : "Invalid import destination"; + + valueTree.setPropertyExcludingListener(this, IDs::importDestinationValid, isValid, nullptr); + valueTree.setPropertyExcludingListener(this, IDs::importDestinationErrorMessage, errorMessage, nullptr); + } + } + else if(valueTree.getType() == IDs::hierarchyMappingNode) + { + if(property == IDs::objectType) + { + auto hierarchyMapping = valueTree.getParent(); + validateHierarchyMapping(hierarchyMapping); + } + else if(property == IDs::propertyTemplatePath || property == IDs::propertyTemplatePathType) + { + validatePropertyTemplatePath(valueTree); + } + else if(property == IDs::objectName) + { + validateObjectName(valueTree); + } + } + } + + void Validator::valueTreeChildAdded(juce::ValueTree& parent, juce::ValueTree& child) + { + if(parent.getType() == IDs::hierarchyMapping) + { + validateHierarchyMapping(parent); + } + + if(child.getType() == IDs::hierarchyMappingNode) + { + validatePropertyTemplatePath(child); + validateObjectName(child); + } + } + + void Validator::valueTreeChildRemoved(juce::ValueTree& parent, juce::ValueTree& child, int indexOfChild) + { + if(parent.getType() == IDs::hierarchyMapping) + { + validateHierarchyMapping(parent); + } + } + + void Validator::valueTreeChildOrderChanged(juce::ValueTree& parent, int oldIndex, int newIndex) + { + if(parent.getType() == IDs::hierarchyMapping) + { + validateHierarchyMapping(parent); + } + } + + bool Validator::validateOriginalsSubfolder(const juce::String& originalsFolder, const juce::String& languageSubfolder, const juce::String& originalsSubfolder) + { + if(originalsFolder.isEmpty() || originalsSubfolder.isEmpty()) + return true; + + auto originalsFolderWithLanguageSubfolder = juce::File(originalsFolder).getChildFile(languageSubfolder); + + auto originalsSubfolderAbsolutePath = originalsFolderWithLanguageSubfolder.getChildFile(originalsSubfolder); + + return originalsSubfolderAbsolutePath.isAChildOf(originalsFolderWithLanguageSubfolder); + } + + bool Validator::validateImportDestination(const juce::String& importDestination, Wwise::ObjectType objectType) + { + using namespace Wwise; + + static const std::initializer_list<ObjectType> allowedObjectTypes = {ObjectType::VirtualFolder, ObjectType::WorkUnit, + ObjectType::RandomContainer, ObjectType::BlendContainer, ObjectType::ActorMixer, ObjectType::SwitchContainer}; + + static const juce::String pathPrefix = "\\Actor-Mixer Hierarchy"; + + auto allowedType = std::find(allowedObjectTypes.begin(), allowedObjectTypes.end(), + objectType) != allowedObjectTypes.end(); + + auto allowedPathPrefix = importDestination.startsWith(pathPrefix); + + return importDestination.isNotEmpty() && !importDestination.endsWith("\\") && allowedType && allowedPathPrefix; + } + + void Validator::validatePropertyTemplatePath(juce::ValueTree hierarchyMappingNode) + { + using namespace Wwise; + + const juce::String propertyTemplatePath = hierarchyMappingNode[IDs::propertyTemplatePath]; + const auto propertyTemplatePathType = juce::VariantConverter<Wwise::ObjectType>::fromVar(hierarchyMappingNode[IDs::propertyTemplatePathType]); + + static const std::initializer_list<ObjectType> allowedObjectTypes = {ObjectType::WorkUnit, + ObjectType::RandomContainer, ObjectType::BlendContainer, ObjectType::ActorMixer, ObjectType::SwitchContainer, + ObjectType::Sound}; + + static const juce::String pathPrefix = "\\Actor-Mixer Hierarchy"; + + auto allowedType = std::find(allowedObjectTypes.begin(), allowedObjectTypes.end(), + propertyTemplatePathType) != allowedObjectTypes.end() || + propertyTemplatePathType == ObjectType::Unknown; + + auto allowedPathPrefix = propertyTemplatePath.startsWith(pathPrefix); + + bool isValid = propertyTemplatePath.isEmpty() || allowedType && allowedPathPrefix; + juce::String errorMessage = isValid ? "" : "Invalid property template path"; + + hierarchyMappingNode.setPropertyExcludingListener(this, IDs::propertyTemplatePathValid, isValid, nullptr); + hierarchyMappingNode.setPropertyExcludingListener(this, IDs::propertyTemplatePathErrorMessage, errorMessage, nullptr); + } + + void Validator::validateObjectName(juce::ValueTree hierarchyMappingNode) + { + juce::String objectName = hierarchyMappingNode[IDs::objectName]; + + bool isValid = objectName.isNotEmpty(); + juce::String errorMessage = isValid ? "" : "Object name cannot be empty"; + + hierarchyMappingNode.setPropertyExcludingListener(this, IDs::objectNameValid, isValid, nullptr); + hierarchyMappingNode.setPropertyExcludingListener(this, IDs::objectNameErrorMessage, errorMessage, nullptr); + } + + void Validator::validateHierarchyMapping(juce::ValueTree hierarchyMapping) + { + // TODO: Should error be reported on parent or child? + auto hierarchyMappingNodeList = ImportHelper::valueTreeToHierarchyMappingNodeList(hierarchyMapping); + + for(int i = 0; i < hierarchyMappingNodeList.size(); ++i) + { + auto& child = hierarchyMappingNodeList.at(i); + + bool isValid = true; + juce::String errorMessage; + + // Last item must be SoundSFX, report this error above any others + if(i == hierarchyMappingNodeList.size() - 1) + { + if(child.type != Wwise::ObjectType::SoundSFX && child.type != Wwise::ObjectType::SoundVoice) + { + isValid = false; + errorMessage << "Last item must be of type 'SoundSFX' or 'Sound Voice'"; + } + } + + // Since we have limited space in the tooltip, do not do any other validation if an error was already detected + if(isValid && i != 0) + { + auto& parent = hierarchyMappingNodeList.at(i - 1); + + if(parent.type != Wwise::ObjectType::Unknown && + child.type != Wwise::ObjectType::Unknown && + !WwiseHelper::validateObjectTypeParentChildRelationShip(parent.type, child.type)) + { + isValid = false; + errorMessage << "'" << WwiseHelper::objectTypeToReadableString(child.type) << "' cannot be a child of '" << WwiseHelper::objectTypeToReadableString(parent.type) << "'"; + } + } + + auto hierarchyMappingNode = hierarchyMapping.getChild(i); + hierarchyMappingNode.setPropertyExcludingListener(this, IDs::objectTypeValid, isValid, nullptr); + hierarchyMappingNode.setPropertyExcludingListener(this, IDs::objectTypeErrorMessage, errorMessage, nullptr); + } + } +} // namespace AK::WwiseTransfer::ApplicationState diff --git a/src/shared/Persistance/ApplicationStateValidator.h b/src/shared/Persistance/ApplicationStateValidator.h @@ -0,0 +1,31 @@ +#pragma once + +#include "Core/DawContext.h" +#include "Model/Wwise.h" + +#include <juce_data_structures/juce_data_structures.h> + +namespace AK::WwiseTransfer::ApplicationState +{ + class Validator + : juce::ValueTree::Listener + { + public: + Validator(juce::ValueTree appState); + ~Validator(); + + private: + juce::ValueTree applicationState; + + void valueTreePropertyChanged(juce::ValueTree& valueTree, const juce::Identifier& property) override; + void valueTreeChildAdded(juce::ValueTree& parent, juce::ValueTree& child) override; + void valueTreeChildRemoved(juce::ValueTree& parent, juce::ValueTree& child, int indexOfChild) override; + void valueTreeChildOrderChanged(juce::ValueTree& parent, int oldIndex, int newIndex) override; + + bool validateImportDestination(const juce::String& importDestination, Wwise::ObjectType objectType); + bool validateOriginalsSubfolder(const juce::String& originalsFolder, const juce::String& languageSubfolder, const juce::String& originalsSubfolder); + void validatePropertyTemplatePath(juce::ValueTree hierarchyMappingNode); + void validateObjectName(juce::ValueTree hierarchyMappingNode); + void validateHierarchyMapping(juce::ValueTree hierarchyMapping); + }; +} // namespace AK::WwiseTransfer::ApplicationState diff --git a/src/shared/Persistance/FeatureSupport.cpp b/src/shared/Persistance/FeatureSupport.cpp @@ -0,0 +1,51 @@ +#include "FeatureSupport.h" + +#include "Helpers/WwiseHelper.h" +#include "Model/IDs.h" + +namespace AK::WwiseTransfer +{ + FeatureSupport::FeatureSupport(juce::ValueTree appState, WaapiClient& waapiClient) + : applicationState(appState) + , version(applicationState.getChildWithName(IDs::version)) + , waapiClient(waapiClient) + { + auto featureSupport = applicationState.getChildWithName(IDs::featureSupport); + selectObjectsOnImportCommand.referTo(featureSupport, IDs::selectObjectsOnImportCommand, nullptr); + applyTemplateFeatureEnabled.referTo(featureSupport, IDs::applyTemplateFeatureEnabled, nullptr); + undoGroupFeatureEnabled.referTo(featureSupport, IDs::undoGroupFeatureEnabled, nullptr); + waqlEnabled.referTo(featureSupport, IDs::waqlEnabled, nullptr); + originalsFolderLookupEnabled.referTo(featureSupport, IDs::originalsFolderLookupEnabled, nullptr); + + applicationState.addListener(this); + } + + FeatureSupport::~FeatureSupport() + { + applicationState.removeListener(this); + } + + void FeatureSupport::valueTreePropertyChanged(juce::ValueTree& treeWhosePropertyHasChanged, + const juce::Identifier& property) + { + if(treeWhosePropertyHasChanged.getType() == IDs::application && property == IDs::waapiConnected) + { + auto onGetVersionAsync = [this](const auto& response) + { + using namespace FeatureSupportConstants; + + auto versionValueTree = WwiseHelper::versionToValueTree(response.result); + + version.copyPropertiesAndChildrenFrom(versionValueTree, nullptr); + + selectObjectsOnImportCommand = response.result >= v2022_1_0_0 ? FindInProjectExplorerSelectionChannel1 : FindInProjectExplorerSyncGroup1; + applyTemplateFeatureEnabled = response.result >= v2022_1_0_0; + undoGroupFeatureEnabled = response.result >= v2021_1_10_0; + waqlEnabled = response.result >= v2021_1_0_0; + originalsFolderLookupEnabled = response.result >= v2022_1_0_0; + }; + + waapiClient.getVersionAsync(onGetVersionAsync); + } + } +} // namespace AK::WwiseTransfer diff --git a/src/shared/Persistance/FeatureSupport.h b/src/shared/Persistance/FeatureSupport.h @@ -0,0 +1,42 @@ +#pragma once + +#include "Core/WaapiClient.h" +#include "Model/Wwise.h" + +#include <juce_gui_basics/juce_gui_basics.h> + +namespace AK::WwiseTransfer +{ + namespace FeatureSupportConstants + { + const juce::String FindInProjectExplorerSelectionChannel1 = "FindInProjectExplorerSelectionChannel1"; + const juce::String FindInProjectExplorerSyncGroup1 = "FindInProjectExplorerSyncGroup1"; + const Wwise::Version v2022_1_0_0 = {2022, 1, 0, 0}; + const Wwise::Version v2021_1_0_0 = {2021, 1, 0, 0}; + const Wwise::Version v2021_1_10_0 = {2021, 1, 10, 0}; + } // namespace FeatureSupportConstants + + class FeatureSupport + : juce::ValueTree::Listener + { + public: + FeatureSupport(juce::ValueTree appState, WaapiClient& waapiClient); + ~FeatureSupport(); + + private: + void valueTreePropertyChanged(juce::ValueTree& treeWhosePropertyHasChanged, + const juce::Identifier& property) override; + + WaapiClient& waapiClient; + + juce::ValueTree applicationState; + juce::ValueTree version; + + juce::ValueTree featureSupport; + juce::CachedValue<juce::String> selectObjectsOnImportCommand; + juce::CachedValue<bool> applyTemplateFeatureEnabled; + juce::CachedValue<bool> undoGroupFeatureEnabled; + juce::CachedValue<bool> waqlEnabled; + juce::CachedValue<bool> originalsFolderLookupEnabled; + }; +} // namespace AK::WwiseTransfer diff --git a/src/shared/Persistance/PersistanceSupport.cpp b/src/shared/Persistance/PersistanceSupport.cpp @@ -0,0 +1,151 @@ +#include "PersistanceSupport.h" + +#include "Model/IDs.h" + +namespace AK::WwiseTransfer +{ + namespace PersistanceSupportConstants + { + const std::initializer_list<juce::Identifier> fieldsToPersist{IDs::originalsSubfolder, IDs::importDestination, + IDs::originalsSubfolder, IDs::containerNameExists, IDs::applyTemplate}; + + const std::initializer_list<juce::Identifier> hierarchyMappingNodeFieldsToPersist{IDs::objectName, IDs::objectType, IDs::propertyTemplatePath, IDs::propertyTemplatePathEnabled, IDs::objectLanguage}; + } // namespace PersistanceSupportConstants + + PersistanceSupport::PersistanceSupport(juce::ValueTree appState, DawContext& dawContext) + : dawContext(dawContext) + , applicationState(appState) + { + applicationState.addListener(this); + } + + PersistanceSupport::~PersistanceSupport() + { + applicationState.removeListener(this); + } + + void PersistanceSupport::valueTreePropertyChanged(juce::ValueTree& treeWhosePropertyHasChanged, const juce::Identifier& property) + { + using namespace PersistanceSupportConstants; + + juce::String projectId = applicationState[IDs::projectId]; + + auto treeType = treeWhosePropertyHasChanged.getType(); + + if(treeType == IDs::application && property == IDs::sessionName) + { + juce::ValueTree savedState; + + juce::String cacheKey = dawContext.getSessionName(); + + auto it = stateCache.find(cacheKey); + + if(it != stateCache.end()) + { + savedState = it->second; + } + else + { + savedState = dawContext.retrieveState(); + if(savedState.isValid()) + stateCache[cacheKey] = savedState; + } + + if(savedState.isValid()) + { + // Only apply fields we care about in case user added/tampered with state fields + for(const auto& field : fieldsToPersist) + { + if(savedState.hasProperty(field)) + applicationState.setPropertyExcludingListener(this, field, savedState[field], nullptr); + } + + auto savedHierarchyMapping = savedState.getChildWithName(IDs::hierarchyMapping); + + if(savedHierarchyMapping.isValid()) + { + juce::ValueTree sanitizedHiearchyMapping(IDs::hierarchyMapping); + + for(int i = 0; i < savedHierarchyMapping.getNumChildren(); ++i) + { + juce::ValueTree sanitizedHierarchyMappingNode(IDs::hierarchyMappingNode); + + for(const auto& field : hierarchyMappingNodeFieldsToPersist) + sanitizedHierarchyMappingNode.setPropertyExcludingListener(this, field, savedHierarchyMapping.getChild(i)[field], nullptr); + + sanitizedHiearchyMapping.addChild(sanitizedHierarchyMappingNode, i, nullptr); + } + + auto existingHierarchyMapping = applicationState.getChildWithName(IDs::hierarchyMapping); + + // Since there is no way to exclude this as a listener for copyPropertiesAndChildrenFrom, remove this as listener temporarily + applicationState.removeListener(this); + existingHierarchyMapping.copyPropertiesAndChildrenFrom(sanitizedHiearchyMapping, nullptr); + applicationState.addListener(this); + } + } + } + else if(treeType == IDs::application && std::find(fieldsToPersist.begin(), fieldsToPersist.end(), property) != fieldsToPersist.end() || + treeType == IDs::hierarchyMappingNode && std::find(hierarchyMappingNodeFieldsToPersist.begin(), hierarchyMappingNodeFieldsToPersist.end(), property) != hierarchyMappingNodeFieldsToPersist.end()) + { + saveState(); + } + } + + void PersistanceSupport::valueTreeChildRemoved(juce::ValueTree& parent, juce::ValueTree& child, int indexOfChild) + { + juce::ignoreUnused(child, indexOfChild); + + if(parent.getType() == IDs::hierarchyMapping) + saveState(); + } + + void PersistanceSupport::valueTreeChildOrderChanged(juce::ValueTree& parent, int oldIndex, int newIndex) + { + juce::ignoreUnused(oldIndex, newIndex); + + if(parent.getType() == IDs::hierarchyMapping) + saveState(); + } + + void PersistanceSupport::saveState() + { + // For reasons of simplicity, we store the whole state everytime. It would be possible to retrieve the current state, + // and only modify the value that has changed. It would be more complicated and due to the fact that the size of the state is quite small, + // not provide much performance gain. + using namespace PersistanceSupportConstants; + + juce::String projectId = applicationState[IDs::projectId]; + + if(projectId.isNotEmpty()) + { + juce::ValueTree stateToBeSaved(IDs::application); + + for(const auto& field : fieldsToPersist) + stateToBeSaved.setPropertyExcludingListener(this, field, applicationState[field], nullptr); + + juce::ValueTree hierarchyMappingToBeSaved(IDs::hierarchyMapping); + auto hierarchyMapping = applicationState.getChildWithName(IDs::hierarchyMapping).createCopy(); + + for(int i = 0; i < hierarchyMapping.getNumChildren(); ++i) + { + juce::ValueTree hierarchyMappingNodeToBeSaved(IDs::hierarchyMappingNode); + + for(const auto& field : hierarchyMappingNodeFieldsToPersist) + hierarchyMappingNodeToBeSaved.setPropertyExcludingListener(this, field, hierarchyMapping.getChild(i)[field], nullptr); + + hierarchyMappingToBeSaved.addChild(hierarchyMappingNodeToBeSaved, i, nullptr); + } + + stateToBeSaved.appendChild(hierarchyMappingToBeSaved, nullptr); + + juce::ValueTree savedState = dawContext.retrieveState(); + + if(!stateToBeSaved.isEquivalentTo(savedState)) + { + dawContext.saveState(stateToBeSaved); + stateCache[dawContext.getSessionName()] = stateToBeSaved; + } + } + } +} // namespace AK::WwiseTransfer diff --git a/src/shared/Persistance/PersistanceSupport.h b/src/shared/Persistance/PersistanceSupport.h @@ -0,0 +1,29 @@ +#pragma once + +#include "Core/DawContext.h" +#include "Model/Import.h" + +#include <unordered_map> + +namespace AK::WwiseTransfer +{ + class PersistanceSupport + : juce::ValueTree::Listener + { + public: + PersistanceSupport(juce::ValueTree appState, DawContext& dawContext); + virtual ~PersistanceSupport(); + + private: + DawContext& dawContext; + juce::ValueTree applicationState; + + std::unordered_map<juce::String, juce::ValueTree> stateCache; + + void valueTreePropertyChanged(juce::ValueTree& treeWhosePropertyHasChanged, const juce::Identifier& property) override; + void valueTreeChildRemoved(juce::ValueTree& parent, juce::ValueTree& child, int indexOfChild) override; + void valueTreeChildOrderChanged(juce::ValueTree& parent, int oldIndex, int newIndex) override; + + void saveState(); + }; +} // namespace AK::WwiseTransfer diff --git a/src/shared/Persistance/WwiseProjectSupport.cpp b/src/shared/Persistance/WwiseProjectSupport.cpp @@ -0,0 +1,172 @@ +#include "WwiseProjectSupport.h" + +#include "Helpers/ImportHelper.h" +#include "Model/IDs.h" + +namespace AK::WwiseTransfer +{ + WwiseProjectSupport::WwiseProjectSupport(juce::ValueTree appState, WaapiClient& waapiClient) + : applicationState(appState) + , waapiClient(waapiClient) + , waapiConnected(applicationState, IDs::waapiConnected, nullptr) + , projectPath(applicationState, IDs::projectPath, nullptr) + , projectId(applicationState, IDs::projectId, nullptr) + , originalsFolder(applicationState, IDs::originalsFolder, nullptr) + , languageSubfolder(applicationState, IDs::languageSubfolder, nullptr) + , hierarchyMapping(applicationState.getChildWithName(IDs::hierarchyMapping)) + , languages(applicationState.getChildWithName(IDs::languages)) + { + auto featureSupport = applicationState.getChildWithName(IDs::featureSupport); + originalsFolderLookupEnabled.referTo(featureSupport, IDs::originalsFolderLookupEnabled, nullptr); + + applicationState.addListener(this); + } + + WwiseProjectSupport::~WwiseProjectSupport() + { + applicationState.removeListener(this); + } + + void WwiseProjectSupport::valueTreePropertyChanged(juce::ValueTree& treeWhosePropertyHasChanged, const juce::Identifier& property) + { + auto treeType = treeWhosePropertyHasChanged.getType(); + + if(treeType == IDs::application) + { + if(property == IDs::originalsFolderLookupEnabled) + { + originalsFolderLookupEnabled.forceUpdateOfCachedValue(); + if(originalsFolderLookupEnabled.get()) + { + loadOriginalsFolder(); + } + else + { + originalsFolder = ""; + } + } + else if(property == IDs::projectId) + { + // Project id is set to empty by the waapi client when it receives the project loaded event. + // This means that a project was loaded in wwise and that we should refresh the project info + projectId.forceUpdateOfCachedValue(); + if(projectId.get().isEmpty()) + { + loadProjectInfo(); + } + else + { + loadProjectLanguages(); + + if(originalsFolderLookupEnabled.get()) + { + loadOriginalsFolder(); + } + } + } + else if(property == IDs::waapiConnected) + { + waapiConnected.forceUpdateOfCachedValue(); + + if(waapiConnected.get()) + { + loadProjectInfo(); + } + else + { + projectPath = ""; + projectId = ""; + originalsFolder = ""; + } + } + } + else if(treeType == IDs::hierarchyMapping || + treeType == IDs::hierarchyMappingNode) + { + updateLanguageSubpath(); + } + } + + void WwiseProjectSupport::valueTreeChildAdded(juce::ValueTree& parentTree, juce::ValueTree& childWhichHasBeenAdded) + { + juce::ignoreUnused(childWhichHasBeenAdded); + + if(parentTree.getType() == IDs::hierarchyMapping) + { + updateLanguageSubpath(); + } + } + + void WwiseProjectSupport::valueTreeChildRemoved(juce::ValueTree& parentTree, juce::ValueTree& childWhichHasBeenRemoved, int indexFromWhichChildWasRemoved) + { + juce::ignoreUnused(childWhichHasBeenRemoved, indexFromWhichChildWasRemoved); + + if(parentTree.getType() == IDs::hierarchyMapping) + { + updateLanguageSubpath(); + } + } + + void WwiseProjectSupport::valueTreeChildOrderChanged(juce::ValueTree& parentTreeWhoseChildrenHaveMoved, int oldIndex, int newIndex) + { + juce::ignoreUnused(oldIndex, newIndex); + + if(parentTreeWhoseChildrenHaveMoved.getType() == IDs::hierarchyMapping) + { + updateLanguageSubpath(); + } + } + + void WwiseProjectSupport::loadProjectInfo() + { + auto onGetProjectInfoAsync = [this](const auto& response) + { + projectPath = response.result.projectPath; + projectId = response.result.projectId; + }; + + waapiClient.getProjectInfoAsync(onGetProjectInfoAsync); + } + + void WwiseProjectSupport::loadProjectLanguages() + { + auto onGetProjectLanguages = [this](const auto& response) + { + if(response.status) + { + languages.copyPropertiesAndChildrenFrom(WwiseHelper::languagesToValueTree(response.result), nullptr); + } + }; + + waapiClient.getProjectLanguagesAsync(onGetProjectLanguages); + } + + void WwiseProjectSupport::loadOriginalsFolder() + { + auto onGetOriginalsFolderAsync = [this](const auto& response) + { + originalsFolder = response.result; + }; + + waapiClient.getOriginalsFolderAsync(onGetOriginalsFolderAsync); + } + + void WwiseProjectSupport::updateLanguageSubpath() + { + juce::String subfolder("SFX"); + + auto hierarchyMappingNodeList = ImportHelper::valueTreeToHierarchyMappingNodeList(hierarchyMapping); + + if(!hierarchyMappingNodeList.empty()) + { + auto lastNode = hierarchyMappingNodeList.back(); + + if(lastNode.type == Wwise::ObjectType::SoundVoice && lastNode.language.isNotEmpty()) + { + subfolder = juce::String("Voices") + juce::File::getSeparatorChar() + lastNode.language; + } + } + + languageSubfolder = subfolder; + } +} // namespace AK::WwiseTransfer diff --git a/src/shared/Persistance/WwiseProjectSupport.h b/src/shared/Persistance/WwiseProjectSupport.h @@ -0,0 +1,40 @@ +#pragma once + +#include "Core/WaapiClient.h" + +#include <juce_gui_basics/juce_gui_basics.h> + +namespace AK::WwiseTransfer +{ + class WwiseProjectSupport + : juce::ValueTree::Listener + { + public: + WwiseProjectSupport(juce::ValueTree appState, WaapiClient& waapiClient); + ~WwiseProjectSupport(); + + private: + WaapiClient& waapiClient; + + juce::ValueTree applicationState; + juce::ValueTree hierarchyMapping; + juce::ValueTree languages; + + juce::CachedValue<bool> waapiConnected; + juce::CachedValue<juce::String> projectPath; + juce::CachedValue<juce::String> projectId; + juce::CachedValue<bool> originalsFolderLookupEnabled; + juce::CachedValue<juce::String> originalsFolder; + juce::CachedValue<juce::String> languageSubfolder; + + void valueTreePropertyChanged(juce::ValueTree& treeWhosePropertyHasChanged, const juce::Identifier& property) override; + void valueTreeChildAdded(juce::ValueTree& parentTree, juce::ValueTree& childWhichHasBeenAdded) override; + void valueTreeChildRemoved(juce::ValueTree& parentTree, juce::ValueTree& childWhichHasBeenRemoved, int indexFromWhichChildWasRemoved) override; + void valueTreeChildOrderChanged(juce::ValueTree& parentTreeWhoseChildrenHaveMoved, int oldIndex, int newIndex) override; + + void loadProjectInfo(); + void loadProjectLanguages(); + void loadOriginalsFolder(); + void updateLanguageSubpath(); + }; +} // namespace AK::WwiseTransfer diff --git a/src/shared/Theme/CustomLookAndFeel.cpp b/src/shared/Theme/CustomLookAndFeel.cpp @@ -0,0 +1,305 @@ +#include "CustomLookAndFeel.h" + +#include "BinaryData.h" + +namespace AK::WwiseTransfer +{ + CustomLookAndFeel::CustomLookAndFeel() + : windowBackgroundColor{0xff464646} + , widgetBackgroundColor{0xff373737} + , thickOutlineColor{0xff3a3a3a} + , textColor{0xfff9f9f9} + , textColorDisabled(0x99000000) + , highlightedTextColor{0xffbcbcbc} + , highlightedFillColor{0xff646464} + , buttonBackgroundColor{0xff5a5a5a} + , thinOutlineColor{0xff292929} + , tableHeaderBackgroundColor{0xff545454} + , previewItemNoChangeColor{0xff7d7d7d} + , previewItemNewColor{0xff29afff} + , previewItemReplacedColor{0xffda8e40} + , regularTypeFace{juce::Typeface::createSystemTypefaceFor(BinaryData::open_sans_ttf, BinaryData::open_sans_ttfSize)} + , boldTypeFace{juce::Typeface::createSystemTypefaceFor(BinaryData::open_sans_bold_ttf, BinaryData::open_sans_bold_ttfSize)} + { + setColourScheme({ + windowBackgroundColor, + widgetBackgroundColor, + widgetBackgroundColor, + thickOutlineColor, + textColor, + highlightedFillColor, + highlightedTextColor, + highlightedFillColor, + textColor, + }); + + setColour(juce::TextButton::buttonColourId, buttonBackgroundColor); + setColour(juce::TextEditor::outlineColourId, thinOutlineColor); + setColour(juce::ComboBox::outlineColourId, thinOutlineColor); + setColour(juce::TreeView::backgroundColourId, widgetBackgroundColor); + setColour(juce::TableHeaderComponent::backgroundColourId, tableHeaderBackgroundColor); + setColour(juce::TableHeaderComponent::textColourId, textColor); + setColour(juce::TableHeaderComponent::highlightColourId, highlightedFillColor); + setColour(juce::TableHeaderComponent::outlineColourId, thickOutlineColor); + setColour(juce::HyperlinkButton::textColourId, textColor); + setColour(juce::TooltipWindow::backgroundColourId, widgetBackgroundColor); + } + + const std::shared_ptr<juce::Drawable>& CustomLookAndFeel::getIconForObjectType(Wwise::ObjectType objectType) + { + using namespace Wwise; + + switch(objectType) + { + case ObjectType::ActorMixer: + { + static std::shared_ptr<juce::Drawable> actorMixerIcon(juce::Drawable::createFromImageData(BinaryData::ObjectIcons_PhysicalFolder_nor_svg, BinaryData::ObjectIcons_PhysicalFolder_nor_svgSize)); + return actorMixerIcon; + } + case ObjectType::AudioFileSource: + { + static std::shared_ptr<juce::Drawable> actorMixerIcon(juce::Drawable::createFromImageData(BinaryData::ObjectIcons_AudioObjectSound_nor_svg, BinaryData::ObjectIcons_AudioObjectSound_nor_svgSize)); + return actorMixerIcon; + } + case ObjectType::BlendContainer: + { + static std::shared_ptr<juce::Drawable> blendContainerIcon(juce::Drawable::createFromImageData(BinaryData::ObjectIcons_BlendContainer_nor_svg, BinaryData::ObjectIcons_BlendContainer_nor_svgSize)); + return blendContainerIcon; + } + case ObjectType::PhysicalFolder: + { + static std::shared_ptr<juce::Drawable> physicalFolderIcon(juce::Drawable::createFromImageData(BinaryData::ObjectIcons_PhysicalFolder_nor_svg, BinaryData::ObjectIcons_PhysicalFolder_nor_svgSize)); + return physicalFolderIcon; + } + case ObjectType::RandomContainer: + { + static std::shared_ptr<juce::Drawable> randomContainerIcon(juce::Drawable::createFromImageData(BinaryData::ObjectIcons_RandomContainer_nor_svg, BinaryData::ObjectIcons_RandomContainer_nor_svgSize)); + return randomContainerIcon; + } + case ObjectType::SequenceContainer: + { + static std::shared_ptr<juce::Drawable> sequenceContainerIcon(juce::Drawable::createFromImageData(BinaryData::ObjectIcons_SequenceContainer_nor_svg, BinaryData::ObjectIcons_SequenceContainer_nor_svgSize)); + return sequenceContainerIcon; + } + case ObjectType::SoundSFX: + { + static std::shared_ptr<juce::Drawable> soundSFXIcon(juce::Drawable::createFromImageData(BinaryData::ObjectIcons_SoundFX_nor_svg, BinaryData::ObjectIcons_SoundFX_nor_svgSize)); + return soundSFXIcon; + } + case ObjectType::SoundVoice: + { + static std::shared_ptr<juce::Drawable> soundVoiceIcon(juce::Drawable::createFromImageData(BinaryData::ObjectIcons_SoundVoice_nor_svg, BinaryData::ObjectIcons_SoundVoice_nor_svgSize)); + return soundVoiceIcon; + } + case ObjectType::SwitchContainer: + { + static std::shared_ptr<juce::Drawable> switchContainerIcon(juce::Drawable::createFromImageData(BinaryData::ObjectIcons_SwitchContainer_nor_svg, BinaryData::ObjectIcons_SwitchContainer_nor_svgSize)); + return switchContainerIcon; + } + case ObjectType::VirtualFolder: + { + static std::shared_ptr<juce::Drawable> virtualFolderIcon(juce::Drawable::createFromImageData(BinaryData::ObjectIcons_Folder_nor_svg, BinaryData::ObjectIcons_Folder_nor_svgSize)); + return virtualFolderIcon; + } + case ObjectType::WorkUnit: + { + static std::shared_ptr<juce::Drawable> workUnitIcon(juce::Drawable::createFromImageData(BinaryData::ObjectIcons_Workunit_nor_svg, BinaryData::ObjectIcons_Workunit_nor_svgSize)); + return workUnitIcon; + } + default: + { + static std::shared_ptr<juce::Drawable> defaultIcon(juce::Drawable::createFromImageData(BinaryData::ObjectIcons_Folder_nor_svg, BinaryData::ObjectIcons_Folder_nor_svgSize)); + return defaultIcon; + } + } + } + + juce::Colour CustomLookAndFeel::getTextColourForObjectStatus(Import::ObjectStatus objectStatus) + { + if(objectStatus == Import::ObjectStatus::NoChange) + return previewItemNoChangeColor; + else if(objectStatus == Import::ObjectStatus::New || objectStatus == Import::ObjectStatus::NewRenamed) + return previewItemNewColor; + else if(objectStatus == Import::ObjectStatus::Replaced) + return previewItemReplacedColor; + else + return textColor; + } + + void CustomLookAndFeel::drawTableHeaderColumn(juce::Graphics& g, juce::TableHeaderComponent& header, + const juce::String& columnName, int /*columnId*/, + int width, int height, bool isMouseOver, bool isMouseDown, + int columnFlags) + { + auto highlightColour = header.findColour(juce::TableHeaderComponent::highlightColourId); + auto columnDisabled = (columnFlags & 128) != 0; + + if(isMouseDown && !columnDisabled) + g.fillAll(highlightColour); + else if(isMouseOver && !columnDisabled) + g.fillAll(highlightColour.withMultipliedAlpha(0.625f)); + + juce::Rectangle<int> area(width, height); + area.reduce(4, 0); + + if((columnFlags & (juce::TableHeaderComponent::sortedForwards | juce::TableHeaderComponent::sortedBackwards)) != 0) + { + juce::Path sortArrow; + sortArrow.addTriangle(0.0f, 0.0f, + 0.5f, (columnFlags & juce::TableHeaderComponent::sortedForwards) != 0 ? -0.8f : 0.8f, + 1.0f, 0.0f); + + g.setColour(textColorDisabled); + g.fillPath(sortArrow, sortArrow.getTransformToScaleToFit(area.removeFromRight(height / 2).reduced(2).toFloat(), true)); + } + + auto textColour = header.findColour(juce::TableHeaderComponent::textColourId) + .withAlpha(columnDisabled ? 0.5f : 1.0f); + g.setColour(textColour); + g.setFont(getTableHeaderFont().withHeight((float)height * 0.6f)); + g.drawFittedText(columnName, area, juce::Justification::centredLeft, 1); + } + + void CustomLookAndFeel::drawGroupComponentOutline(juce::Graphics& g, int width, int height, + const juce::String& text, const juce::Justification& position, + juce::GroupComponent& group) + { + const float indent = 3.0f; + const float textEdgeGap = 4.0f; + auto constant = 5.0f; + + juce::Font f(CustomLookAndFeelConstants::regularFontSize); + + juce::Path p; + auto x = indent; + auto y = f.getAscent() - 3.0f; + auto w = juce::jmax(0.0f, (float)width - x * 2.0f); + auto h = juce::jmax(0.0f, (float)height - y - indent); + constant = juce::jmin(constant, w * 0.5f, h * 0.5f); + auto constant2 = 2.0f * constant; + + auto textW = text.isEmpty() ? 0 : juce::jlimit(0.0f, juce::jmax(0.0f, w - constant2 - textEdgeGap * 2), (float)f.getStringWidth(text) + textEdgeGap * 2.0f); + auto textX = constant + textEdgeGap; + + if(position.testFlags(juce::Justification::horizontallyCentred)) + textX = constant + (w - constant2 - textW) * 0.5f; + else if(position.testFlags(juce::Justification::right)) + textX = w - constant - textW - textEdgeGap; + + p.startNewSubPath(x + textX + textW, y); + p.lineTo(x + w - constant, y); + + p.addArc(x + w - constant2, y, constant2, constant2, 0, juce::MathConstants<float>::halfPi); + p.lineTo(x + w, y + h - constant); + + p.addArc(x + w - constant2, y + h - constant2, constant2, constant2, juce::MathConstants<float>::halfPi, juce::MathConstants<float>::pi); + p.lineTo(x + constant, y + h); + + p.addArc(x, y + h - constant2, constant2, constant2, juce::MathConstants<float>::pi, juce::MathConstants<float>::pi * 1.5f); + p.lineTo(x, y + constant); + + p.addArc(x, y, constant2, constant2, juce::MathConstants<float>::pi * 1.5f, juce::MathConstants<float>::twoPi); + p.lineTo(x + textX, y); + + auto alpha = group.isEnabled() ? 1.0f : 0.5f; + + g.setColour(group.findColour(juce::GroupComponent::outlineColourId) + .withMultipliedAlpha(alpha)); + + g.strokePath(p, juce::PathStrokeType(2.0f)); + + g.setColour(group.findColour(juce::GroupComponent::textColourId) + .withMultipliedAlpha(alpha)); + g.setFont(f); + g.drawText(text, + juce::roundToInt(x + textX), 0, + juce::roundToInt(textW), + juce::roundToInt(f.getHeight()), + juce::Justification::centred, true); + } + + juce::Typeface::Ptr CustomLookAndFeel::getTypefaceForFont(const juce::Font& font) + { + if(font.isBold()) + return boldTypeFace; + + return regularTypeFace; + } + + void CustomLookAndFeel::drawTextEditorOutline(juce::Graphics& g, int width, int height, juce::TextEditor& textEditor) + { + if(dynamic_cast<juce::AlertWindow*>(textEditor.getParentComponent()) != nullptr || !textEditor.isEnabled() || textEditor.isReadOnly()) + return; + + const auto hasKeyboardFocus = textEditor.hasKeyboardFocus(true); + + auto colour = textEditor.findColour(hasKeyboardFocus ? juce::TextEditor::focusedOutlineColourId : juce::TextEditor::outlineColourId); + auto lineThickness = hasKeyboardFocus ? 2 : 1; + + g.setColour(colour); + g.drawRect(0, 0, width, height, lineThickness); + } + + void CustomLookAndFeel::drawTooltip(juce::Graphics& g, const juce::String& text, int width, int height) + { + juce::Rectangle<int> bounds(width, height); + + g.setColour(findColour(juce::TooltipWindow::backgroundColourId)); + g.fillRect(bounds.toFloat()); + + g.setColour(findColour(juce::TooltipWindow::outlineColourId)); + g.drawRect(bounds.toFloat().reduced(0.5f, 0.5f), 1.0f); + + const float tooltipFontSize = 13.0f; + const int maxToolTipWidth = 400; + + juce::AttributedString s; + s.setJustification(juce::Justification::centred); + s.append(text, juce::Font(tooltipFontSize, juce::Font::bold), findColour(juce::TooltipWindow::textColourId)); + + juce::TextLayout tl; + tl.createLayoutWithBalancedLineLengths(s, (float)maxToolTipWidth); + + tl.draw(g, {static_cast<float>(width), static_cast<float>(height)}); + } + + juce::Font CustomLookAndFeel::getLabelFont(juce::Label& label) + { + static auto defaultLabelFont = juce::Label().getFont(); + + if(label.getFont() != defaultLabelFont) + return label.getFont(); + + return juce::Font(CustomLookAndFeelConstants::regularFontSize); + } + + juce::Font CustomLookAndFeel::getTextButtonFont(juce::TextButton&, int buttonHeight) + { + return juce::Font(CustomLookAndFeelConstants::smallFontSize); + } + + juce::Font CustomLookAndFeel::getPopupMenuFont() + { + return juce::Font(CustomLookAndFeelConstants::regularFontSize); + } + + juce::Font CustomLookAndFeel::getTableHeaderFont() + { + return juce::Font(CustomLookAndFeelConstants::smallFontSize, juce::Font::bold); + } + + juce::Font CustomLookAndFeel::getAlertWindowFont() + { + return juce::Font(CustomLookAndFeelConstants::smallFontSize); + } + + juce::Font CustomLookAndFeel::getAlertWindowMessageFont() + { + return juce::Font(CustomLookAndFeelConstants::smallFontSize); + } + + juce::Font CustomLookAndFeel::getAlertWindowTitleFont() + { + return juce::Font(CustomLookAndFeelConstants::largeFontSize, juce::Font::bold); + } +} // namespace AK::WwiseTransfer diff --git a/src/shared/Theme/CustomLookAndFeel.h b/src/shared/Theme/CustomLookAndFeel.h @@ -0,0 +1,66 @@ +#pragma once + +#include "Model/Import.h" +#include "Model/Wwise.h" + +#include <juce_gui_basics/juce_gui_basics.h> +#include <memory> + +namespace AK::WwiseTransfer +{ + namespace CustomLookAndFeelConstants + { + constexpr float smallFontSize = 16.0f; + constexpr float regularFontSize = 18.0f; + constexpr float largeFontSize = 20.0f; + }; // namespace CustomLookAndFeelConstants + + class CustomLookAndFeel : public juce::LookAndFeel_V4 + { + public: + CustomLookAndFeel(); + + const std::shared_ptr<juce::Drawable>& getIconForObjectType(Wwise::ObjectType objectType); + juce::Colour getTextColourForObjectStatus(Import::ObjectStatus objectStatus); + + void drawTextEditorOutline(juce::Graphics& g, int width, int height, juce::TextEditor& textEditor) override; + + void drawTableHeaderColumn(juce::Graphics& g, juce::TableHeaderComponent& header, + const juce::String& columnName, int /*columnId*/, + int width, int height, bool isMouseOver, bool isMouseDown, + int columnFlags) override; + + void drawGroupComponentOutline(juce::Graphics&, int w, int h, const juce::String& text, + const juce::Justification&, juce::GroupComponent&) override; + + void drawTooltip(juce::Graphics&, const juce::String& text, int w, int h) override; + + juce::Typeface::Ptr getTypefaceForFont(const juce::Font&) override; + + juce::Font getLabelFont(juce::Label& label) override; + juce::Font getTextButtonFont(juce::TextButton&, int buttonHeight) override; + juce::Font getPopupMenuFont() override; + juce::Font getAlertWindowMessageFont() override; + juce::Font getAlertWindowFont() override; + juce::Font getAlertWindowTitleFont() override; + juce::Font getTableHeaderFont(); + + private: + juce::Typeface::Ptr regularTypeFace; + juce::Typeface::Ptr boldTypeFace; + + juce::Colour windowBackgroundColor; + juce::Colour widgetBackgroundColor; + juce::Colour thickOutlineColor; + juce::Colour textColor; + juce::Colour textColorDisabled; + juce::Colour highlightedTextColor; + juce::Colour highlightedFillColor; + juce::Colour buttonBackgroundColor; + juce::Colour thinOutlineColor; + juce::Colour tableHeaderBackgroundColor; + juce::Colour previewItemNoChangeColor; + juce::Colour previewItemNewColor; + juce::Colour previewItemReplacedColor; + }; +} // namespace AK::WwiseTransfer diff --git a/src/shared/Theme/Fonts/open_sans.ttf b/src/shared/Theme/Fonts/open_sans.ttf Binary files differ. diff --git a/src/shared/Theme/Fonts/open_sans_bold.ttf b/src/shared/Theme/Fonts/open_sans_bold.ttf Binary files differ. diff --git a/src/shared/Theme/Icons/Dialog_Help_Active.png b/src/shared/Theme/Icons/Dialog_Help_Active.png Binary files differ. diff --git a/src/shared/Theme/Icons/General_Browse_Normal.svg b/src/shared/Theme/Icons/General_Browse_Normal.svg @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> +<svg width="100%" height="100%" viewBox="0 0 20 20" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;"> + <g transform="matrix(1,0,0,1,-156,-4)"> + <g id="General_Browse_Normal" transform="matrix(1,0,0,1,108,2.70894e-13)"> + <g id="Transparent-BG" serif:id="Transparent BG" transform="matrix(1,0,0,1,48,4)"> + <rect x="0" y="0" width="20" height="20" style="fill:white;fill-opacity:0;"/> + </g> + <g transform="matrix(1,0,0,1,-396,-130)"> + <path d="M453,140L459,140L459,148L448,148L448,142L452,142L453,141L453,140ZM452,139L452,141L448,141L448,139L452,139Z" style="fill:rgb(189,189,189);"/> + <path d="M447.134,141.5C447.049,141.647 447,141.818 447,142L447,148C447,148.552 447.448,149 448,149L459,149C459.552,149 460,148.552 460,148L460,140C460,139.448 459.552,139 459,139L453,139C453,138.448 452.552,138 452,138L448,138C447.448,138 447,138.448 447,139L447,141C447,141.182 447.049,141.353 447.134,141.5ZM453,140L459,140L459,148L448,148L448,142L452,142L453,141L453,140ZM452,139L452,141L448,141L448,139L452,139Z" style="fill:rgb(58,58,58);"/> + </g> + </g> + </g> +</svg> diff --git a/src/shared/Theme/Icons/General_FolderWithTriangle_Normal.svg b/src/shared/Theme/Icons/General_FolderWithTriangle_Normal.svg @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> +<svg width="100%" height="100%" viewBox="0 0 20 20" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;"> + <g transform="matrix(1,0,0,1,-150,-28)"> + <g id="General_FolderWithTriangle_Normal" transform="matrix(1,0,0,1,102,25)"> + <g id="Transparent-BG" serif:id="Transparent BG" transform="matrix(1,0,0,1,48,3)"> + <rect x="0" y="0" width="20" height="20" style="fill:white;fill-opacity:0;"/> + </g> + <g transform="matrix(1,0,0,1,-396,-131)"> + <path d="M453,140L459,140L459,148L448,148L448,142L452,142L453,141L453,140ZM452,140L452,141L448,141L448,139L452,139L452,140Z" style="fill:rgb(189,189,189);"/> + <path d="M452.065,138.002L452.131,138.009L452.195,138.019L452.259,138.034L452.321,138.053L452.383,138.076L452.442,138.103L452.5,138.134L452.556,138.169L452.609,138.207L452.659,138.248L452.707,138.293L452.752,138.341L452.793,138.391L452.831,138.444L452.866,138.5L452.897,138.558L452.924,138.617L452.947,138.679L452.966,138.741L452.981,138.805L452.991,138.869L452.998,138.935L453,139L459,139L459.065,139.002L459.131,139.009L459.195,139.019L459.259,139.034L459.321,139.053L459.383,139.076L459.442,139.103L459.5,139.134L459.556,139.169L459.609,139.207L459.659,139.248L459.707,139.293L459.752,139.341L459.793,139.391L459.831,139.444L459.866,139.5L459.897,139.558L459.924,139.617L459.947,139.679L459.966,139.741L459.981,139.805L459.991,139.869L459.998,139.935L460,140L460,148L459.998,148.065L459.991,148.131L459.981,148.195L459.966,148.259L459.947,148.321L459.924,148.383L459.897,148.442L459.866,148.5L459.831,148.556L459.793,148.609L459.752,148.659L459.707,148.707L459.659,148.752L459.609,148.793L459.556,148.831L459.5,148.866L459.442,148.897L459.383,148.924L459.321,148.947L459.259,148.966L459.195,148.981L459.131,148.991L459.065,148.998L459,149L448,149L447.935,148.998L447.869,148.991L447.805,148.981L447.741,148.966L447.679,148.947L447.617,148.924L447.558,148.897L447.5,148.866L447.444,148.831L447.391,148.793L447.341,148.752L447.293,148.707L447.248,148.659L447.207,148.609L447.169,148.556L447.134,148.5L447.103,148.442L447.076,148.383L447.053,148.321L447.034,148.259L447.019,148.195L447.009,148.131L447.002,148.065L447,148L447,142L447.002,141.935L447.009,141.869L447.019,141.805L447.034,141.741L447.053,141.679L447.076,141.617L447.103,141.558L447.134,141.5C447.134,141.5 447.103,141.442 447.103,141.442L447.076,141.383L447.053,141.321L447.034,141.259L447.019,141.195L447.009,141.131L447.002,141.065L447,141L447,139L447.002,138.935L447.009,138.869L447.019,138.805L447.034,138.741L447.053,138.679L447.076,138.617L447.103,138.558L447.134,138.5L447.169,138.444L447.207,138.391L447.248,138.341L447.293,138.293L447.341,138.248L447.391,138.207L447.444,138.169L447.5,138.134L447.558,138.103L447.617,138.076L447.679,138.053L447.741,138.034L447.805,138.019L447.869,138.009L447.935,138.002L448,138L452,138L452.065,138.002ZM453,140L453,141L452,142L448,142L448,148L459,148L459,140L453,140ZM448,139L448,141L452,141L452,140L452,139L448,139Z" style="fill:rgb(58,58,58);"/> + </g> + <g transform="matrix(1,0,0,1,-72.5132,-174.075)"> + <circle cx="137" cy="194" r="2" style="fill:rgb(58,58,58);"/> + </g> + <g transform="matrix(1.73001,2.81678e-17,-2.81678e-17,-1.5,-255.548,50.5)"> + <path d="M186.021,21.666L186.042,21.665L186.064,21.663L186.085,21.659L186.106,21.655L186.126,21.651L186.147,21.645L186.167,21.638L186.188,21.631L186.208,21.622L186.227,21.613L186.247,21.603L186.266,21.592L186.284,21.58L186.303,21.568L186.321,21.555L186.338,21.541L186.355,21.526L186.371,21.511L186.387,21.495L186.403,21.478L186.418,21.461L186.432,21.443L186.446,21.424L186.459,21.405L186.472,21.385L186.484,21.365L186.495,21.344L186.506,21.323L186.516,21.301L186.525,21.279L186.533,21.257L186.541,21.234L186.548,21.211L186.555,21.187L186.56,21.164L186.565,21.14L186.569,21.116L186.573,21.092L186.575,21.067L186.577,21.043L186.578,21.019L186.578,20.994L186.577,20.97L186.576,20.945L186.574,20.921L186.571,20.897L186.567,20.872L186.563,20.849L186.558,20.825L186.552,20.801L186.545,20.778L186.538,20.755L186.529,20.732L186.521,20.71L186.511,20.688L186.501,20.667L185.501,18.667L185.49,18.646L185.478,18.625L185.466,18.605L185.453,18.586L185.44,18.567L185.425,18.549L185.411,18.531L185.396,18.514L185.38,18.497L185.364,18.482L185.347,18.467L185.33,18.452L185.312,18.439L185.294,18.426L185.275,18.414L185.256,18.402L185.237,18.392L185.218,18.382L185.198,18.374L185.178,18.366L185.157,18.359L185.137,18.352L185.116,18.347L185.095,18.342L185.074,18.339L185.053,18.336L185.032,18.334L185.011,18.333L184.989,18.333L184.968,18.334L184.947,18.336L184.926,18.339L184.905,18.342L184.884,18.347L184.863,18.352L184.843,18.359L184.822,18.366L184.802,18.374L184.782,18.382L184.763,18.392L184.744,18.402L184.725,18.414L184.706,18.426L184.688,18.439L184.67,18.452L184.653,18.467L184.636,18.482L184.62,18.497L184.604,18.514L184.589,18.531L184.575,18.549L184.56,18.567L184.547,18.586L184.534,18.605L184.522,18.625L184.51,18.646L184.499,18.667L183.499,20.667L183.489,20.688L183.479,20.71L183.471,20.732L183.462,20.755L183.455,20.778L183.448,20.801L183.442,20.825L183.437,20.849L183.433,20.872L183.429,20.897L183.426,20.921L183.424,20.945L183.423,20.97L183.422,20.994L183.422,21.019L183.423,21.043L183.425,21.067L183.427,21.092L183.431,21.116L183.435,21.14L183.44,21.164L183.445,21.187L183.452,21.211L183.459,21.234L183.467,21.257L183.475,21.279L183.484,21.301L183.494,21.323L183.505,21.344L183.516,21.365L183.528,21.385L183.541,21.405L183.554,21.424L183.568,21.443L183.582,21.461L183.597,21.478L183.613,21.495L183.629,21.511L183.645,21.526L183.662,21.541L183.679,21.555L183.697,21.568L183.716,21.58L183.734,21.592L183.753,21.603L183.773,21.613L183.792,21.622L183.812,21.631L183.833,21.638L183.853,21.645L183.874,21.651L183.894,21.655L183.915,21.659L183.936,21.663L183.958,21.665L183.979,21.666L184,21.667L186,21.667L186.021,21.666ZM184,21L185,19L186,21L184,21Z" style="fill:rgb(58,58,58);"/> + <path d="M185,19L186,21L184,21L185,19Z" style="fill:rgb(189,189,189);"/> + </g> + </g> + </g> +</svg> diff --git a/src/shared/Theme/Icons/General_GetFromWwise_Normal.svg b/src/shared/Theme/Icons/General_GetFromWwise_Normal.svg @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> +<svg width="100%" height="100%" viewBox="0 0 30 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;"> + <g transform="matrix(1,0,0,1,-302,-160)"> + <g id="General_GetFromWwise_Normal" transform="matrix(1,0,0,1,-713,-207)"> + <g id="Icon-Base" serif:id="Icon Base" transform="matrix(2,0,0,1,935,343)"> + <path d="M55,27.1C55,25.941 54.53,25 53.95,25L41.05,25C40.47,25 40,25.941 40,27.1L40,37.9C40,39.059 40.47,40 41.05,40L53.95,40C54.53,40 55,39.059 55,37.9L55,27.1Z" style="fill-opacity:0;"/> + </g> + <g id="Wwise-Icon" serif:id="Wwise Icon" transform="matrix(1,0,0,1,848,343)"> + <g id="Icon-Base1" serif:id="Icon Base" transform="matrix(1,0,0,1,140,-5.32907e-14)"> + <path d="M55,27.1C55,25.941 54.059,25 52.9,25L42.1,25C40.941,25 40,25.941 40,27.1L40,37.9C40,39.059 40.941,40 42.1,40L52.9,40C54.059,40 55,39.059 55,37.9L55,27.1Z" style="fill-opacity:0;"/> + </g> + <g transform="matrix(1.1835,0,0,1.1835,-152.159,-479.382)"> + <path d="M287.37,434.481C287.372,434.881 287.553,435.24 287.84,435.465C288.126,435.715 288.31,436.096 288.31,436.518C288.31,437.278 287.725,437.89 287.004,437.89L286.981,437.89C286.259,437.89 285.673,437.278 285.673,436.518C285.673,436.096 285.859,435.715 286.145,435.465C286.431,435.24 286.617,434.881 286.615,434.481L286.615,434.384C286.612,433.98 286.431,433.395 286.145,433.173C285.859,432.921 285.673,432.541 285.673,432.117C285.673,431.359 286.259,430.745 286.981,430.745L287.004,430.745C287.725,430.745 288.31,431.359 288.31,432.117C288.31,432.541 288.126,432.921 287.84,433.173C287.553,433.395 287.367,433.98 287.37,434.384L287.37,434.481ZM290.197,432.221C290.2,432.622 290.385,432.981 290.681,433.206C290.975,433.456 291.164,433.836 291.164,434.259C291.164,435.019 290.563,435.631 289.821,435.631L289.798,435.631C289.055,435.631 288.452,435.019 288.452,434.259C288.452,433.836 288.643,433.456 288.937,433.206C289.231,432.981 289.423,432.622 289.421,432.221L289.421,432.125C289.418,431.721 289.231,431.362 288.937,431.139C288.643,430.887 288.452,430.507 288.452,430.084C288.452,429.325 289.055,428.712 289.798,428.712L289.821,428.712C290.563,428.712 291.164,429.325 291.164,430.084C291.164,430.507 290.975,430.887 290.681,431.139C290.385,431.362 290.194,431.721 290.197,432.125L290.197,432.221ZM284.596,432.221C284.598,432.622 284.786,432.981 285.084,433.206C285.382,433.456 285.573,433.836 285.573,434.259C285.573,435.019 284.965,435.631 284.215,435.631L284.192,435.631C283.441,435.631 282.832,435.019 282.832,434.259C282.832,433.836 283.025,433.456 283.322,433.206C283.619,432.981 283.813,432.622 283.811,432.221L283.811,432.125C283.808,431.721 283.619,431.362 283.322,431.139C283.025,430.887 282.832,430.507 282.832,430.084C282.832,429.325 283.441,428.712 284.192,428.712L284.215,428.712C284.965,428.712 285.573,429.325 285.573,430.084C285.573,430.507 285.382,430.887 285.084,431.139C284.786,431.362 284.593,431.721 284.596,432.125L284.596,432.221ZM293.331,432.026C293.331,431.453 292.871,430.988 292.304,430.988C291.736,430.988 291.276,431.453 291.276,432.026C291.276,432.599 291.736,433.064 292.304,433.064C292.871,433.064 293.331,432.599 293.331,432.026ZM282.724,432.026C282.724,431.453 282.264,430.988 281.696,430.988C281.129,430.988 280.669,431.453 280.669,432.026C280.669,432.599 281.129,433.064 281.696,433.064C282.264,433.064 282.724,432.599 282.724,432.026ZM288.346,428.384C288.346,427.62 287.732,427 286.975,427C286.219,427 285.605,427.62 285.605,428.384C285.605,429.147 286.219,429.767 286.975,429.767C287.732,429.767 288.346,429.147 288.346,428.384Z" style="fill:rgb(189,189,189);fill-rule:nonzero;"/> + <path d="M289.741,436.475L289.821,436.476C291.024,436.476 292.009,435.491 292.009,434.259C292.009,434.13 291.998,434.003 291.977,433.88C292.083,433.899 292.192,433.909 292.304,433.909C293.335,433.909 294.176,433.068 294.176,432.026C294.176,430.985 293.335,430.143 292.304,430.143C292.203,430.143 292.104,430.151 292.007,430.167C292.009,430.139 292.009,430.112 292.009,430.084C292.009,428.853 291.024,427.867 289.821,427.867L289.798,427.867C289.573,427.867 289.356,427.901 289.152,427.965C288.957,426.934 288.054,426.155 286.975,426.155C285.903,426.155 285.005,426.924 284.803,427.947C284.616,427.895 284.418,427.867 284.215,427.867L284.214,427.867C284.206,427.867 284.199,427.868 284.192,427.871L284.192,427.867C282.976,427.867 281.987,428.856 281.987,430.084C281.987,430.112 281.988,430.139 281.989,430.166C281.894,430.151 281.796,430.143 281.696,430.143C280.665,430.143 279.824,430.985 279.824,432.026C279.824,433.068 280.665,433.909 281.696,433.909C281.807,433.909 281.915,433.899 282.02,433.88C281.998,434.003 281.987,434.13 281.987,434.259C281.987,435.469 282.946,436.445 284.135,436.475L284.215,436.476C284.429,436.476 284.636,436.445 284.832,436.387C284.83,436.431 284.828,436.474 284.828,436.518C284.828,437.737 285.773,438.704 286.926,438.734L287.059,438.734C288.21,438.704 289.155,437.737 289.155,436.518C289.155,436.471 289.154,436.424 289.15,436.377C289.338,436.436 289.536,436.47 289.741,436.475ZM287.637,435.261C287.47,435.048 287.372,434.776 287.37,434.481L287.37,434.384C287.367,433.98 287.553,433.395 287.84,433.173C288.126,432.921 288.31,432.541 288.31,432.117C288.31,431.359 287.725,430.745 287.004,430.745L286.981,430.745C286.259,430.745 285.673,431.359 285.673,432.117C285.673,432.541 285.859,432.921 286.145,433.173C286.431,433.395 286.612,433.98 286.615,434.384L286.615,434.481C286.617,434.776 286.516,435.048 286.348,435.261C286.304,435.245 286.257,435.225 286.21,435.201L286.202,435.218C286.244,435.242 286.289,435.262 286.335,435.278C286.278,435.347 286.215,435.41 286.145,435.465C285.859,435.715 285.673,436.096 285.673,436.518C285.673,437.278 286.259,437.89 286.981,437.89L287.004,437.89C287.725,437.89 288.31,437.278 288.31,436.518C288.31,436.096 288.126,435.715 287.84,435.465C287.77,435.41 287.706,435.347 287.65,435.278C287.707,435.258 287.762,435.232 287.813,435.2L287.806,435.184C287.749,435.216 287.691,435.242 287.637,435.261ZM290.47,432.999C290.299,432.787 290.199,432.515 290.197,432.221L290.197,432.125C290.194,431.721 290.385,431.362 290.681,431.139C290.975,430.887 291.164,430.507 291.164,430.084C291.164,429.325 290.563,428.712 289.821,428.712L289.798,428.712C289.055,428.712 288.452,429.325 288.452,430.084C288.452,430.507 288.643,430.887 288.937,431.139C289.231,431.362 289.418,431.721 289.421,432.125L289.421,432.221C289.423,432.515 289.32,432.787 289.148,432.999C289.102,432.982 289.053,432.961 289.003,432.935L288.997,432.952C289.041,432.977 289.087,432.999 289.135,433.016C289.076,433.086 289.01,433.15 288.937,433.206C288.643,433.456 288.452,433.836 288.452,434.259C288.452,435.019 289.055,435.631 289.798,435.631L289.821,435.631C290.563,435.631 291.164,435.019 291.164,434.259C291.164,433.836 290.975,433.456 290.681,433.206C290.608,433.15 290.541,433.086 290.483,433.016C290.545,432.994 290.604,432.964 290.66,432.928L290.652,432.913C290.59,432.95 290.528,432.978 290.47,432.999ZM284.87,432.998C284.699,432.786 284.598,432.515 284.596,432.221L284.596,432.125C284.593,431.721 284.786,431.362 285.084,431.139C285.382,430.887 285.573,430.507 285.573,430.084C285.573,429.325 284.965,428.712 284.215,428.712L284.192,428.712C283.441,428.712 282.832,429.325 282.832,430.084C282.832,430.507 283.025,430.887 283.322,431.139C283.619,431.362 283.808,431.721 283.811,432.125L283.811,432.221C283.813,432.515 283.709,432.786 283.536,432.998C283.477,432.977 283.413,432.948 283.35,432.91L283.342,432.924C283.398,432.961 283.459,432.992 283.523,433.015C283.463,433.086 283.396,433.15 283.322,433.206C283.025,433.456 282.832,433.836 282.832,434.259C282.832,435.019 283.441,435.631 284.192,435.631L284.215,435.631C284.965,435.631 285.573,435.019 285.573,434.259C285.573,433.836 285.382,433.456 285.084,433.206C285.01,433.15 284.943,433.086 284.884,433.015C284.921,433.002 284.958,432.985 284.993,432.967L284.986,432.949C284.946,432.968 284.908,432.985 284.87,432.998ZM293.331,432.026C293.331,431.453 292.871,430.988 292.304,430.988C291.736,430.988 291.276,431.453 291.276,432.026C291.276,432.599 291.736,433.064 292.304,433.064C292.871,433.064 293.331,432.599 293.331,432.026ZM282.724,432.026C282.724,431.453 282.264,430.988 281.696,430.988C281.129,430.988 280.669,431.453 280.669,432.026C280.669,432.599 281.129,433.064 281.696,433.064C282.264,433.064 282.724,432.599 282.724,432.026ZM288.346,428.384C288.346,427.62 287.732,427 286.975,427C286.219,427 285.605,427.62 285.605,428.384C285.605,429.147 286.219,429.767 286.975,429.767C287.732,429.767 288.346,429.147 288.346,428.384Z" style="fill:rgb(58,58,58);"/> + </g> + </g> + <g id="Arrow" transform="matrix(1,0,0,1,3,-0.992581)"> + <path d="M1018,375L1022,375L1022,377L1018,377L1018,380.993L1014,376L1018,370.993L1018,375Z" style="fill:rgb(189,189,189);"/> + <path d="M1019,374L1019,370.993C1019,370.568 1018.73,370.189 1018.33,370.049C1017.93,369.908 1017.48,370.037 1017.22,370.368L1013.22,375.376C1012.93,375.741 1012.93,376.26 1013.22,376.625L1017.22,381.618C1017.49,381.949 1017.93,382.077 1018.33,381.936C1018.73,381.795 1019,381.417 1019,380.993L1019,378C1019,378 1022,378 1022,378C1022.55,378 1023,377.552 1023,377L1023,375C1023,374.448 1022.55,374 1022,374L1019,374ZM1018,375L1022,375L1022,377L1018,377L1018,380.993L1014,376L1018,370.993L1018,375Z" style="fill:rgb(58,58,58);"/> + </g> + </g> + </g> +</svg> diff --git a/src/shared/Theme/Icons/General_ListMoveDown_Normal.svg b/src/shared/Theme/Icons/General_ListMoveDown_Normal.svg @@ -0,0 +1,41 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> +<svg width="100%" height="100%" viewBox="0 0 20 20" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;"> + <g transform="matrix(1,0,0,1,-314,-136)"> + <g transform="matrix(1.1181,0,0,-1.63448,-1926.06,2002.23)"> + <g id="General_ListMoveDown_Normal"> + <g id="ListMove"> + <g transform="matrix(1.1925,0,0,0.87402,908.743,583.286)"> + <rect x="918" y="625" width="15" height="14" style="fill:none;"/> + </g> + <g transform="matrix(0.894377,0,0,0.655515,1185.11,721.075)"> + <rect x="918" y="625" width="15" height="14" style="fill:rgb(189,189,189);fill-opacity:0;"/> + </g> + <g transform="matrix(3.57751,2.99703e-16,2.19059e-17,0.244726,-1283.37,977.941)"> + <rect x="922" y="632" width="1" height="5" style="fill:rgb(189,189,189);fill-opacity:0.5;"/> + <path d="M923,629.5C923.138,629.5 923.25,630.619 923.25,632L923.25,637C923.25,638.381 923.138,639.5 923,639.5L922,639.5C921.862,639.5 921.75,638.381 921.75,637L921.75,632C921.75,630.619 921.862,629.5 922,629.5L923,629.5ZM923,632L922,632L922,637L923,637L923,632Z" style="fill:rgb(58,58,58);fill-opacity:0.5;"/> + </g> + <g transform="matrix(3.57751,2.99703e-16,2.19059e-17,0.244726,-1283.37,980.388)"> + <rect x="922" y="632" width="1" height="5" style="fill:rgb(189,189,189);"/> + <path d="M923,629.5C923.138,629.5 923.25,630.619 923.25,632L923.25,637C923.25,638.381 923.138,639.5 923,639.5L922,639.5C921.862,639.5 921.75,638.381 921.75,637L921.75,632C921.75,630.619 921.862,629.5 922,629.5L923,629.5ZM923,632L922,632L922,637L923,637L923,632Z" style="fill:rgb(58,58,58);"/> + </g> + <g transform="matrix(3.57751,2.99703e-16,2.19059e-17,0.244726,-1283.37,982.835)"> + <rect x="922" y="632" width="1" height="5" style="fill:rgb(189,189,189);fill-opacity:0.5;"/> + <path d="M923,629.5C923.138,629.5 923.25,630.619 923.25,632L923.25,637C923.25,638.381 923.138,639.5 923,639.5L922,639.5C921.862,639.5 921.75,638.381 921.75,637L921.75,632C921.75,630.619 921.862,629.5 922,629.5L923,629.5ZM923,632L922,632L922,637L923,637L923,632Z" style="fill:rgb(58,58,58);fill-opacity:0.5;"/> + </g> + <g transform="matrix(0.894377,0,0,0.611814,1185.11,749)"> + <rect x="922" y="632" width="1" height="5" style="fill:rgb(189,189,189);"/> + <path d="M923,631C923.552,631 924,631.448 924,632L924,637C924,637.552 923.552,638 923,638L922,638C921.448,638 921,637.552 921,637L921,632C921,631.448 921.448,631 922,631L923,631ZM923,632L922,632L922,637L923,637L923,632Z" style="fill:rgb(58,58,58);"/> + </g> + <g transform="matrix(0.894377,0,0,0.611814,1185.11,749)"> + <path d="M922.5,627L926,632L919,632L922.5,627Z" style="fill:rgb(189,189,189);"/> + <path d="M921.681,626.427C921.868,626.159 922.174,626 922.5,626C922.826,626 923.132,626.159 923.319,626.427L926.819,631.427C927.033,631.732 927.059,632.131 926.887,632.462C926.715,632.793 926.373,633 926,633L919,633C918.627,633 918.285,632.793 918.113,632.462C917.941,632.131 917.967,631.732 918.181,631.427L921.681,626.427ZM922.5,627L926,632L919,632L922.5,627Z" style="fill:rgb(58,58,58);"/> + </g> + <g transform="matrix(0.894377,0,0,0.489451,1185.11,825.722)"> + <rect x="922" y="632" width="1" height="5" style="fill:rgb(189,189,189);"/> + </g> + </g> + </g> + </g> + </g> +</svg> diff --git a/src/shared/Theme/Icons/General_ListMoveUp_Normal.svg b/src/shared/Theme/Icons/General_ListMoveUp_Normal.svg @@ -0,0 +1,41 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> +<svg width="100%" height="100%" viewBox="0 0 20 20" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;"> + <g transform="matrix(1,0,0,1,-314,-114)"> + <g transform="matrix(1.1181,0,0,1.63448,-1926.06,-1732.23)"> + <g id="General_ListMoveUp_Normal"> + <g id="ListMove"> + <g transform="matrix(1.1925,0,0,0.87402,908.743,583.286)"> + <rect x="918" y="625" width="15" height="14" style="fill:none;"/> + </g> + <g transform="matrix(0.894377,0,0,0.655515,1185.11,721.075)"> + <rect x="918" y="625" width="15" height="14" style="fill:rgb(189,189,189);fill-opacity:0;"/> + </g> + <g transform="matrix(3.57751,2.99703e-16,2.19059e-17,0.244726,-1283.37,977.941)"> + <rect x="922" y="632" width="1" height="5" style="fill:rgb(189,189,189);fill-opacity:0.5;"/> + <path d="M923.25,632C923.25,630.619 923.138,629.5 923,629.5L922,629.5C921.862,629.5 921.75,630.619 921.75,632L921.75,637C921.75,638.381 921.862,639.5 922,639.5L923,639.5C923.138,639.5 923.25,638.381 923.25,637L923.25,632ZM923,632L922,632L922,637L923,637L923,632Z" style="fill:rgb(58,58,58);fill-opacity:0.5;"/> + </g> + <g transform="matrix(3.57751,2.99703e-16,2.19059e-17,0.244726,-1283.37,980.388)"> + <rect x="922" y="632" width="1" height="5" style="fill:rgb(189,189,189);"/> + <path d="M923.25,632C923.25,630.619 923.138,629.5 923,629.5L922,629.5C921.862,629.5 921.75,630.619 921.75,632L921.75,637C921.75,638.381 921.862,639.5 922,639.5L923,639.5C923.138,639.5 923.25,638.381 923.25,637L923.25,632ZM923,632L922,632L922,637L923,637L923,632Z" style="fill:rgb(58,58,58);"/> + </g> + <g transform="matrix(3.57751,2.99703e-16,2.19059e-17,0.244726,-1283.37,982.835)"> + <rect x="922" y="632" width="1" height="5" style="fill:rgb(189,189,189);fill-opacity:0.5;"/> + <path d="M923.25,632C923.25,630.619 923.138,629.5 923,629.5L922,629.5C921.862,629.5 921.75,630.619 921.75,632L921.75,637C921.75,638.381 921.862,639.5 922,639.5L923,639.5C923.138,639.5 923.25,638.381 923.25,637L923.25,632ZM923,632L922,632L922,637L923,637L923,632Z" style="fill:rgb(58,58,58);fill-opacity:0.5;"/> + </g> + <g transform="matrix(0.894377,0,0,0.611814,1185.11,749)"> + <rect x="922" y="632" width="1" height="5" style="fill:rgb(189,189,189);"/> + <path d="M924,632C924,631.448 923.552,631 923,631L922,631C921.448,631 921,631.448 921,632L921,637C921,637.552 921.448,638 922,638L923,638C923.552,638 924,637.552 924,637L924,632ZM923,632L922,632L922,637L923,637L923,632Z" style="fill:rgb(58,58,58);"/> + </g> + <g transform="matrix(0.894377,0,0,0.611814,1185.11,749)"> + <path d="M922.5,627L926,632L919,632L922.5,627Z" style="fill:rgb(189,189,189);"/> + <path d="M923.319,626.427C923.132,626.159 922.826,626 922.5,626C922.174,626 921.868,626.159 921.681,626.427L918.181,631.427C917.967,631.732 917.941,632.131 918.113,632.462C918.285,632.793 918.627,633 919,633L926,633C926.373,633 926.715,632.793 926.887,632.462C927.059,632.131 927.033,631.732 926.819,631.427L923.319,626.427ZM922.5,627L926,632L919,632L922.5,627Z" style="fill:rgb(58,58,58);"/> + </g> + <g transform="matrix(0.894377,0,0,0.489451,1185.11,825.722)"> + <rect x="922" y="632" width="1" height="5" style="fill:rgb(189,189,189);"/> + </g> + </g> + </g> + </g> + </g> +</svg> diff --git a/src/shared/Theme/Icons/General_SmallAdd_Normal.svg b/src/shared/Theme/Icons/General_SmallAdd_Normal.svg @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> +<svg width="100%" height="100%" viewBox="0 0 20 20" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;"> + <g transform="matrix(1,0,0,1,-314,-48)"> + <g transform="matrix(1,0,0,1,266,44)"> + <g id="General_SmallAdd_Normal"> + <g id="Plus"> + <g id="General_AddWithTriangle_Normal"> + <g id="Transparent-BG" serif:id="Transparent BG" transform="matrix(1,0,0,1,48,4)"> + <rect x="0" y="0" width="20" height="20" style="fill:white;fill-opacity:0;"/> + </g> + <g transform="matrix(1,0,0,1,-71,-234)"> + <path d="M124,247L128,247L128,243L130,243L130,247L134,247L134,249L130,249L130,253L128,253L128,249L124,249L124,247Z" style="fill:rgb(189,189,189);"/> + <path d="M124,246C123.448,246 123,246.448 123,247L123,249C123,249.552 123.448,250 124,250L127,250C127,250 127,253 127,253C127,253.552 127.448,254 128,254L130,254C130.552,254 131,253.552 131,253L131,250C131,250 134,250 134,250C134.552,250 135,249.552 135,249L135,247C135,246.448 134.552,246 134,246L131,246C131,246 131,243 131,243C131,242.448 130.552,242 130,242L128,242C127.448,242 127,242.448 127,243L127,246C127,246 124,246 124,246ZM124,247L128,247L128,243L130,243L130,247L134,247L134,249L130,249L130,253L128,253L128,249L124,249L124,247Z" style="fill:rgb(58,58,58);"/> + </g> + </g> + </g> + </g> + </g> + </g> +</svg> diff --git a/src/shared/Theme/Icons/General_SmallDelete_Normal.svg b/src/shared/Theme/Icons/General_SmallDelete_Normal.svg @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> +<svg width="100%" height="100%" viewBox="0 0 20 20" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;"> + <g transform="matrix(1,0,0,1,-130,-26)"> + <g id="General_SmallDelete_Normal" transform="matrix(1,0,0,1,83,21)"> + <g id="Transparent-BG" serif:id="Transparent BG" transform="matrix(1,0,0,1,47,5)"> + <rect x="0" y="0" width="20" height="20" style="fill:white;fill-opacity:0;"/> + </g> + <g transform="matrix(0.588889,0,0,0.611111,50.0556,8.16667)"> + <path d="M6.698,19C6.698,20.1 7.598,21 8.698,21L14.887,21C15.987,21 16.887,20.1 16.887,19L16.887,9.545L6.698,9.545L6.698,19ZM18.585,4.636L15.085,4.636L14.085,3L9.5,3L8.5,4.636L5,4.636L5,7.909L18.585,7.909L18.585,4.636Z" style="fill:rgb(189,189,189);fill-rule:nonzero;"/> + <path d="M5,9.545C5,9.545 5,19 5,19C5,21.016 6.682,22.636 8.698,22.636L14.887,22.636C16.903,22.636 18.585,21.016 18.585,19L18.585,9.545C19.523,9.545 20.283,8.813 20.283,7.909L20.283,4.636C20.283,3.733 19.523,3 18.585,3L16.056,3C16.056,3 15.548,2.17 15.548,2.17C15.243,1.67 14.686,1.364 14.085,1.364L9.5,1.364C8.899,1.364 8.342,1.67 8.037,2.17L7.529,3C7.529,3 5,3 5,3C4.062,3 3.302,3.733 3.302,4.636L3.302,7.909C3.302,8.813 4.062,9.545 5,9.545ZM6.698,19C6.698,20.1 7.598,21 8.698,21L14.887,21C15.987,21 16.887,20.1 16.887,19L16.887,9.545L6.698,9.545L6.698,19ZM18.585,4.636L15.085,4.636L14.085,3L9.5,3L8.5,4.636L5,4.636L5,7.909L18.585,7.909L18.585,4.636Z" style="fill:rgb(58,58,58);"/> + </g> + </g> + </g> +</svg> diff --git a/src/shared/Theme/Icons/ObjectIcons_AudioObjectSound_nor.svg b/src/shared/Theme/Icons/ObjectIcons_AudioObjectSound_nor.svg @@ -0,0 +1 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg width="100%" height="100%" viewBox="0 0 15 15" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-miterlimit:1;"><g id="ObjectIcons_AudioObjectSound_nor"><path id="Base-Block" serif:id="Base Block" d="M15,2.1c0,-1.159 -0.941,-2.1 -2.1,-2.1l-10.8,0c-1.159,0 -2.1,0.941 -2.1,2.1l0,10.8c0,1.159 0.941,2.1 2.1,2.1l10.8,0c1.159,0 2.1,-0.941 2.1,-2.1l0,-10.8Z" style="fill-opacity:0;"/><g id="Disc"><circle cx="7.5" cy="7.5" r="7.5" style="fill:#222;"/><circle cx="7.5" cy="7.5" r="6.5" style="fill:#c8c8c8;"/></g><g id="Speaker"><path d="M4.398,6.002l3.602,-2.523l0,8.155l-3.602,-2.632l-1.398,0l0,-3l1.398,0Z" style="fill:#222;"/><path d="M9.507,3.549c2.679,2.48 2.892,5.125 0,7.979" style="fill:none;stroke:#222;stroke-width:1px;"/><path d="M9,5.771c0.946,1.098 1.021,2.271 0,3.535" style="fill:none;stroke:#222;stroke-width:1px;"/></g></g></svg> +\ No newline at end of file diff --git a/src/shared/Theme/Icons/ObjectIcons_AudioObjectUnknown_nor.svg b/src/shared/Theme/Icons/ObjectIcons_AudioObjectUnknown_nor.svg @@ -0,0 +1 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg width="100%" height="100%" viewBox="0 0 15 15" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-miterlimit:1;"><g id="ObjectIcons_AudioObjectUnknown_nor"><path id="Base-Block" serif:id="Base Block" d="M15,2.1c0,-1.159 -0.941,-2.1 -2.1,-2.1l-10.8,-0c-1.159,-0 -2.1,0.941 -2.1,2.1l0,10.8c0,1.159 0.941,2.1 2.1,2.1l10.8,-0c1.159,-0 2.1,-0.941 2.1,-2.1l0,-10.8Z" style="fill-opacity:0;"/><g id="Disc"><circle cx="7.5" cy="7.5" r="7.5" style="fill:#222;"/><circle cx="7.5" cy="7.5" r="6.5" style="fill:#c8c8c8;"/><circle cx="7.5" cy="7.5" r="6.5" style="fill:#c8c8c8;"/></g><g id="Speaker"></g><path d="M9.51,4.466c2.679,1.898 2.892,3.922 0,6.106" style="fill:none;stroke:#222;stroke-width:1px;"/><path d="M5.6,4.466c-2.679,1.898 -2.892,3.922 0,6.106" style="fill:none;stroke:#222;stroke-width:1px;"/><circle cx="7.503" cy="7.503" r="1.5" style="fill:#222;"/></g></svg> +\ No newline at end of file diff --git a/src/shared/Theme/Icons/ObjectIcons_BlendContainer_nor.svg b/src/shared/Theme/Icons/ObjectIcons_BlendContainer_nor.svg @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> +<svg width="100%" height="100%" viewBox="0 0 15 15" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:1.41421;"> + <g transform="matrix(1,0,0,1,-100,-125)"> + <g transform="matrix(1,0,0,1,100,125.067)"> + <g id="ObjectIcons_LayerContainer_nor"> + <g id="Icons"> + <g transform="matrix(1,0,0,1,-40,-25.0671)"> + <g id="Base-Block" serif:id="Base Block"> + <path d="M55,27.1C55,25.941 54.059,25 52.9,25L42.1,25C40.941,25 40,25.941 40,27.1L40,37.9C40,39.059 40.941,40 42.1,40L52.9,40C54.059,40 55,39.059 55,37.9L55,27.1Z" style="fill-opacity:0;"/> + </g> + </g> + <g transform="matrix(1,0,0,1,-1.06581e-12,-0.0671476)"> + <path d="M4,13L1,13L1,10L3.923,10C4.091,9.986 4.375,9.584 4.71,9L1.08,9C0.484,9 0,8.516 0,7.92L0,7.08C0,6.487 0.478,6.006 1.08,6L4.751,6C4.405,5.406 4.092,5 3.845,5L1,5L1,2L4,2C5.499,2 6.612,2.914 7.5,4.101C8.386,2.917 9.497,2.003 11,2L14,2L14,5L11.155,5C10.903,5.012 10.591,5.415 10.249,6L13.92,6C14.522,6.006 15,6.488 15,7.08L15,7.92C15,8.516 14.516,9 13.92,9L10.289,9C10.617,9.572 10.897,9.969 11.077,10L14,10L14,13L11,13C9.471,13 8.371,12.087 7.5,10.906C6.631,12.085 5.534,12.996 4,13ZM4,12C5.243,11.995 6.143,11.153 6.91,10.017L6.512,9.337L6.107,8.585C5.458,9.83 4.751,10.999 4,11L2,11L2,12L4,12ZM11,11C9.964,10.999 9.011,8.774 8.171,7.183C7.086,5.126 5.964,3 4,3L2,3L2,4L4,4C5.036,4 5.989,6.226 6.829,7.817C7.914,9.874 9.036,12 11,12L13,12L13,11L11,11ZM5.263,8L5.539,7.479L5.292,7L1,7L1,8L5.263,8ZM14,8L14,7L9.708,7L9.461,7.479L9.737,8L14,8ZM11,4L13,4L13,3L11,3C9.764,3 8.862,3.841 8.092,4.98L8.493,5.656L8.899,6.404C9.545,5.166 10.248,4.011 11,4Z" style="fill:rgb(34,34,34);"/> + </g> + <g transform="matrix(1,0,0,1,-1.08002e-12,-0.0671476)"> + <path d="M5.539,7.479L5.263,8L1,8L1,7L5.292,7L5.539,7.479ZM14,8L9.737,8L9.461,7.479L9.708,7L14,7L14,8Z" style="fill:rgb(200,200,200);"/> + </g> + <g transform="matrix(1,0,0,1,-2.84217e-14,-0.0671476)"> + <path d="M6.512,9.337L6.91,10.017C6.143,11.153 5.242,11.996 4,12L2,12L2,11L4,11C4.751,11 5.458,9.831 6.107,8.585L6.512,9.337ZM13,4L11,4C10.249,4.011 9.545,5.166 8.899,6.404L8.493,5.656L8.092,4.98C8.862,3.841 9.765,3 11,3L13,3L13,4Z" style="fill:rgb(226,226,226);"/> + </g> + <g transform="matrix(1,0,0,0.947368,13,2.93285)"> + <path d="M0,9.5L-2,9.5C-3.964,9.5 -5.086,7.256 -6.171,5.085C-7.011,3.405 -7.964,1.056 -9,1.056L-11,1.056L-11,0L-9,0C-7.036,0 -5.914,2.244 -4.829,4.415C-3.989,6.095 -3.036,8.444 -2,8.444L0,8.444L0,9.5Z" style="fill:rgb(226,226,226);"/> + </g> + </g> + </g> + </g> + </g> +</svg> diff --git a/src/shared/Theme/Icons/ObjectIcons_Folder_nor.svg b/src/shared/Theme/Icons/ObjectIcons_Folder_nor.svg @@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> +<svg width="100%" height="100%" viewBox="0 0 15 15" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:1.41421;"> + <g transform="matrix(1,0,0,1,-40,-85)"> + <g transform="matrix(1,0,0,1,40,86.0003)"> + <g id="ObjectIcons_Folder_nor"> + <g id="Icons"> + <g transform="matrix(1,0,0,1,-40,-26.0003)"> + <g id="Base-Block" serif:id="Base Block"> + <path d="M55,27.1C55,25.941 54.059,25 52.9,25L42.1,25C40.941,25 40,25.941 40,27.1L40,37.9C40,39.059 40.941,40 42.1,40L52.9,40C54.059,40 55,39.059 55,37.9L55,27.1Z" style="fill-opacity:0;"/> + </g> + </g> + <path d="M0,0L0,13L15,13L15,2L8,1.999L8,-0.001L0,0ZM7,3L7,1L1,1L1,12L14,12L14,3L7,3Z" style="fill:rgb(34,34,34);"/> + <path d="M7,3L14,3L14,12L1,12L1,3L1,1L7,1L7,3ZM6,4L6,2L2,2L2,11L13,11L13,4L6,4Z" style="fill:rgb(200,200,200);"/> + <path d="M6,4L13,4L13,11L2,11L2,4L2,2L6,2L6,4ZM5,5L5,3L3,3L3,10L12,10L12,5L5,5Z" style="fill:rgb(67,67,67);"/> + <g transform="matrix(1,0,0,1,-60,-46.0003)"> + <path d="M65,51L72,51L72,56L63,56L63,51L63,49L65,49L65,51Z" style="fill:rgb(145,145,145);"/> + </g> + </g> + </g> + </g> + </g> +</svg> diff --git a/src/shared/Theme/Icons/ObjectIcons_PhysicalFolder_nor.svg b/src/shared/Theme/Icons/ObjectIcons_PhysicalFolder_nor.svg @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> +<svg width="100%" height="100%" viewBox="0 0 15 15" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:1.41421;"> + <g transform="matrix(1,0,0,1,-20,-85)"> + <g transform="matrix(1,0,0,1,20,85.0003)"> + <g id="ObjectIcons_PhysicalFolder_nor"> + <g id="Icons"> + <g transform="matrix(1,0,0,1,-40,-25.0003)"> + <g id="Base-Block" serif:id="Base Block"> + <path d="M55,27.1C55,25.941 54.059,25 52.9,25L42.1,25C40.941,25 40,25.941 40,27.1L40,37.9C40,39.059 40.941,40 42.1,40L52.9,40C54.059,40 55,39.059 55,37.9L55,27.1Z" style="fill-opacity:0;"/> + </g> + </g> + <path d="M0,1L0,14L15,14L15,3L8,2.999L8,0.999L0,1ZM7,4L7,2L1,2L1,13L14,13L14,4L7,4Z" style="fill:rgb(34,34,34);"/> + <g transform="matrix(1,0,0,1,-60,-45.0003)"> + <path d="M67,49L74,49L74,58L61,58L61,49L61,47L67,47L67,49Z" style="fill:rgb(200,200,200);"/> + </g> + </g> + </g> + </g> + </g> +</svg> diff --git a/src/shared/Theme/Icons/ObjectIcons_RandomContainer_nor.svg b/src/shared/Theme/Icons/ObjectIcons_RandomContainer_nor.svg @@ -0,0 +1,41 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> +<svg width="100%" height="100%" viewBox="0 0 15 15" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:1.41421;"> + <g transform="matrix(1,0,0,1,-140,-125)"> + <g transform="matrix(1,0,0,1,140,125)"> + <g id="ObjectIcons_RandomContainer_nor"> + <g id="Icons"> + <g transform="matrix(1,0,0,1,-40,-25)"> + <g id="Base-Block" serif:id="Base Block"> + <path d="M55,27.1C55,25.941 54.059,25 52.9,25L42.1,25C40.941,25 40,25.941 40,27.1L40,37.9C40,39.059 40.941,40 42.1,40L52.9,40C54.059,40 55,39.059 55,37.9L55,27.1Z" style="fill-opacity:0;"/> + </g> + </g> + <path d="M4.2,14L2.8,14C1.807,14 1,13.193 1,12.2L1,10.8C1,10.289 1.214,9.827 1.558,9.5C1.214,9.173 1,8.711 1,8.2L1,6.8C1,6.289 1.214,5.827 1.558,5.5C1.214,5.173 1,4.711 1,4.2L1,2.8C1,1.808 1.804,1.002 2.8,1L4.2,1C4.711,1.001 5.172,1.214 5.5,1.558C5.826,1.215 6.286,1.001 6.8,1L8.2,1C8.711,1.001 9.172,1.214 9.5,1.558C9.826,1.215 10.286,1.001 10.8,1L12.2,1C13.196,1.002 14,1.808 14,2.8L14,4.2C14,4.711 13.786,5.173 13.442,5.5C13.786,5.827 14,6.289 14,6.8L14,8.2C14,8.711 13.786,9.173 13.442,9.5C13.786,9.827 14,10.289 14,10.8L14,12.2C14,13.191 13.197,13.996 12.2,14L10.8,14C10.289,14 9.827,13.786 9.5,13.442C9.175,13.785 8.715,13.998 8.2,14L6.8,14C6.289,14 5.827,13.786 5.5,13.442C5.175,13.785 4.715,13.998 4.2,14ZM13,10L10,10L10,13L13,13L13,10ZM9,10L6,10L6,13L9,13L9,10ZM5,10L2,10L2,13L5,13L5,10ZM13,6L10,6L10,9L13,9L13,6ZM9,6L6,6L6,9L9,9L9,6ZM5,6L2,6L2,9L5,9L5,6ZM5,2L2,2L2,5L5,5L5,2ZM9,2L6,2L6,5L9,5L9,2ZM13,2L10,2L10,5L13,5L13,2Z" style="fill:rgb(34,34,34);"/> + <g transform="matrix(1,0,0,1,1.42109e-13,-8)"> + <rect x="2" y="10" width="3" height="3" style="fill:rgb(216,216,216);"/> + </g> + <g transform="matrix(1,0,0,1,0,-8)"> + <rect x="10" y="10" width="3" height="3" style="fill:rgb(216,216,216);"/> + </g> + <g transform="matrix(1,0,0,1,1.42109e-13,8)"> + <rect x="10" y="2" width="3" height="3" style="fill:rgb(216,216,216);"/> + </g> + <rect x="6" y="6" width="3" height="3" style="fill:rgb(216,216,216);"/> + <g transform="matrix(1,0,0,1,1.42109e-13,-4)"> + <rect x="6" y="6" width="3" height="3" style="fill:rgb(145,145,145);"/> + </g> + <g transform="matrix(1,0,0,1,4,2.27374e-13)"> + <rect x="6" y="6" width="3" height="3" style="fill:rgb(145,145,145);"/> + </g> + <g transform="matrix(1,0,0,1,1.42109e-13,4)"> + <rect x="6" y="6" width="3" height="3" style="fill:rgb(145,145,145);"/> + </g> + <g transform="matrix(1,0,0,1,-4,4)"> + <rect x="6" y="6" width="3" height="3" style="fill:rgb(145,145,145);"/> + </g> + <rect x="2" y="6" width="3" height="3" style="fill:rgb(216,216,216);"/> + </g> + </g> + </g> + </g> +</svg> diff --git a/src/shared/Theme/Icons/ObjectIcons_SequenceContainer_nor.svg b/src/shared/Theme/Icons/ObjectIcons_SequenceContainer_nor.svg @@ -0,0 +1,27 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> +<svg width="100%" height="100%" viewBox="0 0 15 15" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:1.41421;"> + <g transform="matrix(1,0,0,1,-180,-125)"> + <g transform="matrix(1,0,0,1,180,125)"> + <g id="ObjectIcons_SequenceContainer_nor"> + <g id="Icons"> + <g transform="matrix(1,0,0,1,-40,-25)"> + <g id="Base-Block" serif:id="Base Block"> + <path d="M55,27.1C55,25.941 54.059,25 52.9,25L42.1,25C40.941,25 40,25.941 40,27.1L40,37.9C40,39.059 40.941,40 42.1,40L52.9,40C54.059,40 55,39.059 55,37.9L55,27.1Z" style="fill-opacity:0;"/> + </g> + </g> + <path d="M12.25,14L2.75,14C1.784,14 1,13.216 1,12.25L1,10.75C1,10.26 1.201,9.818 1.527,9.5C1.201,9.182 1,8.74 1,8.25L1,6.75C1,6.26 1.201,5.818 1.527,5.5C1.201,5.182 1,4.74 1,4.25L1,2.75C1,1.786 1.782,1.002 2.75,1L12.25,1C13.218,1.002 14,1.786 14,2.75L14,4.25C14,4.74 13.799,5.182 13.473,5.5C13.799,5.818 14,6.26 14,6.75L14,8.25C14,8.74 13.799,9.182 13.473,9.5C13.799,9.818 14,10.26 14,10.75L14,12.25C14,13.215 13.217,13.999 12.25,14ZM13,10L2,10L2,13L13,13L13,10ZM13,6L2,6L2,9L13,9L13,6ZM13,2L2,2L2,5L13,5L13,2Z" style="fill:rgb(34,34,34);"/> + <g transform="matrix(3.66667,0,0,1,-20,0)"> + <rect x="6" y="6" width="3" height="3" style="fill:rgb(145,145,145);"/> + </g> + <g transform="matrix(3.66667,0,0,1,-20,4)"> + <rect x="6" y="6" width="3" height="3" style="fill:rgb(145,145,145);"/> + </g> + <g transform="matrix(3.66667,0,0,1,-34.6667,-8)"> + <rect x="10" y="10" width="3" height="3" style="fill:rgb(200,200,200);"/> + </g> + </g> + </g> + </g> + </g> +</svg> diff --git a/src/shared/Theme/Icons/ObjectIcons_SoundFX_nor.svg b/src/shared/Theme/Icons/ObjectIcons_SoundFX_nor.svg @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> +<svg width="100%" height="100%" viewBox="0 0 15 15" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:1.41421;"> + <g transform="matrix(1,0,0,1,-40,-125)"> + <g transform="matrix(1,0,0,1,40,125)"> + <g id="ObjectIcons_SoundFX_nor"> + <g id="Icons"> + <g transform="matrix(1,0,0,1,-40,-25)"> + <g id="Base-Block" serif:id="Base Block"> + <path d="M55,27.1C55,25.941 54.059,25 52.9,25L42.1,25C40.941,25 40,25.941 40,27.1L40,37.9C40,39.059 40.941,40 42.1,40L52.9,40C54.059,40 55,39.059 55,37.9L55,27.1Z" style="fill-opacity:0;"/> + </g> + </g> + <path d="M7.575,5.388L11.36,0.977L12.982,0.995C13.602,1.154 13.908,1.512 14,2.005L14,4.752L9.704,7.592L9.732,7.624L12.938,5.822C13.573,5.546 13.947,5.642 14.005,6.189L14.025,9.757L11.486,10.398C12.192,12.004 12.212,13.436 11.286,14.366C10.224,15.432 8.107,15.121 5.853,13.677L4.712,14.809C4.283,15.235 2.497,14.98 1.235,13.728C-0.025,12.476 -0.223,10.643 0.204,10.218L1.313,9.116C-0.121,6.859 -0.435,4.739 0.643,3.656C1.425,2.871 2.901,2.752 4.673,3.51L5.102,1.477C5.083,1.149 5.272,0.99 5.673,1L8.636,1C9.021,1.211 9.125,1.551 9,2L7.432,5.267L7.518,5.338L7.575,5.388ZM13.011,4.174L8.322,7.367C8.77,7.843 9.171,8.329 9.519,8.812L13.011,6.992L13.011,8.992L10.115,9.719C11.119,11.418 11.392,12.952 10.672,13.672C9.577,14.767 6.597,13.564 4.016,10.983C1.437,8.403 0.233,5.424 1.328,4.328C2.06,3.596 3.632,3.891 5.364,4.936L6.011,2L8,2L6.265,5.537C6.744,5.888 7.227,6.29 7.698,6.738L11.864,2L13.011,2L13.011,4.174ZM1.78,9.958C1.911,10.613 2.262,11.387 2.891,12.009C3.559,12.669 4.382,13.036 5.052,13.16L4.291,13.911C4.081,14.119 4.109,14.096 3.585,14.033C3.061,13.969 2.366,13.69 1.812,13.144C1.202,12.54 0.941,11.746 0.932,11.205C0.925,10.823 0.881,10.847 1.077,10.653L1.78,9.958ZM6.159,8.896C7.124,9.861 7.628,10.897 7.286,11.209C6.942,11.521 5.884,10.992 4.917,10.027C3.952,9.061 3.449,8.026 3.791,7.714C4.134,7.402 5.193,7.931 6.159,8.896Z" style="fill:rgb(34,34,34);"/> + <path d="M1.78,9.958C1.911,10.613 2.262,11.387 2.891,12.009C3.559,12.669 4.382,13.036 5.052,13.16L4.291,13.911C4.081,14.119 4.109,14.096 3.585,14.033C3.061,13.969 2.366,13.69 1.812,13.144C1.202,12.54 0.941,11.746 0.932,11.205C0.925,10.823 0.881,10.847 1.077,10.653L1.78,9.958Z" style="fill:rgb(200,200,200);"/> + <path d="M13.011,4.174L8.322,7.367C8.77,7.843 9.171,8.329 9.519,8.812L13.011,6.992L13.011,8.992L10.115,9.719C11.119,11.418 11.392,12.952 10.672,13.672C9.577,14.767 6.597,13.564 4.016,10.983C1.437,8.403 0.233,5.424 1.328,4.328C2.06,3.596 3.632,3.891 5.364,4.936L6.011,2L8,2L6.265,5.537C6.744,5.888 7.227,6.29 7.698,6.738L11.864,2L13.011,2L13.011,4.174ZM6.159,8.896C7.124,9.861 7.628,10.897 7.286,11.209C6.942,11.521 5.884,10.992 4.917,10.027C3.952,9.061 3.449,8.026 3.791,7.714C4.134,7.402 5.193,7.931 6.159,8.896Z" style="fill:rgb(200,200,200);"/> + </g> + </g> + </g> + </g> +</svg> diff --git a/src/shared/Theme/Icons/ObjectIcons_SoundVoice_nor.svg b/src/shared/Theme/Icons/ObjectIcons_SoundVoice_nor.svg @@ -0,0 +1,38 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> +<svg width="100%" height="100%" viewBox="0 0 15 15" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:1.41421;"> + <g transform="matrix(1,0,0,1,-80,-125)"> + <g transform="matrix(1,0,0,1,80,125)"> + <g id="ObjectIcons_SoundVoice_nor"> + <g id="Icons"> + <g transform="matrix(1,0,0,1,-40,-25)"> + <g id="Base-Block" serif:id="Base Block"> + <path d="M55,27.1C55,25.941 54.059,25 52.9,25L42.1,25C40.941,25 40,25.941 40,27.1L40,37.9C40,39.059 40.941,40 42.1,40L52.9,40C54.059,40 55,39.059 55,37.9L55,27.1Z" style="fill-opacity:0;"/> + </g> + </g> + <g transform="matrix(1,0,0,1,-200,-85)"> + <path d="M207.357,85.005C207.807,85.025 208.632,85.653 208.662,86.434C208.708,87.636 208.162,88.036 208.162,88.036C208.162,88.036 208.298,88.101 208.512,88.385L209.985,90.61C210.275,91.102 210.426,92.985 209.576,93.006L208.259,93.012L208.492,94.008C208.653,94.589 207.528,94.904 207,95L204.609,95C204.608,95.763 205.058,96.001 207,96C207.577,96.092 207.956,96.38 208,97L208,98C208.013,98.782 206.809,99.988 206.008,100L203.942,100C202.719,99.832 200.019,99.184 200.019,98.227L200.019,93.196C199.979,92.123 200.014,87.508 200.014,87.508C199.998,85.97 201.388,85.026 202.662,85.005L207.357,85.005ZM203,86C201.542,86.026 200.986,86.527 201,88C201,88 200.972,92.172 201.004,93.101L201.004,98.101C202.005,98.527 203.007,98.854 204.004,99L206,99C206.445,98.842 206.784,98.615 207.004,98.101L207,97C204.154,97.002 203.52,96.428 203.524,94L207,94C207.431,93.917 207.419,93.791 207.289,93.287L206.644,92.105C206.621,92.037 206.649,92.002 206.728,92L208.88,92C209.172,91.992 209.241,91.34 209.004,90.913L207.644,88.922C207.469,88.676 207.175,88.752 206.984,88.66C206.902,88.62 206.816,88.191 206.892,87.928C206.967,87.664 207.293,87.473 207.325,87.452C207.595,87.273 207.671,86.994 207.655,86.537C207.674,86.161 207.3,85.964 207.163,86L203,86Z" style="fill:rgb(34,34,34);"/> + </g> + <g transform="matrix(1,0,0,1,-199.996,-83.899)"> + <path d="M201,97C202.001,97.426 203.003,97.753 204,97.899L205.996,97.899C206.441,97.741 206.78,97.514 207,97L206.996,95.899C204.15,95.901 203.516,95.327 203.52,92.899L206.996,92.899C207.427,92.816 207.415,92.69 207.285,92.186L206.64,91.004C206.617,90.936 206.645,90.901 206.724,90.899L208.876,90.899C209.168,90.891 209.237,90.238 209,89.812L207.64,87.821C207.465,87.575 207.171,87.651 206.98,87.559C206.898,87.519 206.812,87.09 206.888,86.827C206.963,86.563 207.289,86.372 207.321,86.351C207.591,86.172 207.667,85.893 207.651,85.436C207.67,85.059 207.296,84.863 207.159,84.899L204.996,84.899L202.996,84.899C201.538,84.925 200.982,85.426 200.996,86.899C200.996,86.899 200.968,91.071 201,92L201,97Z" style="fill:rgb(200,200,200);"/> + </g> + <g transform="matrix(1,0,0,1,-199.248,-84.0739)"> + <path d="M205.234,86.433C205.236,86.271 205.163,86.143 204.941,86.084C203.696,86.17 202.868,86.779 202.042,87.739C201.195,88.723 201.248,90.074 201.248,90.074C201.341,90.215 201.27,90.202 201.452,90.051C201.627,89.58 202.066,88.853 202.779,88.332C203.565,87.757 204.304,87.524 205.027,87.499C205.17,87.52 205.253,87.474 205.246,87.329L205.234,86.433Z" style="fill:rgb(34,34,34);"/> + </g> + <g transform="matrix(1,0,0,1,-198,-84)"> + <circle cx="203" cy="89" r="1" style="fill:rgb(34,34,34);"/> + </g> + <g transform="matrix(1,0,0,1,0.103745,2.84217e-13)"> + <path d="M12.954,15L10.482,15L9.882,14.115C9.79,13.768 9.779,13.459 9.843,13.186L9.802,13.209C9.2,13.453 8.862,13.291 8.626,12.97L7.966,11.815C7.798,11.359 7.938,11.007 8.333,10.742C8.65,10.53 8.945,10.269 9,10.075C8.971,9.919 8.635,9.628 8.296,9.392C7.999,9.095 8.061,8.696 8.279,8.254L8.917,7.419C9.221,7.035 9.601,6.902 10.073,7.077C10.035,6.791 10.125,6.508 10.319,6.253L11.035,5.523C11.558,4.983 11.932,4.847 12.51,5.181C13.748,5.793 14.482,6.734 14.896,7.815L14.896,12.537C14.465,13.513 13.767,14.352 12.954,15ZM11.983,6C13.42,6.997 14.35,8.516 14.35,10.197C14.35,12.268 13.069,13.616 11.656,14.566L10.909,13.61C12.135,12.801 12.912,11.864 12.912,10.197C12.912,8.806 12.129,7.561 10.923,6.767L11.983,6ZM9.564,7.939C10.504,8.364 11.199,9.141 11.199,10C11.199,10.953 10.345,11.803 9.25,12.187L8.835,11.461C9.527,11.211 10,10.657 10,10C10,9.405 9.611,8.894 9.023,8.617L9.444,8.048L9.564,7.939Z" style="fill:rgb(34,34,34);"/> + </g> + <g transform="matrix(1.26624,0,0,1.2044,-254.785,-103.017)"> + <path d="M210.752,90.515C211.887,91.343 212.621,92.605 212.621,94C212.621,95.72 211.529,96.863 210.493,97.64L209.904,96.846C210.963,96.006 211.485,95.384 211.485,94C211.485,92.845 210.867,91.811 209.915,91.152L210.752,90.515Z" style="fill:rgb(216,216,216);"/> + </g> + <g transform="matrix(1,0,0,1,-199.896,-83.9249)"> + <path d="M209.564,91.939C210.504,92.364 211.199,93.141 211.199,94C211.199,94.953 210.345,95.803 209.25,96.187L208.835,95.461C209.527,95.211 210,94.657 210,94C210,93.405 209.611,92.894 209.023,92.617L209.444,92.048L209.564,91.939Z" style="fill:rgb(216,216,216);"/> + </g> + </g> + </g> + </g> + </g> +</svg> diff --git a/src/shared/Theme/Icons/ObjectIcons_SwitchContainer_nor.svg b/src/shared/Theme/Icons/ObjectIcons_SwitchContainer_nor.svg @@ -0,0 +1,34 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> +<svg width="100%" height="100%" viewBox="0 0 15 15" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:1.41421;"> + <g transform="matrix(1,0,0,1,-200,-125)"> + <g transform="matrix(1,0,0,1,200,125)"> + <g id="ObjectIcons_SwitchContainer_nor"> + <g id="Icons"> + <g transform="matrix(1,0,0,1,-40,-25)"> + <g id="Base-Block" serif:id="Base Block"> + <path d="M55,27.1C55,25.941 54.059,25 52.9,25L42.1,25C40.941,25 40,25.941 40,27.1L40,37.9C40,39.059 40.941,40 42.1,40L52.9,40C54.059,40 55,39.059 55,37.9L55,27.1Z" style="fill-opacity:0;"/> + </g> + </g> + <path d="M1.95,9L1.05,9C0.47,9 0,8.53 0,7.95L0,7.05C0,6.471 0.469,6.001 1.05,6L1.95,6L2,6.003L2,2.35C2,1.606 2.604,1.001 3.35,1L3.65,1C4.396,1.001 5,1.606 5,2.35L5,12.65C5,13.394 4.396,13.999 3.65,14L3.35,14C2.605,14 2,13.395 2,12.65L2,8.997L1.95,9ZM4,2L3,2L3,7L1,7L1,8L3,8L3,13L4,13L4,2Z" style="fill:rgb(34,34,34);"/> + <path d="M8.2,14L6.8,14C5.807,14 5,13.193 5,12.2L5,10.8C5,10.289 5.214,9.827 5.558,9.5C5.214,9.173 5,8.711 5,8.2L5,6.8C5,6.289 5.214,5.827 5.558,5.5C5.214,5.173 5,4.711 5,4.2L5,2.8C5,1.807 5.805,1.001 6.8,1L8.2,1C9.195,1.001 10,1.807 10,2.8L10,4.2C10,4.711 9.786,5.173 9.442,5.5C9.786,5.827 10,6.289 10,6.8L10,8.2C10,8.711 9.786,9.173 9.442,9.5C9.6,9.649 9.73,9.827 9.823,10.026C9.896,10.009 9.971,10 10.051,10L10.086,10L10.086,7.02C10.086,6.458 10.542,6.001 11.106,6L11.98,6L12.03,6.003L12.08,6L13.92,6C14.517,6.001 15,6.485 15,7.08L15,7.92C15,8.514 14.519,8.997 13.92,9L13,9L13,11.98C13,12.541 12.546,12.997 11.98,13L11.106,13L11.028,12.996L10.951,13L10.051,13C9.973,13 9.896,12.991 9.823,12.974C9.535,13.58 8.917,13.999 8.2,14ZM9,10L6,10L6,13L9,13L9,10ZM14,7L11,7L11,11L10,11L10,12L12,12L12,8L14,8L14,7ZM9,6L6,6L6,9L9,9L9,6ZM9,2L6,2L6,5L9,5L9,2Z" style="fill:rgb(34,34,34);"/> + <g transform="matrix(1,0,0,1,-4,-8)"> + <rect x="10" y="10" width="3" height="3" style="fill:rgb(200,200,200);"/> + </g> + <g transform="matrix(1,0,0,1,-4,-4)"> + <rect x="10" y="10" width="3" height="3" style="fill:rgb(200,200,200);"/> + </g> + <g transform="matrix(1,0,0,1,-4,0)"> + <rect x="10" y="10" width="3" height="3" style="fill:rgb(200,200,200);"/> + </g> + <g transform="matrix(6.12323e-17,-1,1,5.72119e-18,1,7)"> + <path d="M0,2L0,0L-1,0L-1,2L-6,2L-6,3L5,3L5,2L0,2Z" style="fill:rgb(200,200,200);"/> + </g> + <g transform="matrix(6.12323e-17,-1,1,5.72119e-18,13,11)"> + <path d="M0,-2L0,-3L-1,-3L-1,-1L3,-1L3,1L4,1L4,-2L0,-2Z" style="fill:rgb(200,200,200);"/> + </g> + </g> + </g> + </g> + </g> +</svg> diff --git a/src/shared/Theme/Icons/ObjectIcons_Workunit_nor.svg b/src/shared/Theme/Icons/ObjectIcons_Workunit_nor.svg @@ -0,0 +1,18 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> +<svg width="100%" height="100%" viewBox="0 0 15 15" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:1.41421;"> + <g transform="matrix(1,0,0,1,-60,-85)"> + <g id="ObjectIcons_Workunit_nor" transform="matrix(1,0,0,1,-160,-40)"> + <g transform="matrix(1,0,0,1,180,100)"> + <g id="Base-Block" serif:id="Base Block"> + <path d="M55,27.1C55,25.941 54.059,25 52.9,25L42.1,25C40.941,25 40,25.941 40,27.1L40,37.9C40,39.059 40.941,40 42.1,40L52.9,40C54.059,40 55,39.059 55,37.9L55,27.1Z" style="fill-opacity:0;"/> + </g> + </g> + <path d="M227.5,125.735L221,128.926L221,136.062L227.5,139.63L234,136.062L234,128.926L227.5,125.735ZM227.5,126.817L222,129.5L222,135.5L227.5,138.5L233,135.5L233,129.5L227.5,126.817Z" style="fill:rgb(34,34,34);"/> + <path d="M227.5,126.817L222,129.5L222,135.5L227.5,138.5L233,135.5L233,129.5L227.5,126.817ZM226,130L224,130L224,132.553C223.97,134.358 225.313,136.008 227.54,136C229.778,135.992 231.013,134.238 231,132.856L231,130L229,130L229,132.769C229.003,133.482 228.282,133.997 227.527,134C226.762,134.001 225.996,133.509 226,132.683L226,130Z" style="fill:rgb(200,200,200);"/> + <g transform="matrix(1,0,0,1,60,20)"> + <path d="M166,110L164,110L164,112.553C163.97,114.358 165.313,116.008 167.54,116C169.778,115.992 171.013,114.238 171,112.856L171,110L169,110L169,112.769C169.003,113.482 168.282,113.997 167.527,114C166.762,114.001 165.996,113.509 166,112.683L166,110Z" style="fill:rgb(34,34,34);"/> + </g> + </g> + </g> +</svg> diff --git a/src/shared/Theme/Icons/wwise_icon.svg b/src/shared/Theme/Icons/wwise_icon.svg @@ -0,0 +1,10 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> +<svg width="100%" height="100%" viewBox="0 0 63 63" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;"> + <g transform="matrix(4.16667,0,0,4.16667,33.4512,21.4817)"> + <path d="M0,4.693C0.533,4.693 1.061,4.916 1.468,5.316L1.585,5.434C2.084,5.926 2.286,6.606 2.189,7.249C2.13,7.924 2.357,8.628 2.877,9.147C3.808,10.078 5.312,10.076 6.24,9.148L6.269,9.12C7.198,8.19 7.2,6.685 6.271,5.755C5.75,5.235 5.048,5.008 4.37,5.067C3.729,5.162 3.057,4.955 2.557,4.463L2.438,4.345C2.031,3.944 1.711,3.381 1.815,2.878C1.856,2.701 1.878,2.52 1.878,2.339C1.883,1.724 1.65,1.107 1.18,0.637L1.151,0.608C0.528,-0.015 -0.354,-0.219 -1.148,-0.005C-1.65,0.083 -2.144,-0.244 -2.532,-0.626L-2.65,-0.744C-3.146,-1.232 -3.345,-1.913 -3.253,-2.557C-3.191,-3.23 -3.42,-3.935 -3.938,-4.453C-4.87,-5.385 -6.373,-5.382 -7.303,-4.453L-7.332,-4.423C-8.259,-3.495 -8.262,-1.993 -7.33,-1.061C-6.812,-0.543 -6.107,-0.313 -5.435,-0.375C-4.789,-0.469 -4.117,-0.261 -3.622,0.228L-3.504,0.346C-3.091,0.753 -2.878,1.286 -2.878,1.822L-2.876,2.875C-2.876,3.399 -3.104,3.917 -3.5,4.317L-3.618,4.435C-4.109,4.935 -4.789,5.135 -5.432,5.039C-6.108,4.98 -6.811,5.208 -7.33,5.728C-8.261,6.659 -8.259,8.163 -7.33,9.09L-7.303,9.12C-6.373,10.048 -4.867,10.05 -3.938,9.121C-3.418,8.601 -3.191,7.897 -3.251,7.22C-3.345,6.58 -3.138,5.907 -2.647,5.407L-2.528,5.29C-2.15,4.907 -1.658,4.67 -1.156,4.67L0,4.693Z" style="fill:white;fill-rule:nonzero;"/> + </g> + <g transform="matrix(-2.94671,2.94584,2.94584,2.94671,62.5001,9.99981)"> + <path d="M1.697,-4.096C0.372,-4.096 -0.703,-3.021 -0.703,-1.697C-0.703,-0.372 0.372,0.703 1.697,0.703C3.021,0.704 4.096,-0.371 4.096,-1.695C4.097,-3.021 3.022,-4.096 1.697,-4.096" style="fill:white;fill-rule:nonzero;"/> + </g> +</svg> diff --git a/src/shared/UI/AboutComponent.cpp b/src/shared/UI/AboutComponent.cpp @@ -0,0 +1,111 @@ +#include "AboutComponent.h" + +#include "AK/AkWwiseSDKVersion.h" +#include "BinaryData.h" +#include "Theme/CustomLookAndFeel.h" + +#include <juce_gui_basics/juce_gui_basics.h> + +#define AK_WWISE_VST_VERSION_FULL AK_WWISESDK_VERSIONNAME_SHORT "." AK_WWISESDK_NUM2STRING(AK_WWISESDK_VERSION_BUILD) + +namespace AK::WwiseTransfer +{ + namespace AboutComponentConstants + { + constexpr int titleHeight = 32; + constexpr int labelHeight = 24; + constexpr int linkHeight = 20; + constexpr int margin = 10; + constexpr int width = 300; + constexpr int height = 254; + constexpr int wwiseIconHeight = 100; + const juce::String githubBaseUrl = "https://github.com/audiokinetic/"; + const juce::String releaseNoteUrlPart = "/releases/tag/"; + const juce::String licenseUrlPart = "/blob/main/License.txt"; + const juce::String documentationUrl = "https://www.audiokinetic.com/library/reawwise"; + } // namespace AboutComponentConstants + + AboutComponent::AboutComponent(const juce::String& applicationName) + : copyRightSymbol(juce::CharPointer_UTF8("\xa9")) + , wwiseIcon(juce::Drawable::createFromImageData(BinaryData::wwise_icon_svg, BinaryData::wwise_icon_svgSize)) + + { + using namespace AboutComponentConstants; + + setSize(width, height); + setLookAndFeel(&lookAndFeel); + + titleLabel.setFont(titleHeight); + titleLabel.setText("ReaWwise", juce::dontSendNotification); + titleLabel.setJustificationType(juce::Justification::centred); + + versionLabel.setText("Version " + juce::String(JUCE_APPLICATION_VERSION_STRING) + " " + juce::String(COMMIT_HASH), juce::dontSendNotification); + versionLabel.setEnabled(false); + versionLabel.setJustificationType(juce::Justification::centred); + + copyrightLabel.setText(juce::String(juce::CharPointer_UTF8("\xc2\xa9")) + " " + juce::String(YEAR) + " Audiokinetic Inc.", juce::dontSendNotification); + copyrightLabel.setJustificationType(juce::Justification::centred); + + documentationLink.setButtonText("Documentation"); + documentationLink.setAlpha(0.5f); + documentationLink.setURL(documentationUrl); + documentationLink.setJustificationType(juce::Justification::centred); + + releaseNotesLink.setButtonText("Release Notes"); + releaseNotesLink.setAlpha(0.5f); + releaseNotesLink.setURL(githubBaseUrl + applicationName + releaseNoteUrlPart + JUCE_APPLICATION_VERSION_STRING); + releaseNotesLink.setJustificationType(juce::Justification::centred); + + licensingLink.setButtonText("License Info"); + licensingLink.setAlpha(0.5f); + licensingLink.setURL(githubBaseUrl + applicationName + licenseUrlPart); + licensingLink.setJustificationType(juce::Justification::centred); + + addAndMakeVisible(titleLabel); + addAndMakeVisible(versionLabel); + addAndMakeVisible(copyrightLabel); + addAndMakeVisible(documentationLink); + addAndMakeVisible(releaseNotesLink); + addAndMakeVisible(licensingLink); + addAndMakeVisible(*wwiseIcon); + + versionLabel.setTooltip("Wwise SDK: " + juce::String(AK_WWISE_VST_VERSION_FULL) + juce::newLine + + "Branch: " + juce::String(BRANCH_NAME) + juce::newLine + + "Build: " + juce::String(BUILD_NUMBER)); + } + + void AboutComponent::resized() + { + using namespace AboutComponentConstants; + + auto area = getLocalBounds(); + area.reduce(margin, margin); + + titleLabel.setBounds(area.removeFromTop(titleHeight)); + versionLabel.setBounds(area.removeFromTop(labelHeight)); + + area.removeFromTop(margin); + + wwiseIcon->setTransformToFit(area.removeFromTop(wwiseIconHeight).toFloat(), juce::RectanglePlacement::centred); + + area.removeFromTop(margin); + + copyrightLabel.setBounds(area.removeFromTop(labelHeight)); + + area.removeFromTop(margin); + + juce::FlexBox fb; + fb.flexDirection = juce::FlexBox::Direction::row; + + fb.items.add(juce::FlexItem(documentationLink).withHeight(linkHeight).withFlex(1)); + fb.items.add(juce::FlexItem(releaseNotesLink).withHeight(linkHeight).withFlex(1)); + fb.items.add(juce::FlexItem(licensingLink).withHeight(linkHeight).withFlex(1)); + + fb.performLayout(area.removeFromTop(linkHeight)); + } + + void AboutComponent::paint(juce::Graphics& g) + { + g.fillAll(getLookAndFeel().findColour(juce::ResizableWindow::backgroundColourId)); + } +} // namespace AK::WwiseTransfer diff --git a/src/shared/UI/AboutComponent.h b/src/shared/UI/AboutComponent.h @@ -0,0 +1,32 @@ +#pragma once + +#include "Theme/CustomLookAndFeel.h" + +#include <juce_gui_basics/juce_gui_basics.h> + +namespace AK::WwiseTransfer +{ + class AboutComponent : public juce::Component + { + public: + AboutComponent(const juce::String& applicationName); + + void resized() override; + void paint(juce::Graphics& g); + + private: + CustomLookAndFeel lookAndFeel; + + juce::Label titleLabel; + juce::Label versionLabel; + juce::Label copyrightLabel; + + juce::String copyRightSymbol; + + juce::HyperlinkButton documentationLink; + juce::HyperlinkButton releaseNotesLink; + juce::HyperlinkButton licensingLink; + + std::unique_ptr<juce::Drawable> wwiseIcon; + }; +} // namespace AK::WwiseTransfer diff --git a/src/shared/UI/CustomDrawableButton.cpp b/src/shared/UI/CustomDrawableButton.cpp @@ -0,0 +1,21 @@ +#include "CustomDrawableButton.h" + +namespace AK::WwiseTransfer +{ + namespace CustomDrawableButtonConstants + { + constexpr int margin = 2; + } + + CustomDrawableButton::CustomDrawableButton(const juce::String& buttonName, std::unique_ptr<juce::Drawable> drawableValue) + : juce::DrawableButton(buttonName, juce::DrawableButton::ButtonStyle::ImageOnButtonBackground) + , drawable(std::move(drawableValue)) + { + setImages(drawable.get()); + } + + juce::Rectangle<float> CustomDrawableButton::getImageBounds() const + { + return getLocalBounds().reduced(CustomDrawableButtonConstants::margin).toFloat(); + } +} // namespace AK::WwiseTransfer diff --git a/src/shared/UI/CustomDrawableButton.h b/src/shared/UI/CustomDrawableButton.h @@ -0,0 +1,18 @@ +#pragma once + +#include <juce_gui_basics/juce_gui_basics.h> + +namespace AK::WwiseTransfer +{ + class CustomDrawableButton + : public juce::DrawableButton + { + public: + CustomDrawableButton(const juce::String& buttonName, std::unique_ptr<juce::Drawable> drawable); + + juce::Rectangle<float> getImageBounds() const override; + + private: + std::unique_ptr<juce::Drawable> drawable; + }; +} // namespace AK::WwiseTransfer diff --git a/src/shared/UI/HierarchyMappingControls.cpp b/src/shared/UI/HierarchyMappingControls.cpp @@ -0,0 +1,121 @@ +#include "HierarchyMappingControls.h" + +#include "BinaryData.h" +#include "Helpers/ImportHelper.h" +#include "Model/IDs.h" +#include "Model/Import.h" + +namespace AK::WwiseTransfer +{ + namespace HierarchyMappingControlsConstants + { + constexpr int buttonSize = 24; + } + + HierarchyMappingControls::HierarchyMappingControls(juce::ValueTree appState, ApplicationProperties& applicationProperties, const juce::String& applicationName) + : applicationState(appState) + , hierarchyMapping(applicationState.getChildWithName(IDs::hierarchyMapping)) + , selectedRow(hierarchyMapping, IDs::selectedRow, nullptr) + , insertButton("InsertButton", juce::Drawable::createFromImageData(BinaryData::General_SmallAdd_Normal_svg, BinaryData::General_SmallAdd_Normal_svgSize)) + , removeButton("RemoveButton", juce::Drawable::createFromImageData(BinaryData::General_SmallDelete_Normal_svg, BinaryData::General_SmallDelete_Normal_svgSize)) + , moveUpButton("MoveUpButton", juce::Drawable::createFromImageData(BinaryData::General_ListMoveUp_Normal_svg, BinaryData::General_ListMoveUp_Normal_svgSize)) + , moveDownButton("MoveDownButton", juce::Drawable::createFromImageData(BinaryData::General_ListMoveDown_Normal_svg, BinaryData::General_ListMoveDown_Normal_svgSize)) + , presetMenuComponent(applicationState, applicationProperties, applicationName) + { + insertButton.setTooltip("Insert"); + removeButton.setTooltip("Remove"); + moveUpButton.setTooltip("Move Up"); + moveDownButton.setTooltip("Move Down"); + + insertButton.onClick = [this] + { + hierarchyMapping.addChild(ImportHelper::hierarchyMappingNodeToValueTree(Import::HierarchyMappingNode("", Wwise::ObjectType::Unknown)), selectedRow, nullptr); + }; + + removeButton.onClick = [this] + { + hierarchyMapping.removeChild(selectedRow, nullptr); + }; + + moveUpButton.onClick = [this] + { + hierarchyMapping.moveChild(selectedRow, selectedRow - 1, nullptr); + }; + + moveDownButton.onClick = [this] + { + hierarchyMapping.moveChild(selectedRow, selectedRow + 1, nullptr); + }; + + addAndMakeVisible(insertButton); + addAndMakeVisible(removeButton); + addAndMakeVisible(moveUpButton); + addAndMakeVisible(moveDownButton); + addAndMakeVisible(presetMenuComponent); + + applicationState.addListener(this); + + refreshComponent(); + } + + HierarchyMappingControls::~HierarchyMappingControls() + { + applicationState.removeListener(this); + } + + void HierarchyMappingControls::refreshComponent() + { + removeButton.setEnabled(hierarchyMapping.getNumChildren() > 1); + moveUpButton.setEnabled(selectedRow > 0); + moveDownButton.setEnabled(selectedRow >= 0 && selectedRow < hierarchyMapping.getNumChildren() - 1); + } + + void HierarchyMappingControls::resized() + { + using namespace HierarchyMappingControlsConstants; + + auto area = getLocalBounds(); + + juce::FlexBox buttonSection; + buttonSection.flexDirection = juce::FlexBox::Direction::column; + buttonSection.justifyContent = juce::FlexBox::JustifyContent::spaceBetween; + + auto buttonSectionWidth = area.getWidth(); + buttonSection.items.add(juce::FlexItem(buttonSectionWidth, buttonSize, presetMenuComponent)); + buttonSection.items.add(juce::FlexItem(buttonSectionWidth, buttonSize, insertButton)); + buttonSection.items.add(juce::FlexItem(buttonSectionWidth, buttonSize, removeButton)); + buttonSection.items.add(juce::FlexItem(buttonSectionWidth, buttonSize, moveUpButton)); + buttonSection.items.add(juce::FlexItem(buttonSectionWidth, buttonSize, moveDownButton)); + + buttonSection.performLayout(area); + } + + void HierarchyMappingControls::valueTreePropertyChanged(juce::ValueTree& treeWhosePropertyHasChanged, const juce::Identifier& property) + { + if(treeWhosePropertyHasChanged == hierarchyMapping && property == selectedRow.getPropertyID()) + { + triggerAsyncUpdate(); + } + } + + void HierarchyMappingControls::valueTreeChildAdded(juce::ValueTree& parentTree, juce::ValueTree& childWhichHasBeenAdded) + { + if(parentTree == hierarchyMapping) + { + triggerAsyncUpdate(); + } + } + + void HierarchyMappingControls::valueTreeChildRemoved(juce::ValueTree& parentTree, juce::ValueTree& childWhichHasBeenRemoved, int indexFromWhichChildWasRemoved) + { + if(parentTree == hierarchyMapping) + { + triggerAsyncUpdate(); + } + } + + void HierarchyMappingControls::handleAsyncUpdate() + { + refreshComponent(); + } +} // namespace AK::WwiseTransfer diff --git a/src/shared/UI/HierarchyMappingControls.h b/src/shared/UI/HierarchyMappingControls.h @@ -0,0 +1,43 @@ +#pragma once + +#include "CustomDrawableButton.h" +#include "Model/Import.h" +#include "PresetMenuComponent.h" + +#include <juce_gui_basics/juce_gui_basics.h> + +namespace AK::WwiseTransfer +{ + class HierarchyMappingControls + : public juce::Component + , private juce::ValueTree::Listener + , private juce::AsyncUpdater + { + public: + HierarchyMappingControls(juce::ValueTree appState, ApplicationProperties& applicationProperties, const juce::String& applicationName); + ~HierarchyMappingControls(); + + void resized() override; + + private: + juce::ValueTree applicationState; + juce::ValueTree hierarchyMapping; + juce::CachedValue<int> selectedRow; + + CustomDrawableButton insertButton; + CustomDrawableButton removeButton; + CustomDrawableButton moveUpButton; + CustomDrawableButton moveDownButton; + + PresetMenuComponent presetMenuComponent; + + void valueTreePropertyChanged(juce::ValueTree& treeWhosePropertyHasChanged, const juce::Identifier& property) override; + void valueTreeChildAdded(juce::ValueTree& parentTree, juce::ValueTree& childWhichHasBeenAdded) override; + void valueTreeChildRemoved(juce::ValueTree& parentTree, juce::ValueTree& childWhichHasBeenRemoved, int indexFromWhichChildWasRemoved) override; + + void handleAsyncUpdate() override; + void refreshComponent(); + + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(HierarchyMappingControls); + }; +} // namespace AK::WwiseTransfer diff --git a/src/shared/UI/HierarchyMappingTable.cpp b/src/shared/UI/HierarchyMappingTable.cpp @@ -0,0 +1,230 @@ +#include "HierarchyMappingTable.h" + +#include "Helpers/ImportHelper.h" +#include "Model/Import.h" +#include "Theme/CustomLookAndFeel.h" + +namespace AK::WwiseTransfer +{ + enum HierarchyMappingTableColumn + { + ObjectType = 1, + ObjectName, + PropertyTemplatePath + }; + + namespace HierarchyMappingTableConstants + { + constexpr int tableHeaderHeight = 24; + constexpr int columnInitialWidth = 10; + constexpr int margin = 4; + inline const std::initializer_list<juce::String> tableHeaders{"Object Type", "Object Name", "Property Template Path"}; + constexpr int columnMinimumWidth = 10; + constexpr int columnMaximumWidth = 1000; + constexpr int defaultColumnPropertyFlags = juce::TableHeaderComponent::ColumnPropertyFlags::visible | juce::TableHeaderComponent::ColumnPropertyFlags::resizable; + constexpr int disabledFlag = 128; + } // namespace HierarchyMappingTableConstants + + HierarchyMappingTable::HierarchyMappingTable(juce::ValueTree appState) + : applicationState(appState) + , hierarchyMapping(applicationState.getChildWithName(IDs::hierarchyMapping)) + , selectedRow(hierarchyMapping, IDs::selectedRow, nullptr) + , model(appState) + { + using namespace HierarchyMappingTableConstants; + + auto featureSupport = appState.getChildWithName(IDs::featureSupport); + applyTemplateFeatureEnabled.referTo(featureSupport, IDs::applyTemplateFeatureEnabled, nullptr); + + setModel(&model); + + for(const auto& tableHeader : tableHeaders) + { + auto index = (&tableHeader - tableHeaders.begin()); + getHeader().addColumn(tableHeader, index + 1, columnInitialWidth, columnMinimumWidth, columnMaximumWidth, defaultColumnPropertyFlags); + } + + getHeader().setPopupMenuActive(false); + setHeaderHeight(tableHeaderHeight); + applicationState.addListener(this); + + selectRow(selectedRow.get()); + + refreshHeader(); + } + + HierarchyMappingTable::~HierarchyMappingTable() + { + applicationState.removeListener(this); + } + + void HierarchyMappingTable::valueTreePropertyChanged(juce::ValueTree& treeWhosePropertyHasChanged, const juce::Identifier& property) + { + auto treeType = treeWhosePropertyHasChanged.getType(); + + if(treeType == IDs::hierarchyMappingNode || treeType == IDs::hierarchyMapping && property == IDs::selectedRow) + { + repaint(); + } + + if(treeType == IDs::featureSupport && property == IDs::applyTemplateFeatureEnabled) + { + refreshHeader(); + } + } + + void HierarchyMappingTable::valueTreeChildAdded(juce::ValueTree& parentTree, juce::ValueTree& childWhichHasBeenAdded) + { + if(parentTree.getType() == IDs::hierarchyMapping) + { + updateContent(); + resized(); + + if(parentTree.getNumChildren() == 1) + selectRow(0); + } + } + + void HierarchyMappingTable::valueTreeChildRemoved(juce::ValueTree& parentTree, juce::ValueTree& childWhichHasBeenRemoved, int indexFromWhichChildWasRemoved) + { + if(parentTree.getType() == IDs::hierarchyMapping) + { + updateContent(); + resized(); + + if(selectedRow == -1 && indexFromWhichChildWasRemoved != 0) + selectRow(indexFromWhichChildWasRemoved - 1); + } + } + + void HierarchyMappingTable::valueTreeChildOrderChanged(juce::ValueTree& parentTreeWhoseChildrenHaveMoved, int oldIndex, int newIndex) + { + if(parentTreeWhoseChildrenHaveMoved.getType() == IDs::hierarchyMapping) + { + repaint(); + + selectRow(newIndex); + } + } + + void HierarchyMappingTable::selectedRowsChanged(int row) + { + selectedRow = row; + } + + void HierarchyMappingTable::refreshHeader() + { + using namespace HierarchyMappingTableConstants; + + // For some reason, the column width measurement only works properly if the following attribute is set to false + getHeader().setStretchToFitActive(false); + + auto currentWidth = getHeader().getColumnWidth(tableHeaders.size()); + auto propertyFlags = defaultColumnPropertyFlags; + + if(!applyTemplateFeatureEnabled.get()) + propertyFlags |= disabledFlag; + + getHeader().removeColumn(tableHeaders.size()); + getHeader().addColumn(*(tableHeaders.end() - 1), tableHeaders.size(), currentWidth, columnMinimumWidth, columnMaximumWidth, propertyFlags); + + getHeader().setStretchToFitActive(true); + } + + HierarchyMappingTable::HierarchyMappingTableModel::HierarchyMappingTableModel(juce::ValueTree appState) + : hierarchyMapping(appState.getChildWithName(IDs::hierarchyMapping)) + { + auto featureSupport = appState.getChildWithName(IDs::featureSupport); + applyTemplateFeatureEnabled.referTo(featureSupport, IDs::applyTemplateFeatureEnabled, nullptr); + } + + int HierarchyMappingTable::HierarchyMappingTableModel::getNumRows() + { + return hierarchyMapping.getNumChildren(); + } + + void HierarchyMappingTable::HierarchyMappingTableModel::paintRowBackground(juce::Graphics& g, int rowNumber, int width, int height, bool rowIsSelected) + { + if(rowIsSelected) + g.fillAll(juce::LookAndFeel::getDefaultLookAndFeel().findColour(juce::TextEditor::highlightColourId)); + else + g.fillAll(juce::LookAndFeel::getDefaultLookAndFeel().findColour(juce::ListBox::backgroundColourId)); + } + + void HierarchyMappingTable::HierarchyMappingTableModel::paintCell(juce::Graphics& g, int rowNumber, int columnId, int width, int height, bool rowIsSelected) + { + using namespace HierarchyMappingTableConstants; + + auto hierarchyMappingNode = ImportHelper::valueTreeToHiarchyMappingNode(hierarchyMapping.getChild(rowNumber)); + + juce::String text; + bool cellEnabled = true; + bool validCell = true; + + switch(columnId) + { + case HierarchyMappingTableColumn::ObjectType: + { + text = hierarchyMappingNode.type == Wwise::ObjectType::Unknown ? "Select Object Type" : WwiseHelper::objectTypeToReadableString(hierarchyMappingNode.type); + validCell = hierarchyMappingNode.typeValid; + break; + } + case HierarchyMappingTableColumn::ObjectName: + { + text = hierarchyMappingNode.name; + validCell = hierarchyMappingNode.nameValid; + break; + } + case HierarchyMappingTableColumn::PropertyTemplatePath: + { + text = hierarchyMappingNode.propertyTemplatePath; + cellEnabled = hierarchyMappingNode.propertyTemplatePathEnabled && applyTemplateFeatureEnabled; + validCell = hierarchyMappingNode.propertyTemplatePathValid; + break; + } + } + + // Cell color depends on table enablement, field enablement and field error STATE + auto textColor = juce::LookAndFeel::getDefaultLookAndFeel().findColour(juce::TextEditor::textColourId); + + auto alpha = cellEnabled ? 1.0f : 0.5f; + + g.setFont(CustomLookAndFeelConstants::smallFontSize); + g.setColour(textColor.withAlpha(alpha)); + g.drawText(text, margin, 0, width, height, juce::Justification::left); + + if(cellEnabled && !validCell) + { + g.setColour(juce::Colour(juce::Colours::red).withAlpha(alpha)); + g.drawRect(0, 0, width, height); + } + } + + juce::String HierarchyMappingTable::HierarchyMappingTableModel::getCellTooltip(int rowNumber, int columnId) + { + juce::String tooltipText; + + auto hierarchyMappingNode = ImportHelper::valueTreeToHiarchyMappingNode(hierarchyMapping.getChild(rowNumber)); + + switch(columnId) + { + case HierarchyMappingTableColumn::ObjectType: + { + tooltipText = hierarchyMappingNode.typeErrorMessage; + break; + } + case HierarchyMappingTableColumn::ObjectName: + { + tooltipText = hierarchyMappingNode.nameErrorMessage; + break; + } + case HierarchyMappingTableColumn::PropertyTemplatePath: + { + tooltipText = hierarchyMappingNode.propertyTemplatePathErrorMessage; + break; + } + } + + return tooltipText; + } +} // namespace AK::WwiseTransfer diff --git a/src/shared/UI/HierarchyMappingTable.h b/src/shared/UI/HierarchyMappingTable.h @@ -0,0 +1,52 @@ +#pragma once + +#include "Model/Import.h" + +#include <juce_gui_basics/juce_gui_basics.h> + +namespace AK::WwiseTransfer +{ + class HierarchyMappingTable + : public juce::TableListBox + , public juce::ValueTree::Listener + { + public: + HierarchyMappingTable(juce::ValueTree appState); + ~HierarchyMappingTable() override; + + private: + struct HierarchyMappingTableModel + : public juce::TableListBoxModel + { + HierarchyMappingTableModel(juce::ValueTree appState); + + int getNumRows() override; + void paintRowBackground(juce::Graphics&, int rowNumber, int width, int height, bool rowIsSelected) override; + void paintCell(juce::Graphics&, int rowNumber, int columnId, int width, int height, bool rowIsSelected) override; + juce::String getCellTooltip(int rowNumber, int columnId) override; + + private: + juce::ValueTree hierarchyMapping; + juce::CachedValue<int> selectedRow; + juce::CachedValue<bool> applyTemplateFeatureEnabled; + }; + + HierarchyMappingTableModel model; + juce::ValueTree applicationState; + juce::ValueTree hierarchyMapping; + juce::CachedValue<int> selectedRow; + juce::CachedValue<bool> applyTemplateFeatureEnabled; + + void valueTreePropertyChanged(juce::ValueTree& treeWhosePropertyHasChanged, const juce::Identifier& property) override; + void valueTreeChildAdded(juce::ValueTree& parentTree, juce::ValueTree& childWhichHasBeenAdded) override; + void valueTreeChildRemoved(juce::ValueTree& parentTree, juce::ValueTree& childWhichHasBeenRemoved, int indexFromWhichChildWasRemoved) override; + void valueTreeChildOrderChanged(juce::ValueTree& parentTreeWhoseChildrenHaveMoved, int oldIndex, int newIndex) override; + + void selectedRowsChanged(int row) override; + + private: + void refreshHeader(); + + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(HierarchyMappingTable) + }; +} // namespace AK::WwiseTransfer diff --git a/src/shared/UI/ImportComponent.cpp b/src/shared/UI/ImportComponent.cpp @@ -0,0 +1,52 @@ +#include "ImportComponent.h" + +#include "Model/IDs.h" +#include "Model/Import.h" + +namespace AK::WwiseTransfer +{ + namespace ImportComponentConstants + { + constexpr int margin = 10; + constexpr int spacing = 4; + constexpr int marginHorizontal = 12; + constexpr int topMargin = 20; + constexpr int hierarchyMappingTableHeight = 124; + constexpr int selectedRowPropertiesSectionHeight = 134; + constexpr int hierarchyMappingControlsWidth = 24; + } // namespace ImportComponentConstants + + ImportComponent::ImportComponent(juce::ValueTree appState, WaapiClient& waapiClient, ApplicationProperties& applicationProperties, const juce::String& applicationName) + : hierarchyMappingTable(appState) + , hierarchyMappingControls(appState, applicationProperties, applicationName) + , selectedRowPropertiesComponent(appState, waapiClient) + { + setText("Wwise Structures"); + + addAndMakeVisible(hierarchyMappingTable); + addAndMakeVisible(hierarchyMappingControls); + addAndMakeVisible(selectedRowPropertiesComponent); + } + + void ImportComponent::resized() + { + using namespace ImportComponentConstants; + + auto area = getLocalBounds(); + + area.reduce(marginHorizontal, 0); + area.removeFromTop(topMargin); + area.removeFromBottom(margin); + + auto hierarchyMappingTableArea = area.removeFromTop(hierarchyMappingTableHeight); + { + hierarchyMappingControls.setBounds(hierarchyMappingTableArea.removeFromRight(hierarchyMappingControlsWidth)); + hierarchyMappingTableArea.removeFromRight(spacing); + + hierarchyMappingTable.setBounds(hierarchyMappingTableArea); + } + + area.removeFromTop(spacing); + selectedRowPropertiesComponent.setBounds(area.removeFromTop(selectedRowPropertiesSectionHeight)); + } +} // namespace AK::WwiseTransfer diff --git a/src/shared/UI/ImportComponent.h b/src/shared/UI/ImportComponent.h @@ -0,0 +1,33 @@ +#pragma once + +#include "Core/WaapiClient.h" +#include "HierarchyMappingControls.h" +#include "HierarchyMappingTable.h" +#include "Model/Import.h" +#include "Persistance/ApplicationProperties.h" +#include "PresetMenuComponent.h" +#include "SelectedRowPropertiesComponent.h" +#include "SimpleListBox.h" + +#include <juce_gui_basics/juce_gui_basics.h> + +namespace AK::WwiseTransfer +{ + class ImportComponent + : public juce::GroupComponent + { + public: + ImportComponent(juce::ValueTree appState, WaapiClient& waapiClient, ApplicationProperties& applicationProperties, const juce::String& applicationName); + + void resized() override; + + private: + juce::Label hierarchyMappingLabel; + HierarchyMappingTable hierarchyMappingTable; + HierarchyMappingControls hierarchyMappingControls; + + SelectedRowPropertiesComponent selectedRowPropertiesComponent; + + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(ImportComponent); + }; +} // namespace AK::WwiseTransfer diff --git a/src/shared/UI/ImportConflictsComponent.cpp b/src/shared/UI/ImportConflictsComponent.cpp @@ -0,0 +1,116 @@ +#include "ImportConflictsComponent.h" + +#include "Helpers/ImportHelper.h" +#include "Model/IDs.h" + +namespace AK::WwiseTransfer +{ + namespace ImportConflictsComponentContants + { + constexpr int margin = 10; + constexpr int editorBoxHeight = 26; + constexpr int labelWidth = 136; + constexpr std::initializer_list<Import::ContainerNameExistsOption> containerNameExistsOptions{Import::ContainerNameExistsOption::UseExisting, + Import::ContainerNameExistsOption::CreateNew, Import::ContainerNameExistsOption::Replace}; + constexpr std::initializer_list<Import::ApplyTemplateOption> applyTemplateOptions{Import::ApplyTemplateOption::Always, + Import::ApplyTemplateOption::NewObjectCreationOnly}; + const juce::String pastePropertiesToolTip = "Paste properties are only available when connected to Wwise 2022+"; + } // namespace ImportConflictsComponentContants + + ImportConflictsComponent::ImportConflictsComponent(juce::ValueTree appState) + : applicationState(appState) + , containerNameExists(applicationState, IDs::containerNameExists, nullptr) + , audioFilenameExists(applicationState, IDs::audioFileNameExists, nullptr) + , applyTemplate(applicationState, IDs::applyTemplate, nullptr) + { + using namespace ImportConflictsComponentContants; + + auto featureSupport = applicationState.getChildWithName(IDs::featureSupport); + applyTemplateFeatureEnabled.referTo(featureSupport, IDs::applyTemplateFeatureEnabled, nullptr); + + containerNameExistsLabel.setText("If Sound Name Exists", juce::dontSendNotification); + containerNameExistsLabel.setBorderSize(juce::BorderSize(0)); + containerNameExistsLabel.setMinimumHorizontalScale(1.0f); + containerNameExistsLabel.setJustificationType(juce::Justification::right); + + applyTemplateLabel.setText("Apply Template", juce::dontSendNotification); + applyTemplateLabel.setBorderSize(juce::BorderSize(0)); + applyTemplateLabel.setMinimumHorizontalScale(1.0f); + applyTemplateLabel.setJustificationType(juce::Justification::right); + + for(auto& containerNameExistsOption : containerNameExistsOptions) + containerNameExistsComboBox.addItem(ImportHelper::containerNameExistsOptionToReadableString(containerNameExistsOption), static_cast<int>(containerNameExistsOption)); + + for(auto& applyTemplateOption : applyTemplateOptions) + applyTemplateComboBox.addItem(ImportHelper::applyTemplateOptionToReadableString(applyTemplateOption), static_cast<int>(applyTemplateOption)); + + containerNameExistsComboBox.getSelectedIdAsValue().referTo(containerNameExists.getPropertyAsValue()); + audioFileNameExistsComboBox.getSelectedIdAsValue().referTo(audioFilenameExists.getPropertyAsValue()); + applyTemplateComboBox.getSelectedIdAsValue().referTo(applyTemplate.getPropertyAsValue()); + + addAndMakeVisible(containerNameExistsLabel); + addAndMakeVisible(audioFileNameExistsLabel); + addAndMakeVisible(applyTemplateLabel); + addAndMakeVisible(containerNameExistsComboBox); + addAndMakeVisible(audioFileNameExistsComboBox); + addAndMakeVisible(applyTemplateComboBox); + + refreshComponent(); + + applicationState.addListener(this); + } + + ImportConflictsComponent::~ImportConflictsComponent() + { + applicationState.removeListener(this); + } + + void ImportConflictsComponent::resized() + { + using namespace ImportConflictsComponentContants; + + auto area = getLocalBounds(); + + auto containerNameSection = area.removeFromTop(editorBoxHeight); + { + containerNameExistsLabel.setBounds(containerNameSection.removeFromLeft(labelWidth)); + containerNameSection.removeFromLeft(margin); + + containerNameExistsComboBox.setBounds(containerNameSection); + } + + area.removeFromTop(margin); + + auto applyTemplateSection = area.removeFromTop(editorBoxHeight); + { + applyTemplateLabel.setBounds(applyTemplateSection.removeFromLeft(labelWidth)); + applyTemplateSection.removeFromLeft(margin); + + applyTemplateComboBox.setBounds(applyTemplateSection); + } + } + + void ImportConflictsComponent::valueTreePropertyChanged(juce::ValueTree& treeWhosePropertyHasChanged, const juce::Identifier& property) + { + if(treeWhosePropertyHasChanged.getType() == IDs::featureSupport && property == IDs::applyTemplateFeatureEnabled) + { + triggerAsyncUpdate(); + } + } + + void ImportConflictsComponent::handleAsyncUpdate() + { + refreshComponent(); + } + + void ImportConflictsComponent::refreshComponent() + { + using namespace ImportConflictsComponentContants; + + applyTemplateLabel.setEnabled(applyTemplateFeatureEnabled); + applyTemplateComboBox.setEnabled(applyTemplateFeatureEnabled); + + applyTemplateLabel.setTooltip(applyTemplateFeatureEnabled ? "" : pastePropertiesToolTip); + applyTemplateComboBox.setTooltip(applyTemplateFeatureEnabled ? "" : pastePropertiesToolTip); + } +} // namespace AK::WwiseTransfer diff --git a/src/shared/UI/ImportConflictsComponent.h b/src/shared/UI/ImportConflictsComponent.h @@ -0,0 +1,44 @@ +#pragma once + +#include "Model/Import.h" + +#include <juce_gui_basics/juce_gui_basics.h> + +namespace AK::WwiseTransfer +{ + class ImportConflictsComponent + : public juce::Component + , private juce::ValueTree::Listener + , private juce::AsyncUpdater + { + public: + ImportConflictsComponent(juce::ValueTree applicationState); + ~ImportConflictsComponent(); + + void resized() override; + + private: + juce::Label containerNameExistsLabel; + juce::Label audioFileNameExistsLabel; + juce::Label applyTemplateLabel; + + juce::ComboBox containerNameExistsComboBox; + juce::ComboBox audioFileNameExistsComboBox; + juce::ComboBox applyTemplateComboBox; + + juce::ValueTree applicationState; + juce::CachedValue<Import::ContainerNameExistsOption> containerNameExists; + juce::CachedValue<Import::AudioFilenameExistsOption> audioFilenameExists; + juce::CachedValue<Import::ApplyTemplateOption> applyTemplate; + + juce::CachedValue<bool> applyTemplateFeatureEnabled; + + juce::CachedValue<juce::String> selectObjectsOnImportCommand; + + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(ImportConflictsComponent); + + void valueTreePropertyChanged(juce::ValueTree& treeWhosePropertyHasChanged, const juce::Identifier& property) override; + void handleAsyncUpdate() override; + void refreshComponent(); + }; +} // namespace AK::WwiseTransfer diff --git a/src/shared/UI/ImportControlsComponent.cpp b/src/shared/UI/ImportControlsComponent.cpp @@ -0,0 +1,297 @@ +#include "ImportControlsComponent.h" + +#include "Helpers/ImportHelper.h" +#include "Model/IDs.h" + +namespace AK::WwiseTransfer +{ + enum MessageBoxOption + { + Cancel = 0, + Continue = 1 + }; + + namespace ImportControlsComponentConstants + { + constexpr int showSilentIncrementWarningToggleWidth = 300; + constexpr int showSilentIncrementWarningToggleHeight = 60; + constexpr int showSilentIncrementWarningToggleMarginLeft = 78; + }; // namespace ImportControlsComponentConstants + + ImportControlsComponent::ImportControlsComponent(juce::ValueTree appState, WaapiClient& waapiClient, DawContext& dawContext, ApplicationProperties& applicationProperties, const juce::String& applicationName) + : applicationState(appState) + , originalsSubfolderValid(applicationState, IDs::originalsSubfolderValid, nullptr) + , importDestinationValid(applicationState, IDs::importDestinationValid, nullptr) + , importDestination(applicationState, IDs::importDestination, nullptr) + , originalsSubFolder(applicationState, IDs::originalsSubfolder, nullptr) + , projectPath(applicationState, IDs::projectPath, nullptr) + , containerNameExistsOption(applicationState, IDs::containerNameExists, nullptr) + , applyTemplateOption(applicationState, IDs::applyTemplate, nullptr) + , hierarchyMapping(applicationState.getChildWithName(IDs::hierarchyMapping)) + , waapiClient(waapiClient) + , dawContext(dawContext) + , applicationProperties(applicationProperties) + , applicationName(applicationName) + { + using namespace ImportControlsComponentConstants; + + auto featureSupport = applicationState.getChildWithName(IDs::featureSupport); + selectObjectsOnImportCommand.referTo(featureSupport, IDs::selectObjectsOnImportCommand, nullptr); + applyTemplateFeatureEnabled.referTo(featureSupport, IDs::applyTemplateFeatureEnabled, nullptr); + undoGroupFeatureEnabled.referTo(featureSupport, IDs::undoGroupFeatureEnabled, nullptr); + + importButton.setButtonText("Transfer to Wwise"); + + importButton.onClick = [this] + { + onImportButtonClick(); + }; + + addAndMakeVisible(importButton); + + refreshComponent(); + + applicationState.addListener(this); + + showSilentIncrementWarningToggle.setButtonText("Don't show message again"); + showSilentIncrementWarningToggle.setSize(showSilentIncrementWarningToggleWidth, showSilentIncrementWarningToggleHeight); + } + + ImportControlsComponent::~ImportControlsComponent() + { + applicationState.removeListener(this); + } + + void ImportControlsComponent::resized() + { + importButton.setBounds(getLocalBounds()); + } + + void ImportControlsComponent::onImportButtonClick() + { + using namespace ImportControlsComponentConstants; + + juce::Logger::writeToLog("Sending render request to daw"); + + dawContext.renderImportItems(); + + auto hierarchyMappingPath = ImportHelper::hierarchyMappingToPath(ImportHelper::valueTreeToHierarchyMappingNodeList(applicationState.getChildWithName(IDs::hierarchyMapping))); + + Import::Options opts(importDestination, originalsSubFolder, hierarchyMappingPath); + + auto importItems = dawContext.getImportItems(opts); + + auto showRenameWarning = false, showRenderFailed = false; + if(importItems.size()) + { + for(auto& importItem : importItems) + { + if(importItem.renderFilePath.isEmpty()) + { + showRenderFailed = true; + break; + } + else if(importItem.audioFilePath != importItem.renderFilePath) + { + showRenameWarning = true; + break; + } + } + } + + auto hierarchyMappingNodeList = ImportHelper::valueTreeToHierarchyMappingNodeList(hierarchyMapping); + + Import::Task::Options importTaskOptions{ + importItems, + containerNameExistsOption, + applyTemplateOption, + importDestination, + hierarchyMappingNodeList, + selectObjectsOnImportCommand, + applyTemplateFeatureEnabled, + undoGroupFeatureEnabled}; + + auto onImportComplete = [this, importTaskOptions = importTaskOptions](const Import::Summary& importSummary) + { + showImportSummary(importSummary, importTaskOptions); + }; + + importTask.reset(new ImportTask(waapiClient, importTaskOptions, onImportComplete)); + + if(showRenderFailed) + { + juce::String message("One or more files failed to render."); + + juce::Logger::writeToLog(message); + + juce::AlertWindow::showMessageBoxAsync(juce::MessageBoxIconType::InfoIcon, "Import Aborted", message); + } + else if(showRenameWarning && applicationProperties.getShowSilentIncrementWarning()) + { + juce::String message("Several file names where silently incremented to avoid overwriting during the render process."); + + juce::Logger::writeToLog(message); + + auto onDialogBtnClicked = [this, importItems = importItems](int result) + { + applicationProperties.setShowSilentIncrementWarning(!showSilentIncrementWarningToggle.getToggleState()); + + if(result == MessageBoxOption::Continue) + { + importTask->launchThread(); + } + }; + + auto messageBoxOptions = juce::MessageBoxOptions() + .withTitle("Action Required") + .withMessage(message) + .withButton("Continue") + .withButton("Cancel"); + + juce::AlertWindow::showAsync(messageBoxOptions, onDialogBtnClicked); + + auto modalManager = juce::ModalComponentManager::getInstance(); + auto alertWindow = dynamic_cast<juce::AlertWindow*>(modalManager->getModalComponent(0)); + alertWindow->addCustomComponent(&showSilentIncrementWarningToggle); + + // Reset and reposition the toggle button + showSilentIncrementWarningToggle.setToggleState(false, true); + auto bounds = showSilentIncrementWarningToggle.getBounds(); + bounds.setX(showSilentIncrementWarningToggleMarginLeft); + showSilentIncrementWarningToggle.setBounds(bounds); + } + else + { + importTask->launchThread(); + } + } + + void ImportControlsComponent::showImportSummary(const Import::Summary& summary, const Import::Task::Options& importTaskOptions) + { + juce::String message; + + message << summary.objectsCreated << " object(s) created."; + message << juce::NewLine() << summary.objectTemplatesApplied << " object template(s) applied."; + message << juce::NewLine() << summary.audioFilesImported << " audio files(s) imported."; + + if(summary.errorMessage.isNotEmpty()) + message << juce::NewLine() << summary.errorMessage; + + auto messageBoxOptions = juce::MessageBoxOptions() + .withTitle("Import Summary") + .withMessage(message) + .withButton("View Details") + .withButton("Dismiss"); + + auto onDialogBtnClicked = [this, summary = summary, importTaskOptions = importTaskOptions](int result) + { + if(result == MessageBoxOption::Continue) + { + viewImportSummaryDetails(summary, importTaskOptions); + } + }; + + juce::AlertWindow::showAsync(messageBoxOptions, onDialogBtnClicked); + } + + void ImportControlsComponent::viewImportSummaryDetails(const Import::Summary& summary, const Import::Task::Options& importTaskOptions) + { + auto currentTime = juce::Time::getCurrentTime(); + + auto importSummaryFile = juce::File::getSpecialLocation(juce::File::tempDirectory) + .getChildFile(applicationName + "_ImportSummary_" + currentTime.formatted("%Y-%m-%d_%H-%M-%S")) + .withFileExtension(".html"); + + importSummaryFile.create(); + + importSummaryFile.appendText("<style>table td, th { border:1px solid black; padding:10px; }"); + importSummaryFile.appendText("table { border-collapse:collapse; }"); + importSummaryFile.appendText("table th { text-align: left; }</style>"); + importSummaryFile.appendText("<pre>" + applicationName + ": Import Summary " + currentTime.formatted("%Y-%m-%d %H:%M:%S") + "\n\n"); + importSummaryFile.appendText("Import Destination: " + importTaskOptions.importDestination + "\n"); + importSummaryFile.appendText("Container Name Exists: " + ImportHelper::containerNameExistsOptionToReadableString(importTaskOptions.containerNameExistsOption) + "\n"); + importSummaryFile.appendText("Apply Template: " + ImportHelper::applyTemplateOptionToReadableString(importTaskOptions.applyTemplateOption) + "\n\n"); + + importSummaryFile.appendText("Objects created: " + juce::String(summary.objectsCreated) + "\n"); + importSummaryFile.appendText("Object Templates Applied: " + juce::String(summary.objectTemplatesApplied) + "\n"); + importSummaryFile.appendText("Audio Files Imported: " + juce::String(summary.audioFilesImported) + "\n\n"); + + importSummaryFile.appendText("<table><tr><th>Object Path</th><th>Type</th><th>Created</th><th>Originals Wav</th><th>Property Template Applied</th></tr>"); + + for(const auto& [objectPath, object] : summary.objects) + { + importSummaryFile.appendText("<tr><td>" + objectPath + "</td><td>" + WwiseHelper::objectTypeToReadableString(object.type) + "</td><td>" + (object.newlyCreated ? "X" : "") + "</td><td>" + object.originalWavFilePath + "</td><td>" + object.propertyTemplatePath + "</td></tr>"); + } + + importSummaryFile.appendText("</table></pre>"); + + juce::URL importSummaryFileUrl(importSummaryFile.getFullPathName()); + importSummaryFileUrl.launchInDefaultBrowser(); + } + + void ImportControlsComponent::refreshComponent() + { + auto importButtonEnabled = originalsSubfolderValid.get() && importDestinationValid.get() && projectPath.get().isNotEmpty(); + + auto hieararchyMappingNodes = ImportHelper::valueTreeToHierarchyMappingNodeList(hierarchyMapping); + + auto hierarchyMappingValid = true; + for(const auto& hierarchyMappingNode : hieararchyMappingNodes) + { + hierarchyMappingValid &= hierarchyMappingNode.typeValid && + hierarchyMappingNode.nameValid && + (!hierarchyMappingNode.propertyTemplatePathEnabled || hierarchyMappingNode.propertyTemplatePathValid); + } + + importButtonEnabled &= hierarchyMappingValid; + + importButton.setEnabled(importButtonEnabled); + + juce::String tooltip = ""; + + if(projectPath.get().isEmpty()) + tooltip = "Connect to Wwise to continue"; + else if(!importButtonEnabled) + tooltip = "Fix pending errors to continue"; + + importButton.setTooltip(tooltip); + } + + void ImportControlsComponent::valueTreePropertyChanged(juce::ValueTree& treeWhosePropertyHasChanged, const juce::Identifier& property) + { + if(treeWhosePropertyHasChanged == applicationState && (property == IDs::originalsSubfolderValid || property == IDs::importDestinationValid || property == IDs::projectPath) || + treeWhosePropertyHasChanged.getType() == IDs::hierarchyMappingNode) + { + triggerAsyncUpdate(); + } + } + + void ImportControlsComponent::valueTreeChildAdded(juce::ValueTree& parentTree, juce::ValueTree& childWhichHasBeenAdded) + { + if(parentTree.getType() == IDs::hierarchyMapping) + { + triggerAsyncUpdate(); + } + } + + void ImportControlsComponent::valueTreeChildRemoved(juce::ValueTree& parentTree, juce::ValueTree& childWhichHasBeenRemoved, int indexFromWhichChildWasRemoved) + { + if(parentTree.getType() == IDs::hierarchyMapping) + { + triggerAsyncUpdate(); + } + } + + void ImportControlsComponent::valueTreeChildOrderChanged(juce::ValueTree& parentTreeWhoseChildrenHaveMoved, int oldIndex, int newIndex) + { + if(parentTreeWhoseChildrenHaveMoved.getType() == IDs::hierarchyMapping) + { + triggerAsyncUpdate(); + } + } + + void ImportControlsComponent::handleAsyncUpdate() + { + refreshComponent(); + } +} // namespace AK::WwiseTransfer diff --git a/src/shared/UI/ImportControlsComponent.h b/src/shared/UI/ImportControlsComponent.h @@ -0,0 +1,64 @@ +#pragma once + +#include "Core/DawContext.h" +#include "Core/ImportTask.h" +#include "Core/WaapiClient.h" +#include "Persistance/ApplicationProperties.h" + +#include <juce_gui_basics/juce_gui_basics.h> + +namespace AK::WwiseTransfer +{ + class ImportControlsComponent + : public juce::Component + , private juce::ValueTree::Listener + , private juce::AsyncUpdater + { + public: + ImportControlsComponent(juce::ValueTree appState, WaapiClient& waapiClient, DawContext& dawContext, ApplicationProperties& applicationProperties, const juce::String& applicationName); + ~ImportControlsComponent() override; + + void resized() override; + + private: + juce::TextButton importButton; + juce::ValueTree applicationState; + juce::CachedValue<bool> originalsSubfolderValid; + juce::CachedValue<bool> importDestinationValid; + juce::CachedValue<juce::String> importDestination; + juce::CachedValue<juce::String> originalsSubFolder; + juce::CachedValue<juce::String> projectPath; + juce::CachedValue<Import::ContainerNameExistsOption> containerNameExistsOption; + juce::CachedValue<Import::ApplyTemplateOption> applyTemplateOption; + juce::ValueTree hierarchyMapping; + + juce::CachedValue<juce::String> selectObjectsOnImportCommand; + juce::CachedValue<bool> applyTemplateFeatureEnabled; + juce::CachedValue<bool> undoGroupFeatureEnabled; + + WaapiClient& waapiClient; + DawContext& dawContext; + ApplicationProperties& applicationProperties; + + std::unique_ptr<juce::ThreadWithProgressWindow> importTask; + + juce::ToggleButton showSilentIncrementWarningToggle; + + const juce::String applicationName; + + void onImportButtonClick(); + void showImportSummary(const Import::Summary& summary, const Import::Task::Options& importTaskOptions); + void viewImportSummaryDetails(const Import::Summary& summary, const Import::Task::Options& importTaskOptions); + + void refreshComponent(); + + void valueTreePropertyChanged(juce::ValueTree& treeWhosePropertyHasChanged, const juce::Identifier& property) override; + void valueTreeChildAdded(juce::ValueTree& parentTree, juce::ValueTree& childWhichHasBeenAdded); + void valueTreeChildRemoved(juce::ValueTree& parentTree, juce::ValueTree& childWhichHasBeenRemoved, int indexFromWhichChildWasRemoved); + void valueTreeChildOrderChanged(juce::ValueTree& parentTreeWhoseChildrenHaveMoved, int oldIndex, int newIndex); + + void handleAsyncUpdate() override; + + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(ImportControlsComponent) + }; +} // namespace AK::WwiseTransfer diff --git a/src/shared/UI/ImportDestinationComponent.cpp b/src/shared/UI/ImportDestinationComponent.cpp @@ -0,0 +1,105 @@ +#include "ImportDestinationComponent.h" + +#include "BinaryData.h" +#include "Persistance/ApplicationState.h" +#include "Theme/CustomLookAndFeel.h" + +namespace AK::WwiseTransfer +{ + namespace ImportDestinationComponentConstants + { + constexpr int margin = 10; + constexpr int spacing = 4; + constexpr int editorBoxHeight = 26; + constexpr int labelWidth = 120; + constexpr int syncButtonWidth = 36; + } // namespace ImportDestinationComponentConstants + + ImportDestinationComponent::ImportDestinationComponent(juce::ValueTree appState, WaapiClient& waapiClient) + : applicationState(appState) + , waapiClient(waapiClient) + , importDestination(applicationState, IDs::importDestination, nullptr) + , importDestinationType(applicationState, IDs::importDestinationType, nullptr) + , projectPath(applicationState, IDs::projectPath, nullptr) + , updateImportDestinationButton("UpdateImportDestinationButton", juce::Drawable::createFromImageData(BinaryData::General_GetFromWwise_Normal_svg, BinaryData::General_GetFromWwise_Normal_svgSize)) + { + importDestinationLabel.setText("Import Destination", juce::dontSendNotification); + importDestinationLabel.setBorderSize(juce::BorderSize(0)); + importDestinationLabel.setMinimumHorizontalScale(1.0f); + importDestinationLabel.setJustificationType(juce::Justification::right); + + importDestinationEditor.setFont(CustomLookAndFeelConstants::smallFontSize); + importDestinationEditor.getTextValue().referTo(importDestination.getPropertyAsValue()); + importDestinationEditor.getValidationValue().referTo(applicationState.getPropertyAsValue(IDs::importDestinationValid, nullptr)); + importDestinationEditor.getErrorMessageValue().referTo(applicationState.getPropertyAsValue(IDs::importDestinationErrorMessage, nullptr)); + + updateImportDestinationButton.setTooltip("Sync with selected object in Wwise"); + + updateImportDestinationButton.onClick = [this] + { + updateImportDestination(); + }; + + applicationState.addListener(this); + + addAndMakeVisible(importDestinationLabel); + addAndMakeVisible(importDestinationEditor); + addAndMakeVisible(updateImportDestinationButton); + + refreshComponent(); + } + + ImportDestinationComponent::~ImportDestinationComponent() + { + applicationState.removeListener(this); + } + + void ImportDestinationComponent::resized() + { + using namespace ImportDestinationComponentConstants; + + auto area = getLocalBounds(); + + auto ImportDestinationSection = area.removeFromTop(editorBoxHeight); + { + importDestinationLabel.setBounds(ImportDestinationSection.removeFromLeft(labelWidth)); + ImportDestinationSection.removeFromLeft(margin); + + updateImportDestinationButton.setBounds(ImportDestinationSection.removeFromRight(syncButtonWidth)); + ImportDestinationSection.removeFromRight(spacing); + + importDestinationEditor.setBounds(ImportDestinationSection); + } + } + + void ImportDestinationComponent::refreshComponent() + { + auto projectPathEmpty = projectPath.get().isEmpty(); + + updateImportDestinationButton.setEnabled(!projectPathEmpty); + } + + void ImportDestinationComponent::updateImportDestination() + { + auto onGetSelectedObject = [this](const Waapi::Response<Waapi::ObjectResponse>& response) + { + if(response.result.path.isEmpty()) + return juce::AlertWindow::showMessageBoxAsync(juce::MessageBoxIconType::InfoIcon, "Import Destination", "No object is selected in Wwise. Please select one and try again."); + + importDestination = response.result.path; + importDestinationType = response.result.type; + }; + + waapiClient.getSelectedObjectAsync(onGetSelectedObject); + } + + void ImportDestinationComponent::valueTreePropertyChanged(juce::ValueTree& treeWhosePropertyHasChanged, const juce::Identifier& property) + { + triggerAsyncUpdate(); + } + + void ImportDestinationComponent::handleAsyncUpdate() + { + refreshComponent(); + } +} // namespace AK::WwiseTransfer diff --git a/src/shared/UI/ImportDestinationComponent.h b/src/shared/UI/ImportDestinationComponent.h @@ -0,0 +1,41 @@ +#pragma once + +#include "Core/WaapiClient.h" +#include "CustomDrawableButton.h" +#include "Model/Wwise.h" +#include "ValidatableTextEditor.h" + +#include <juce_gui_basics/juce_gui_basics.h> + +namespace AK::WwiseTransfer +{ + class ImportDestinationComponent + : public juce::Component + , private juce::ValueTree::Listener + , private juce::AsyncUpdater + { + public: + ImportDestinationComponent(juce::ValueTree applicationState, WaapiClient& waapiClient); + ~ImportDestinationComponent(); + + private: + juce::ValueTree applicationState; + juce::CachedValue<juce::String> importDestination; + juce::CachedValue<juce::String> projectPath; + juce::CachedValue<Wwise::ObjectType> importDestinationType; + juce::Label importDestinationLabel; + ValidatableTextEditor importDestinationEditor; + + CustomDrawableButton updateImportDestinationButton; + + WaapiClient& waapiClient; + + void resized() override; + void refreshComponent(); + void updateImportDestination(); + void valueTreePropertyChanged(juce::ValueTree& treeWhosePropertyHasChanged, const juce::Identifier& property) override; + void handleAsyncUpdate() override; + + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(ImportDestinationComponent); + }; +} // namespace AK::WwiseTransfer diff --git a/src/shared/UI/ImportPreviewComponent.cpp b/src/shared/UI/ImportPreviewComponent.cpp @@ -0,0 +1,356 @@ +#include "ImportPreviewComponent.h" + +#include "Helpers/ImportHelper.h" +#include "Helpers/WwiseHelper.h" +#include "Model/IDs.h" + +#include <set> +#include <unordered_map> + +namespace AK::WwiseTransfer +{ + namespace ImportPreviewComponentConstants + { + constexpr int headerHeight = 24; + constexpr int columnInitialWidth = 10; + constexpr int columnMinimumWidth = 10; + constexpr int columnMaximumWidth = 1000; + const std::initializer_list<juce::String> tableHeaders{"Name", "Object Status", "Originals WAV", "WAV Status"}; + constexpr int defaultColumnPropertyFlags = juce::TableHeaderComponent::ColumnPropertyFlags::visible | juce::TableHeaderComponent::ColumnPropertyFlags::resizable | juce::TableHeaderComponent::ColumnPropertyFlags::sortable; + constexpr int iconPadding = 2; + constexpr int disabledFlag = 128; + } // namespace ImportPreviewComponentConstants + + enum TreeValueItemColumn + { + Name = 1, + ObjectStatus, + OriginalsWav, + WavStatus + }; + + ImportPreviewComponent::ImportPreviewComponent(juce::ValueTree appState) + : applicationState(appState) + , previewItems(applicationState.getChildWithName(IDs::previewItems)) + , rootItem(header, previewItems) + , previewLoading(applicationState, IDs::previewLoading, nullptr) + { + using namespace ImportPreviewComponentConstants; + + auto featureSupport = appState.getChildWithName(IDs::featureSupport); + applyTemplateFeatureEnabled.referTo(featureSupport, IDs::applyTemplateFeatureEnabled, nullptr); + + treeView.setDefaultOpenness(true); + treeView.setRootItem(&rootItem); + treeView.setRootItemVisible(false); + + for(const auto& tableHeader : tableHeaders) + { + auto index = (&tableHeader - tableHeaders.begin()); + header.addColumn(tableHeader, index + 1, columnInitialWidth, columnMinimumWidth, columnMaximumWidth, defaultColumnPropertyFlags); + } + + header.setStretchToFitActive(true); + + applicationState.addListener(this); + + emptyState.setText("Current Render settings will not result in any rendered files.", juce::dontSendNotification); + emptyState.setJustificationType(juce::Justification::centred); + + addAndMakeVisible(header); + addAndMakeVisible(treeView); + addChildComponent(loadingComponent); + + refreshHeader(); + + addChildComponent(emptyState); + } + + ImportPreviewComponent::~ImportPreviewComponent() + { + applicationState.removeListener(this); + } + + void ImportPreviewComponent::resized() + { + auto area = getLocalBounds(); + + header.setBounds(area.removeFromTop(ImportPreviewComponentConstants::headerHeight)); + header.resizeAllColumnsToFit(area.getWidth()); + + treeView.setBounds(area); + + loadingComponent.setBounds(area); + + emptyState.setBounds(area); + } + + void ImportPreviewComponent::valueTreePropertyChanged(juce::ValueTree& treeWhosePropertyHasChanged, + const juce::Identifier& property) + { + if(property == IDs::previewLoading) + { + triggerAsyncUpdate(); + } + + if(treeWhosePropertyHasChanged.getType() == IDs::featureSupport && property == IDs::applyTemplateFeatureEnabled) + { + refreshHeader(); + } + } + + void ImportPreviewComponent::valueTreeChildAdded(juce::ValueTree& parentTree, juce::ValueTree& childWhichHasBeenAdded) + { + if(parentTree.getType() == IDs::previewItems) + { + triggerAsyncUpdate(); + } + } + + void ImportPreviewComponent::valueTreeChildRemoved(juce::ValueTree& parentTree, juce::ValueTree& childWhichHasBeenRemoved, int indexFromWhichChildWasRemoved) + { + if(parentTree.getType() == IDs::previewItems) + { + triggerAsyncUpdate(); + } + } + + void ImportPreviewComponent::handleAsyncUpdate() + { + loadingComponent.setVisible(previewLoading); + emptyState.setVisible(previewItems.getNumChildren() == 0 && !previewLoading); + } + + void ImportPreviewComponent::refreshHeader() + { + using namespace ImportPreviewComponentConstants; + + // For some reason, the column width measurement only works properly if the following attribute is set to false + header.setStretchToFitActive(false); + + auto currentWidth = header.getColumnWidth(tableHeaders.size()); + auto propertyFlags = defaultColumnPropertyFlags; + + if(!applyTemplateFeatureEnabled.get()) + propertyFlags |= disabledFlag; + + header.removeColumn(tableHeaders.size()); + header.addColumn(*(tableHeaders.end() - 1), tableHeaders.size(), currentWidth, columnMinimumWidth, columnMaximumWidth, propertyFlags); + + header.setStretchToFitActive(true); + } + + ValueTreeItem::ValueTreeItem(juce::TableHeaderComponent& header, juce::ValueTree t) + : header(header) + , tree(t) + { + tree.addListener(this); + header.addListener(this); + } + + ValueTreeItem::~ValueTreeItem() + { + tree.removeListener(this); + header.removeListener(this); + } + + bool ValueTreeItem::mightContainSubItems() + { + return tree.getNumChildren() > 0; + } + + void ValueTreeItem::itemOpennessChanged(bool isNowOpen) + { + if(isNowOpen && getNumSubItems() == 0) + { + refreshSubItems(); + } + else + { + // TODO: there may be a performance benefit to call clear subitems. The issue with calling clearSubItems() + // here is that it loses the "openness" state of the tree. + // clearSubItems(); + } + } + + void ValueTreeItem::refreshSubItems() + { + clearSubItems(); + + auto isSorted = header.getSortColumnId() > 0; + + if(isSorted) + { + auto comparator = Comparator(header); + + for(int i = 0; i < tree.getNumChildren(); ++i) + { + addSubItemSorted(comparator, new ValueTreeItem(header, tree.getChild(i))); + } + } + else + { + for(int i = 0; i < tree.getNumChildren(); ++i) + { + addSubItem(new ValueTreeItem(header, tree.getChild(i))); + } + } + } + + void ValueTreeItem::valueTreePropertyChanged(juce::ValueTree&, const juce::Identifier&) + { + repaintItem(); + } + + void ValueTreeItem::valueTreeChildAdded(juce::ValueTree& parentTree, juce::ValueTree&) + { + treeChildrenChanged(parentTree); + } + + void ValueTreeItem::valueTreeChildRemoved(juce::ValueTree& parentTree, juce::ValueTree&, int) + { + treeChildrenChanged(parentTree); + } + + void ValueTreeItem::valueTreeChildOrderChanged(juce::ValueTree& parentTree, int, int) + { + treeChildrenChanged(parentTree); + } + + void ValueTreeItem::valueTreeParentChanged(juce::ValueTree&) + { + } + + void ValueTreeItem::treeChildrenChanged(const juce::ValueTree& parentTree) + { + if(parentTree == tree) + { + refreshSubItems(); + treeHasChanged(); + } + } + + void ValueTreeItem::paintItem(juce::Graphics& g, int width, int height) + { + using namespace ImportPreviewComponentConstants; + + auto previewItem = ImportHelper::valueTreeToPreviewItem(tree); + + std::array<juce::String, 4> cellText{ + previewItem.name, + ImportHelper::objectStatusToReadableString(previewItem.objectStatus), + previewItem.audioFilePath, + ImportHelper::wavStatusToReadableString(previewItem.wavStatus), + }; + + jassert(cellText.size() == header.getNumColumns(true)); + + auto* customLookAndFeel = dynamic_cast<CustomLookAndFeel*>(&getOwnerView()->getLookAndFeel()); + g.setColour(customLookAndFeel->getTextColourForObjectStatus(previewItem.objectStatus)); + + // First column is special since it has indentation + icon + auto indent = getItemPosition(true).getX(); + int iconSize = height; + int trueColumnWidth = header.getColumnWidth(1) - indent; + int textWidth = trueColumnWidth - iconSize; + + auto icon = customLookAndFeel->getIconForObjectType(previewItem.type); + + g.setFont(CustomLookAndFeelConstants::smallFontSize); + + if(trueColumnWidth > 0) + { + icon->drawWithin(g, juce::Rectangle<float>(iconSize, iconSize).reduced(iconPadding, iconPadding), juce::RectanglePlacement::centred, 1); + + if(textWidth > 0) + { + g.drawText(cellText[0], + iconSize, 0, textWidth, height, + juce::Justification::centredLeft, true); + } + } + + auto xPosition = trueColumnWidth; + + // The rest of the cells are just text, so no special text coordinates to calculate + for(int i = 1; i < cellText.size(); ++i) + { + auto columnWidth = header.getColumnWidth(i + 1); + + g.drawText(cellText[i], + xPosition, 0, columnWidth, height, + juce::Justification::centredLeft, true); + + xPosition += columnWidth; + } + } + + void ValueTreeItem::tableColumnsChanged(juce::TableHeaderComponent* tableHeader) + { + } + + void ValueTreeItem::tableColumnsResized(juce::TableHeaderComponent* tableHeader) + { + repaintItem(); + } + + void ValueTreeItem::tableSortOrderChanged(juce::TableHeaderComponent* tableHeader) + { + if(isOpen()) + { + auto comparator = Comparator(header); + + sortSubItems(comparator); + treeHasChanged(); + } + } + + juce::String ValueTreeItem::getUniqueName() const + { + return tree.getType().toString(); + } + + juce::String ValueTreeItem::getComparisonTextForColumn(int column) + { + auto previewItem = ImportHelper::valueTreeToPreviewItem(tree); + + switch(column) + { + case TreeValueItemColumn::Name: + return getUniqueName(); + case TreeValueItemColumn::ObjectStatus: + return ImportHelper::objectStatusToReadableString(previewItem.objectStatus); + case TreeValueItemColumn::OriginalsWav: + return previewItem.audioFilePath; + case TreeValueItemColumn::WavStatus: + // TODO: Return the wav status as string eventually + return juce::String(); + default: + return juce::String(); + } + } + + ValueTreeItem::Comparator::Comparator(const juce::TableHeaderComponent& header) + : sortColumnId(header.getSortColumnId() == 0 ? 1 : header.getSortColumnId()) + , sortDirectionForward(header.getSortColumnId() == 0 ? true : header.isSortedForwards()) + { + } + + int ValueTreeItem::Comparator::compareElements(juce::TreeViewItem* first, juce::TreeViewItem* second) + { + auto firstAsValueTreeItem = dynamic_cast<ValueTreeItem*>(first); + auto secondAsValueTreeItem = dynamic_cast<ValueTreeItem*>(second); + + if(firstAsValueTreeItem && secondAsValueTreeItem) + { + auto firstTextValue = firstAsValueTreeItem->getComparisonTextForColumn(sortColumnId); + auto secondTextValue = secondAsValueTreeItem->getComparisonTextForColumn(sortColumnId); + + auto compareVal = firstTextValue.compareNatural(secondTextValue); + + return sortDirectionForward ? compareVal : -1 * compareVal; + } + + return 0; + } +} // namespace AK::WwiseTransfer diff --git a/src/shared/UI/ImportPreviewComponent.h b/src/shared/UI/ImportPreviewComponent.h @@ -0,0 +1,92 @@ +#pragma once + +#include "BinaryData.h" +#include "Core/DawContext.h" +#include "Helpers/ImportHelper.h" +#include "LoadingComponent.h" +#include "Theme/CustomLookAndFeel.h" + +#include <juce_gui_basics/juce_gui_basics.h> +#include <unordered_map> + +namespace AK::WwiseTransfer +{ + struct ValueTreeItem + : public juce::TreeViewItem + , public juce::ValueTree::Listener + , public juce::TableHeaderComponent::Listener + { + struct Comparator + { + Comparator(const juce::TableHeaderComponent& header); + + int compareElements(juce::TreeViewItem* first, juce::TreeViewItem* second); + + private: + const int sortColumnId; + const bool sortDirectionForward; + }; + + ValueTreeItem(juce::TableHeaderComponent& header, juce::ValueTree tree); + ~ValueTreeItem(); + + bool mightContainSubItems() override; + void itemOpennessChanged(bool isNowOpen) override; + juce::String getUniqueName() const override; + juce::String getComparisonTextForColumn(int column); + + private: + juce::TableHeaderComponent& header; + juce::ValueTree tree; + + void refreshSubItems(); + void valueTreePropertyChanged(juce::ValueTree&, const juce::Identifier&) override; + void valueTreeChildAdded(juce::ValueTree& parentTree, juce::ValueTree&) override; + void valueTreeChildRemoved(juce::ValueTree& parentTree, juce::ValueTree&, int) override; + void valueTreeChildOrderChanged(juce::ValueTree& parentTree, int, int) override; + void valueTreeParentChanged(juce::ValueTree&) override; + void treeChildrenChanged(const juce::ValueTree& parentTree); + void paintItem(juce::Graphics& g, int width, int height) override; + void tableColumnsChanged(juce::TableHeaderComponent* tableHeader) override; + void tableColumnsResized(juce::TableHeaderComponent* tableHeader) override; + void tableSortOrderChanged(juce::TableHeaderComponent* tableHeader) override; + + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(ValueTreeItem) + }; + + class ImportPreviewComponent + : public juce::Component + , public juce::ValueTree::Listener + , public juce::AsyncUpdater + { + public: + ImportPreviewComponent(juce::ValueTree appState); + ~ImportPreviewComponent(); + + void resized() override; + + private: + juce::ValueTree applicationState; + juce::ValueTree previewItems; + juce::TableHeaderComponent header; + juce::TreeView treeView; + ValueTreeItem rootItem; + + juce::CachedValue<bool> previewLoading; + juce::CachedValue<bool> applyTemplateFeatureEnabled; + + LoadingComponent loadingComponent; + + juce::Label emptyState; + + void valueTreePropertyChanged(juce::ValueTree& treeWhosePropertyHasChanged, const juce::Identifier& property) override; + void valueTreeChildAdded(juce::ValueTree& parentTree, juce::ValueTree& childWhichHasBeenAdded); + void valueTreeChildRemoved(juce::ValueTree& parentTree, juce::ValueTree& childWhichHasBeenRemoved, int indexFromWhichChildWasRemoved); + + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(ImportPreviewComponent) + + // Inherited via AsyncUpdater + void handleAsyncUpdate() override; + void refreshHeader(); + }; +} // namespace AK::WwiseTransfer diff --git a/src/shared/UI/LoadingComponent.cpp b/src/shared/UI/LoadingComponent.cpp @@ -0,0 +1,47 @@ +#include "LoadingComponent.h" + +namespace AK::WwiseTransfer +{ + namespace LoadingComponentConstants + { + constexpr int loaderSize = 25; + constexpr int textHeight = 24; + constexpr float backgroundOpacity = 0.8f; + } // namespace LoadingComponentConstants + + LoadingComponent::LoadingComponent() + : progressBar(progress) + { + text.setText("Loading preview ...", juce::dontSendNotification); + text.setJustificationType(juce::Justification::centred); + + addAndMakeVisible(progressBar); + addAndMakeVisible(text); + } + + void LoadingComponent::resized() + { + using namespace LoadingComponentConstants; + + auto area = getLocalBounds(); + + juce::FlexBox fb; + fb.flexDirection = juce::FlexBox::Direction::column; + fb.alignItems = juce::FlexBox::AlignItems::center; + fb.justifyContent = juce::FlexBox::JustifyContent::center; + + fb.items.add(juce::FlexItem(progressBar).withWidth(loaderSize).withHeight(loaderSize)); + fb.items.add(juce::FlexItem(text).withWidth(area.getWidth()).withHeight(textHeight)); + + fb.performLayout(area); + } + + void LoadingComponent::paint(juce::Graphics& g) + { + auto color = getLookAndFeel() + .findColour(juce::ResizableWindow::ColourIds::backgroundColourId) + .withAlpha(LoadingComponentConstants::backgroundOpacity); + + g.fillAll(color); + } +} // namespace AK::WwiseTransfer diff --git a/src/shared/UI/LoadingComponent.h b/src/shared/UI/LoadingComponent.h @@ -0,0 +1,22 @@ +#pragma once + +#include <juce_gui_basics/juce_gui_basics.h> + +namespace AK::WwiseTransfer +{ + class LoadingComponent : public juce::Component + { + public: + LoadingComponent(); + + void resized() override; + void paint(juce::Graphics& g) override; + + private: + juce::ProgressBar progressBar; + juce::Label text; + + double progress = -1; + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(LoadingComponent) + }; +} // namespace AK::WwiseTransfer diff --git a/src/shared/UI/MainComponent.cpp b/src/shared/UI/MainComponent.cpp @@ -0,0 +1,145 @@ +#include "MainComponent.h" + +#include "Persistance/ApplicationState.h" + +namespace AK::WwiseTransfer +{ + namespace MainComponentConstants + { + constexpr int margin = 10; + constexpr int originalsSubfolderComponentHeight = 62; + constexpr int importDestinationComponentHeight = 26; + constexpr int importComponentHeight = 292; + constexpr int importConflictsComponentHeight = 62; + constexpr int importControlsComponentHeight = 24; + constexpr int ouputLogComponentHeight = 50; + constexpr int mainComponentWidth = 600; + constexpr int mainComponentHeight = 600; + constexpr int connectionMonitorDelayDefault = 200; + constexpr int minConnectionRetryDelayDefault = 200; + constexpr int maxConnectionRetryDelayDefault = 1000; + constexpr int splitterHeight = 8; + } // namespace MainComponentConstants + + MainComponent::MainComponent(DawContext& dawContext, const juce::String& applicationName) + : applicationState(ApplicationState::create()) + , validator(applicationState) + , applicationProperties(applicationName) + , waapiClientWatcher(applicationState, waapiClient, WaapiClientWatcherConfig{applicationProperties.getWaapiIp(), applicationProperties.getWaapiPort(), MainComponentConstants::connectionMonitorDelayDefault, MainComponentConstants::minConnectionRetryDelayDefault, MainComponentConstants::maxConnectionRetryDelayDefault}) + , originalsSubfolderComponent(applicationState, applicationName) + , importDestinationComponent(applicationState, waapiClient) + , importComponent(applicationState, waapiClient, applicationProperties, applicationName) + , importPreviewComponent(applicationState) + , dawWatcher(applicationState, waapiClient, dawContext, applicationProperties.getPreviewRefreshInterval()) + , importConflictsComponent(applicationState) + , importControlsComponent(applicationState, waapiClient, dawContext, applicationProperties, applicationName) + , featureSupport(applicationState, waapiClient) + , persistanceSupport(applicationState, dawContext) + , wwiseProjectSupport(applicationState, waapiClient) + , collapsedUI(applicationState, IDs::collapsedUI, nullptr) + , logger(applicationName) + { + using namespace MainComponentConstants; + + if(hasScaleFactorOverride()) + juce::Desktop::getInstance().setGlobalScaleFactor(applicationProperties.getScaleFactorOverride()); + + setSize(mainComponentWidth, mainComponentHeight); + + juce::Logger::setCurrentLogger(&logger); + + splitter.getToggleStateValue().referTo(collapsedUI.getPropertyAsValue()); + + waapiClientWatcher.start(); + dawWatcher.start(); + + applicationState.addListener(this); + + addAndMakeVisible(originalsSubfolderComponent); + + addChildComponent(importDestinationComponent); + addChildComponent(importComponent); + addChildComponent(importConflictsComponent); + + addAndMakeVisible(importPreviewComponent); + addAndMakeVisible(importControlsComponent); + addAndMakeVisible(splitter); + + refreshComponent(false); + } + + MainComponent::~MainComponent() + { + waapiClientWatcher.stop(); + dawWatcher.stop(); + + applicationState.removeListener(this); + + juce::Logger::setCurrentLogger(nullptr); + } + + void MainComponent::resized() + { + using namespace MainComponentConstants; + + auto area = getLocalBounds(); + area.reduce(margin, margin); + + originalsSubfolderComponent.setBounds(area.removeFromTop(originalsSubfolderComponentHeight)); + + if(!collapsedUI) + { + area.removeFromTop(margin); + + importDestinationComponent.setBounds(area.removeFromTop(importDestinationComponentHeight)); + + area.removeFromTop(margin); + + importComponent.setBounds(area.removeFromTop(importComponentHeight)); + + area.removeFromTop(margin); + + importConflictsComponent.setBounds(area.removeFromTop(importConflictsComponentHeight)); + } + + area.removeFromTop(margin); + + splitter.setBounds(area.removeFromTop(splitterHeight)); + + area.removeFromTop(margin); + + importControlsComponent.setBounds(area.removeFromBottom(importControlsComponentHeight)); + + area.removeFromBottom(margin); + + importPreviewComponent.setBounds(area); + } + + void MainComponent::valueTreePropertyChanged(juce::ValueTree& treeWhosePropertyHasChanged, const juce::Identifier& property) + { + if(treeWhosePropertyHasChanged.getType() == IDs::application && property == IDs::collapsedUI) + { + triggerAsyncUpdate(); + } + } + + void MainComponent::handleAsyncUpdate() + { + refreshComponent(true); + } + + void MainComponent::refreshComponent(bool shouldResize) + { + importDestinationComponent.setVisible(!collapsedUI); + importComponent.setVisible(!collapsedUI); + importConflictsComponent.setVisible(!collapsedUI); + + if(shouldResize) + resized(); + } + + bool MainComponent::hasScaleFactorOverride() + { + return applicationProperties.getScaleFactorOverride() > 0.0; + } +} // namespace AK::WwiseTransfer diff --git a/src/shared/UI/MainComponent.h b/src/shared/UI/MainComponent.h @@ -0,0 +1,73 @@ +#pragma once + +#include "Core/DawContext.h" +#include "Core/DawWatcher.h" +#include "Core/Logger.h" +#include "Core/WaapiClient.h" +#include "ImportComponent.h" +#include "ImportConflictsComponent.h" +#include "ImportControlsComponent.h" +#include "ImportDestinationComponent.h" +#include "ImportPreviewComponent.h" +#include "OriginalsSubfolderComponent.h" +#include "OutputLogComponent.h" +#include "Persistance/ApplicationProperties.h" +#include "Persistance/ApplicationStateValidator.h" +#include "Persistance/FeatureSupport.h" +#include "Persistance/PersistanceSupport.h" +#include "Persistance/WwiseProjectSupport.h" +#include "Splitter.h" +#include "Theme/CustomLookAndFeel.h" + +#include <memory> + +namespace AK::WwiseTransfer +{ + class MainComponent + : public juce::Component + , juce::ValueTree::Listener + , juce::AsyncUpdater + { + public: + MainComponent(DawContext& dawContext, const juce::String& applicationName); + ~MainComponent(); + + void resized() override; + bool hasScaleFactorOverride(); + + private: + juce::ValueTree applicationState; + + ApplicationState::Validator validator; + ApplicationProperties applicationProperties; + WaapiClient waapiClient; + WaapiClientWatcher waapiClientWatcher; + Logger logger; + DawWatcher dawWatcher; + + FeatureSupport featureSupport; + PersistanceSupport persistanceSupport; + WwiseProjectSupport wwiseProjectSupport; + + OutputLogComponent outputLog; + OriginalsSubfolderComponent originalsSubfolderComponent; + ImportDestinationComponent importDestinationComponent; + ImportComponent importComponent; + ImportConflictsComponent importConflictsComponent; + ImportPreviewComponent importPreviewComponent; + ImportControlsComponent importControlsComponent; + + juce::TooltipWindow tooltipWindow; + + Splitter splitter; + + juce::CachedValue<bool> collapsedUI; + + void valueTreePropertyChanged(juce::ValueTree& treeWhosePropertyHasChanged, const juce::Identifier& property) override; + void handleAsyncUpdate() override; + + void refreshComponent(bool shouldResize); + + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(MainComponent) + }; +} // namespace AK::WwiseTransfer diff --git a/src/shared/UI/OriginalsSubfolderComponent.cpp b/src/shared/UI/OriginalsSubfolderComponent.cpp @@ -0,0 +1,173 @@ +#include "OriginalsSubfolderComponent.h" + +#include "BinaryData.h" +#include "Persistance/ApplicationState.h" + +namespace AK::WwiseTransfer +{ + namespace WwiseOriginalsComponentConstants + { + constexpr int margin = 10; + constexpr int spacing = 4; + constexpr int editorBoxHeight = 26; + constexpr int labelWidth = 120; + constexpr int wildcardsButtonWidth = 80; + constexpr int smallButtonWidth = 26; + } // namespace WwiseOriginalsComponentConstants + + OriginalsSubfolderComponent::OriginalsSubfolderComponent(juce::ValueTree appState, const juce::String& applicationName) + : applicationState(appState) + , projectPath(applicationState, IDs::projectPath, nullptr) + , originalsSubfolder(applicationState, IDs::originalsSubfolder, nullptr) + , fileBrowserButton("FileBrowserButton", juce::Drawable::createFromImageData(BinaryData::General_FolderWithTriangle_Normal_svg, BinaryData::General_FolderWithTriangle_Normal_svgSize)) + , aboutButton("AboutButton", juce::Drawable::createFromImageData(BinaryData::Dialog_Help_Active_png, BinaryData::Dialog_Help_Active_pngSize)) + , originalsFolder(applicationState, IDs::originalsFolder, nullptr) + , languageSubfolder(applicationState, IDs::languageSubfolder, nullptr) + , aboutComponent(applicationName) + { + projectPathLabel.setText("Project Path", juce::dontSendNotification); + projectPathLabel.setBorderSize(juce::BorderSize(0)); + projectPathLabel.setMinimumHorizontalScale(1.0f); + projectPathLabel.setJustificationType(juce::Justification::right); + + originalsSubfolderLabel.setText("Originals Subfolder", juce::dontSendNotification); + originalsSubfolderLabel.setBorderSize(juce::BorderSize(0)); + originalsSubfolderLabel.setMinimumHorizontalScale(1.0f); + originalsSubfolderLabel.setJustificationType(juce::Justification::right); + + projectPathEditor.setFont(CustomLookAndFeelConstants::smallFontSize); + projectPathEditor.getValueToTruncate().referTo(projectPath.getPropertyAsValue()); + projectPathEditor.setReadOnly(true); + projectPathEditor.setMouseClickGrabsKeyboardFocus(false); + + projectPathEditor.setMouseCursor(juce::MouseCursor::NormalCursor); + + originalsSubfolderEditor.setFont(CustomLookAndFeelConstants::smallFontSize); + originalsSubfolderEditor.getTextValue().referTo(originalsSubfolder.getPropertyAsValue()); + originalsSubfolderEditor.getValidationValue().referTo(applicationState.getPropertyAsValue(IDs::originalsSubfolderValid, nullptr)); + originalsSubfolderEditor.getErrorMessageValue().referTo(applicationState.getPropertyAsValue(IDs::originalsSubfolderErrorMessage, nullptr)); + + aboutButton.onClick = [this] + { + showAboutWindow(); + }; + + fileBrowserButton.setButtonText("^"); + fileBrowserButton.onClick = [this] + { + selectOriginalsSubfoler(); + }; + + wildcardSelector.onItemSelected = [this](const juce::String& wildcard) + { + onWildcardSelected(wildcard); + }; + + addAndMakeVisible(projectPathLabel); + addAndMakeVisible(projectPathEditor); + addAndMakeVisible(originalsSubfolderLabel); + addAndMakeVisible(originalsSubfolderEditor); + addAndMakeVisible(fileBrowserButton); + addAndMakeVisible(wildcardSelector); + addAndMakeVisible(aboutButton); + + refreshComponent(); + + applicationState.addListener(this); + } + + OriginalsSubfolderComponent::~OriginalsSubfolderComponent() + { + applicationState.removeListener(this); + } + + void OriginalsSubfolderComponent::resized() + { + using namespace WwiseOriginalsComponentConstants; + + auto area = getLocalBounds(); + + auto projectPathSection = area.removeFromTop(editorBoxHeight); + { + projectPathLabel.setBounds(projectPathSection.removeFromLeft(labelWidth)); + projectPathSection.removeFromLeft(margin); + + aboutButton.setBounds(projectPathSection.removeFromRight(smallButtonWidth)); + projectPathSection.removeFromRight(spacing); + + projectPathEditor.setBounds(projectPathSection); + } + + area.removeFromTop(margin); + + auto originalsSubfolderSection = area.removeFromTop(editorBoxHeight); + { + originalsSubfolderLabel.setBounds(originalsSubfolderSection.removeFromLeft(labelWidth)); + + wildcardSelector.setBounds(originalsSubfolderSection.removeFromRight(wildcardsButtonWidth)); + originalsSubfolderSection.removeFromRight(spacing); + + fileBrowserButton.setBounds(originalsSubfolderSection.removeFromRight(smallButtonWidth)); + originalsSubfolderSection.removeFromRight(spacing); + + originalsSubfolderSection.removeFromLeft(margin); + originalsSubfolderEditor.setBounds(originalsSubfolderSection); + } + } + + void OriginalsSubfolderComponent::refreshComponent() + { + auto projectPathEmpty = projectPath.get().isEmpty(); + auto originalsFolderEmpty = originalsFolder.get().isEmpty(); + + projectPathLabel.setEnabled(!projectPathEmpty); + + fileBrowserButton.setEnabled(!projectPathEmpty && !originalsFolderEmpty); + fileBrowserButton.setTooltip(originalsFolderEmpty ? "File browser is only available when connected to Wwise 2022+" : ""); + } + + void OriginalsSubfolderComponent::selectOriginalsSubfoler() + { + fileChooser = std::make_unique<juce::FileChooser>("Please select a subfolder relative to the Wwise originals folder...", juce::File(originalsFolder + languageSubfolder), "*"); + + auto folderChooserFlags = juce::FileBrowserComponent::openMode | juce::FileBrowserComponent::canSelectDirectories; + + fileChooser->launchAsync(folderChooserFlags, [this](const juce::FileChooser& chooser) + { + juce::File relativeFolder(chooser.getResult()); + + originalsSubfolder = relativeFolder.getRelativePathFrom(juce::File(originalsFolder + languageSubfolder)); + }); + } + + void OriginalsSubfolderComponent::onWildcardSelected(const juce::String& wildcard) + { + originalsSubfolder = originalsSubfolderEditor.getText() + wildcard; + } + + void OriginalsSubfolderComponent::valueTreePropertyChanged(juce::ValueTree& treeWhosePropertyHasChanged, const juce::Identifier& property) + { + auto treeType = treeWhosePropertyHasChanged.getType(); + + if(treeType == IDs::application && property == IDs::projectPath || treeType == IDs::application && property == IDs::originalsFolder) + { + triggerAsyncUpdate(); + } + } + + void OriginalsSubfolderComponent::handleAsyncUpdate() + { + refreshComponent(); + } + void OriginalsSubfolderComponent::showAboutWindow() + { + juce::DialogWindow::LaunchOptions options; + options.dialogTitle = "About ReaWwise"; + options.useNativeTitleBar = true; + options.resizable = false; + options.componentToCentreAround = this->getParentComponent()->getParentComponent(); + options.content = juce::OptionalScopedPointer<juce::Component>(&aboutComponent, false); + + options.launchAsync(); + } +} // namespace AK::WwiseTransfer diff --git a/src/shared/UI/OriginalsSubfolderComponent.h b/src/shared/UI/OriginalsSubfolderComponent.h @@ -0,0 +1,53 @@ +#pragma once + +#include "AboutComponent.h" +#include "CustomDrawableButton.h" +#include "TruncatableTextEditor.h" +#include "ValidatableTextEditor.h" +#include "WildcardSelector.h" + +#include <juce_gui_basics/juce_gui_basics.h> +#include <memory> + +namespace AK::WwiseTransfer +{ + class OriginalsSubfolderComponent + : public juce::Component + , private juce::ValueTree::Listener + , private juce::AsyncUpdater + { + public: + OriginalsSubfolderComponent(juce::ValueTree applicationState, const juce::String& applicationName); + ~OriginalsSubfolderComponent(); + + private: + juce::ValueTree applicationState; + juce::CachedValue<juce::String> projectPath; + juce::CachedValue<juce::String> originalsSubfolder; + juce::CachedValue<juce::String> originalsFolder; + juce::CachedValue<juce::String> languageSubfolder; + juce::Label projectPathLabel; + juce::Label originalsSubfolderLabel; + TruncatableTextEditor projectPathEditor; + ValidatableTextEditor originalsSubfolderEditor; + + CustomDrawableButton fileBrowserButton; + WildcardSelector wildcardSelector; + + std::unique_ptr<juce::FileChooser> fileChooser; + + CustomDrawableButton aboutButton; + AboutComponent aboutComponent; + + void resized() override; + void refreshComponent(); + void selectOriginalsSubfoler(); + void onWildcardSelected(const juce::String& wildcard); + void valueTreePropertyChanged(juce::ValueTree& treeWhosePropertyHasChanged, const juce::Identifier& property) override; + void handleAsyncUpdate() override; + + void showAboutWindow(); + + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(OriginalsSubfolderComponent) + }; +} // namespace AK::WwiseTransfer diff --git a/src/shared/UI/OutputLogComponent.cpp b/src/shared/UI/OutputLogComponent.cpp @@ -0,0 +1,25 @@ +#include "OutputLogComponent.h" + +namespace AK::WwiseTransfer +{ + OutputLogComponent::OutputLogComponent() + { + setReadOnly(true); + setMultiLine(true); + setScrollbarsShown(true); + insertTextAtCaret("Log Output:"); + } + + void OutputLogComponent::onLogMessage(const juce::String& logMessage) + { + juce::String textToInsert = "\n"; + textToInsert << logMessage; + + auto printMessageToTextBox = [this, textToInsert] + { + insertTextAtCaret(textToInsert); + }; + + juce::MessageManager::callAsync(printMessageToTextBox); + } +} // namespace AK::WwiseTransfer diff --git a/src/shared/UI/OutputLogComponent.h b/src/shared/UI/OutputLogComponent.h @@ -0,0 +1,22 @@ +#pragma once + +#include "Core/Logger.h" +#include "Core/WaapiClient.h" + +#include <juce_gui_basics/juce_gui_basics.h> + +namespace AK::WwiseTransfer +{ + class OutputLogComponent + : public juce::TextEditor + , public Logger::IListener + { + public: + OutputLogComponent(); + + void onLogMessage(const juce::String& logMessage); + + private: + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(OutputLogComponent); + }; +} // namespace AK::WwiseTransfer diff --git a/src/shared/UI/PresetMenuComponent.cpp b/src/shared/UI/PresetMenuComponent.cpp @@ -0,0 +1,124 @@ +#include "PresetMenuComponent.h" + +#include "BinaryData.h" +#include "Helpers/PersistanceHelper.h" +#include "Model/IDs.h" + +namespace AK::WwiseTransfer +{ + PresetMenuComponent::PresetMenuComponent(juce::ValueTree appState, ApplicationProperties& applicationProperties, const juce::String& applicationName) + : CustomDrawableButton("PresetMenuButton", juce::Drawable::createFromImageData(BinaryData::General_FolderWithTriangle_Normal_svg, BinaryData::General_FolderWithTriangle_Normal_svgSize)) + , hierarchyMapping(appState.getChildWithName(IDs::hierarchyMapping)) + , presetFolder(juce::File::getSpecialLocation(juce::File::SpecialLocationType::userApplicationDataDirectory).getChildFile(applicationName).getChildFile("Presets")) + , applicationProperties(applicationProperties) + { + if(!presetFolder.exists()) + presetFolder.createDirectory(); + + onClick = [this] + { + showMenu(); + }; + } + + void PresetMenuComponent::showMenu() + { + auto opts = juce::PopupMenu::Options() + .withTargetComponent(this); + + juce::PopupMenu presetMenu; + presetMenu.setLookAndFeel(&getLookAndFeel()); + + auto onSavePreset = [this] + { + savePreset(); + }; + + presetMenu.addItem("Save Preset...", onSavePreset); + + auto onLoadPreset = [this] + { + loadPresetWithFilePicker(); + }; + + presetMenu.addItem("Load Preset...", onLoadPreset); + + auto recentPresets = applicationProperties.getRecentHierarchyMappingPresets(); + + juce::PopupMenu recentMenu; + + for(const auto& recentPreset : recentPresets) + { + auto onRecentPresetSelected = [this, recentPreset = recentPreset] + { + loadPreset(recentPreset); + }; + + recentMenu.addItem(recentPreset, onRecentPresetSelected); + } + + recentMenu.addSeparator(); + + auto onClearRecentPresets = [this] + { + applicationProperties.clearRecentHierarchyMappingPresets(); + }; + + recentMenu.addItem("Clear Recent Presets", onClearRecentPresets); + + presetMenu.addSubMenu("Recent Preset", recentMenu, !recentPresets.isEmpty()); + + presetMenu.showMenuAsync(opts); + } + + void PresetMenuComponent::loadPresetWithFilePicker() + { + fileChooser = std::make_unique<juce::FileChooser>("Select preset...", presetFolder, "*.xml"); + + auto onFileChosen = [this](const juce::FileChooser& chooser) + { + auto presetFile = chooser.getResult(); + + if(presetFile.exists()) + loadPreset(presetFile); + }; + + fileChooser->launchAsync(juce::FileBrowserComponent::openMode, onFileChosen); + } + + void PresetMenuComponent::loadPreset(const juce::File& presetFile) + { + auto presetData = presetFile.loadFileAsString(); + auto hierarchyMappingTemp = PersistanceHelper::presetDataToHierarchyMapping(presetData); + + if(hierarchyMappingTemp.isValid()) + { + hierarchyMapping.copyPropertiesAndChildrenFrom(hierarchyMappingTemp, nullptr); + applicationProperties.addRecentHierarchyMappingPreset(presetFile.getFullPathName()); + } + else + { + juce::AlertWindow::showMessageBoxAsync(juce::MessageBoxIconType::InfoIcon, "Load Preset", "Unable to load preset! The preset file is corrupt."); + } + } + + void PresetMenuComponent::savePreset() + { + fileChooser = std::make_unique<juce::FileChooser>("Save preset...", presetFolder, "*.xml"); + + auto onFileChosen = [this](const juce::FileChooser& chooser) + { + auto presetData = PersistanceHelper::hierarchyMappingToPresetData(hierarchyMapping); + + auto file = chooser.getResult(); + + file.create(); + + file.replaceWithText(presetData); + + applicationProperties.addRecentHierarchyMappingPreset(file.getFullPathName()); + }; + + fileChooser->launchAsync(juce::FileBrowserComponent::saveMode, onFileChosen); + } +} // namespace AK::WwiseTransfer diff --git a/src/shared/UI/PresetMenuComponent.h b/src/shared/UI/PresetMenuComponent.h @@ -0,0 +1,31 @@ +#pragma once + +#include "CustomDrawableButton.h" +#include "Persistance/ApplicationProperties.h" + +#include <memory> + +namespace AK::WwiseTransfer +{ + class PresetMenuComponent + : public CustomDrawableButton + { + public: + PresetMenuComponent(juce::ValueTree appState, ApplicationProperties& applicationProperties, const juce::String& applicationName); + + private: + juce::File presetFolder; + std::unique_ptr<juce::FileChooser> fileChooser; + + juce::ValueTree hierarchyMapping; + + ApplicationProperties& applicationProperties; + + void showMenu(); + void loadPresetWithFilePicker(); + void loadPreset(const juce::File& filename); + void savePreset(); + + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(PresetMenuComponent) + }; +} // namespace AK::WwiseTransfer diff --git a/src/shared/UI/SelectedRowPropertiesComponent.cpp b/src/shared/UI/SelectedRowPropertiesComponent.cpp @@ -0,0 +1,333 @@ +#include "SelectedRowPropertiesComponent.h" + +#include "BinaryData.h" +#include "Helpers/ImportHelper.h" +#include "Helpers/WwiseHelper.h" +#include "Model/IDs.h" +#include "Model/Wwise.h" +#include "Theme/CustomLookAndFeel.h" + +namespace AK::WwiseTransfer +{ + namespace SelectedRowPropertiesComponentConstants + { + constexpr int margin = 10; + constexpr int spacing = 4; + constexpr int bottomMargin = 14; + constexpr int labelHeight = 26; + constexpr int labelWidth = 170; + constexpr int wildcardsButtonWidth = 100; + constexpr int syncButtonWidth = 36; + constexpr int propertyTemplateToggleButtonWidth = 22; + constexpr int lineThickness = 2; + constexpr std::initializer_list<Wwise::ObjectType> objectTypes{Wwise::ObjectType::ActorMixer, Wwise::ObjectType::AudioFileSource, Wwise::ObjectType::BlendContainer, + Wwise::ObjectType::PhysicalFolder, Wwise::ObjectType::RandomContainer, Wwise::ObjectType::SequenceContainer, Wwise::ObjectType::SoundSFX, + Wwise::ObjectType::SoundVoice, Wwise::ObjectType::SwitchContainer, Wwise::ObjectType::VirtualFolder, Wwise::ObjectType::WorkUnit}; + const juce::String pastePropertiesToolTip = "Paste properties are only available when connected to Wwise 2022+"; + } // namespace SelectedRowPropertiesComponentConstants + + SelectedRowPropertiesComponent::SelectedRowPropertiesComponent(juce::ValueTree appState, WaapiClient& waapiClient) + : applicationState(appState) + , hierarchyMapping(applicationState.getChildWithName(IDs::hierarchyMapping)) + , languages(applicationState.getChildWithName(IDs::languages)) + , selectedRow(hierarchyMapping, IDs::selectedRow, nullptr) + , emptyHierarchyMappingNode(ImportHelper::hierarchyMappingNodeToValueTree(Import::HierarchyMappingNode("", Wwise::ObjectType::Unknown))) + , waapiClient(waapiClient) + , propertyTemplatePathSyncButton("PropertyTemplatePathSyncButton", juce::Drawable::createFromImageData(BinaryData::General_GetFromWwise_Normal_svg, BinaryData::General_GetFromWwise_Normal_svgSize)) + { + using namespace SelectedRowPropertiesComponentConstants; + + // setText("Selected Row Properties"); + + setText("Selected Row Properties"); + + auto featureSupport = applicationState.getChildWithName(IDs::featureSupport); + applyTemplateFeatureEnabled.referTo(featureSupport, IDs::applyTemplateFeatureEnabled, nullptr); + + objectTypeLabel.setText("Object Type", juce::dontSendNotification); + objectTypeLabel.setBorderSize(juce::BorderSize(0)); + objectTypeLabel.setMinimumHorizontalScale(1.0f); + objectTypeLabel.setJustificationType(juce::Justification::right); + + objectNameLabel.setText("Object Name", juce::dontSendNotification); + objectNameLabel.setBorderSize(juce::BorderSize(0)); + objectNameLabel.setMinimumHorizontalScale(1.0f); + objectNameLabel.setJustificationType(juce::Justification::right); + + propertyTemplatePathLabel.setText("Use Property Template", juce::dontSendNotification); + propertyTemplatePathLabel.setBorderSize(juce::BorderSize(0)); + propertyTemplatePathLabel.setMinimumHorizontalScale(1.0f); + propertyTemplatePathLabel.setJustificationType(juce::Justification::right); + + propertyTemplatePathSyncButton.setTooltip("Sync with selected object in Wwise"); + + objectNameEditor.setFont(CustomLookAndFeelConstants::smallFontSize); + propertyTemplatePathEditor.setFont(CustomLookAndFeelConstants::smallFontSize); + + objectTypeComboBox.setTextWhenNothingSelected("Select Object Type"); + + for(auto& objectType : objectTypes) + objectTypeComboBox.addItem(WwiseHelper::objectTypeToReadableString(objectType), static_cast<int>(objectType)); + + objectLanguageComboBox.setTextWhenNothingSelected("Language"); + objectLanguageComboBox.setTextWhenNoChoicesAvailable("No Languages loaded"); + + addAndMakeVisible(objectTypeLabel); + addAndMakeVisible(objectNameLabel); + addAndMakeVisible(propertyTemplatePathLabel); + addAndMakeVisible(objectTypeComboBox); + addAndMakeVisible(objectNameEditor); + addAndMakeVisible(propertyTemplatePathEditor); + addAndMakeVisible(propertyTemplateToggleButton); + addAndMakeVisible(wildcardSelector); + addAndMakeVisible(propertyTemplatePathSyncButton); + addChildComponent(objectLanguageComboBox); + + refreshComponent(); + + objectTypeComboBox.onChange = [this] + { + objectType = static_cast<Wwise::ObjectType>(objectTypeComboBox.getSelectedId()); + }; + + wildcardSelector.onItemSelected = [this](const juce::String& wildcard) + { + objectName = objectName + wildcard; + }; + + propertyTemplatePathSyncButton.onClick = [this] + { + updatePropertyTemplatePath(); + }; + + objectLanguageComboBox.onChange = [this] + { + objectLanguage = objectLanguageComboBox.getText(); + }; + + applicationState.addListener(this); + } + + SelectedRowPropertiesComponent::~SelectedRowPropertiesComponent() + { + applicationState.removeListener(this); + } + + void SelectedRowPropertiesComponent::refreshComponent() + { + hierarchyMappingNode = selectedRow >= 0 ? hierarchyMapping.getChild(selectedRow) : emptyHierarchyMappingNode; + + objectName.referTo(hierarchyMappingNode, IDs::objectName, nullptr); + objectNameValid.referTo(hierarchyMappingNode, IDs::objectNameValid, nullptr); + objectNameErrorMessage.referTo(hierarchyMappingNode, IDs::objectNameErrorMessage, nullptr); + objectType.referTo(hierarchyMappingNode, IDs::objectType, nullptr); + + objectLanguage.referTo(hierarchyMappingNode, IDs::objectLanguage, nullptr); + propertyTemplatePath.referTo(hierarchyMappingNode, IDs::propertyTemplatePath, nullptr); + propertyTemplatePathEnabled.referTo(hierarchyMappingNode, IDs::propertyTemplatePathEnabled, nullptr); + propertyTemplatePathValid.referTo(hierarchyMappingNode, IDs::propertyTemplatePathValid, nullptr); + propertyTemplatePathType.referTo(hierarchyMappingNode, IDs::propertyTemplatePathType, nullptr); + + // Bind components that support cached value binding + objectNameEditor.getTextValue().referTo(objectName.getPropertyAsValue()); + objectNameEditor.getValidationValue().referTo(objectNameValid.getPropertyAsValue()); + objectNameEditor.getErrorMessageValue().referTo(objectNameErrorMessage.getPropertyAsValue()); + objectTypeComboBox.getSelectedIdAsValue().referTo(objectType.getPropertyAsValue()); + propertyTemplatePathEditor.getTextValue().referTo(propertyTemplatePath.getPropertyAsValue()); + propertyTemplatePathEditor.getValidationValue().referTo(propertyTemplatePathValid.getPropertyAsValue()); + propertyTemplatePathEditor.getErrorMessageValue().referTo(hierarchyMappingNode.getPropertyAsValue(IDs::propertyTemplatePathErrorMessage, nullptr)); + propertyTemplateToggleButton.getToggleStateValue().referTo(propertyTemplatePathEnabled.getPropertyAsValue()); + + updatePropertyTemplateSection(); + objectLanguageComboBox.setVisible(objectType == Wwise::ObjectType::SoundVoice); + objectLanguageComboBox.clear(); + + auto languageList = WwiseHelper::valueTreeToLanguages(languages); + for(int i = 0; i < languageList.size(); ++i) + { + objectLanguageComboBox.addItem(languageList[i], i + 1); + if(languageList[i] == objectLanguage) + objectLanguageComboBox.setSelectedId(i + 1); + } + + if(objectLanguage.get().isNotEmpty() && objectLanguageComboBox.getSelectedId() == 0) + objectLanguageComboBox.setText(objectLanguage.get()); + } + + void SelectedRowPropertiesComponent::updatePropertyTemplatePath() + { + // TODO: show loading state + auto onGetSelectedObject = [this](const Waapi::Response<Waapi::ObjectResponse>& response) + { + if(response.result.path.isEmpty()) + return juce::AlertWindow::showMessageBoxAsync(juce::MessageBoxIconType::InfoIcon, "Import Destination", "No object is selected in Wwise. Please select one and try again."); + + propertyTemplatePath = response.result.path; + propertyTemplatePathType = response.result.type; + + // TODO: end loading state + }; + + waapiClient.getSelectedObjectAsync(onGetSelectedObject); + } + + void SelectedRowPropertiesComponent::updatePropertyTemplateSection() + { + using namespace SelectedRowPropertiesComponentConstants; + + auto isEnabled = propertyTemplatePathEnabled && applyTemplateFeatureEnabled; + + propertyTemplatePathSyncButton.setEnabled(isEnabled); + propertyTemplatePathEditor.setEnabled(isEnabled); + propertyTemplatePathEditor.setAlpha(isEnabled ? 1 : 0.5f); + propertyTemplatePathEditor.setMouseCursor(isEnabled ? juce::MouseCursor::IBeamCursor : juce::MouseCursor::NormalCursor); + + // Not using isEnabled because these fields depend on propertyTemplatePathEnabled. + propertyTemplateToggleButton.setEnabled(applyTemplateFeatureEnabled); + propertyTemplatePathLabel.setEnabled(applyTemplateFeatureEnabled); + + propertyTemplatePathEditor.setTooltip(applyTemplateFeatureEnabled ? "" : pastePropertiesToolTip); + propertyTemplatePathSyncButton.setTooltip(applyTemplateFeatureEnabled ? "" : pastePropertiesToolTip); + propertyTemplateToggleButton.setTooltip(applyTemplateFeatureEnabled ? "" : pastePropertiesToolTip); + propertyTemplatePathLabel.setTooltip(applyTemplateFeatureEnabled ? "" : pastePropertiesToolTip); + } + + void SelectedRowPropertiesComponent::paint(juce::Graphics& g) + { + juce::Font f(CustomLookAndFeelConstants::regularFontSize); + + const float textH = f.getHeight(); + const float indent = 3.0f; + const float textEdgeGap = 4.0f; + auto constant = 5.0f; + + auto x = indent; + auto y = f.getAscent() - 3.0f; + auto w = juce::jmax(0.0f, (float)getWidth() - x * 2.0f); + auto h = juce::jmax(0.0f, (float)getHeight() - y - indent); + constant = juce::jmin(constant, w * 0.5f, h * 0.5f); + auto constant2 = 2.0f * constant; + + auto textW = getText().isEmpty() ? 0 + : juce::jlimit(0.0f, + juce::jmax(0.0f, w - constant2 - textEdgeGap * 2), + (float)f.getStringWidth(getText()) + textEdgeGap * 2.0f); + auto textX = constant + textEdgeGap; + + juce::Path p; + p.startNewSubPath(0, y); + p.lineTo(constant2, y); + + p.startNewSubPath(x + textX + textW, y); + p.lineTo(x + w, y); + + auto alpha = 1.0f; + + g.setColour(findColour(juce::GroupComponent::outlineColourId) + .withMultipliedAlpha(alpha)); + + g.strokePath(p, juce::PathStrokeType(2.0f)); + + g.setColour(findColour(juce::GroupComponent::textColourId) + .withMultipliedAlpha(alpha)); + + g.setFont(f); + + g.drawText(getText(), + juce::roundToInt(x + textX), 0, + juce::roundToInt(textW), + juce::roundToInt(textH), + juce::Justification::centred, true); + } + + void SelectedRowPropertiesComponent::resized() + { + using namespace SelectedRowPropertiesComponentConstants; + + auto area = getLocalBounds(); + area.removeFromTop(labelHeight); + + auto objectTypeArea = area.removeFromTop(labelHeight); + { + objectTypeLabel.setBounds(objectTypeArea.removeFromLeft(labelWidth)); + + objectLanguageComboBox.setBounds(objectTypeArea.removeFromRight(wildcardsButtonWidth)); + + objectTypeArea.removeFromRight(spacing); + + objectTypeArea.removeFromLeft(margin); + objectTypeComboBox.setBounds(objectTypeArea); + } + + area.removeFromTop(margin); + + auto objectNameArea = area.removeFromTop(labelHeight); + { + objectNameLabel.setBounds(objectNameArea.removeFromLeft(labelWidth)); + + wildcardSelector.setBounds(objectNameArea.removeFromRight(wildcardsButtonWidth)); + objectNameArea.removeFromRight(spacing); + + objectNameArea.removeFromLeft(margin); + objectNameEditor.setBounds(objectNameArea); + } + + area.removeFromTop(margin); + + auto propertyTemplatePathArea = area.removeFromTop(labelHeight); + { + propertyTemplateToggleButton.setBounds(propertyTemplatePathArea.removeFromLeft(propertyTemplateToggleButtonWidth)); + propertyTemplatePathLabel.setBounds(propertyTemplatePathArea.removeFromLeft(labelWidth - propertyTemplateToggleButtonWidth)); + + propertyTemplatePathArea.removeFromRight(wildcardsButtonWidth - syncButtonWidth); + propertyTemplatePathSyncButton.setBounds(propertyTemplatePathArea.removeFromRight(syncButtonWidth)); + propertyTemplatePathArea.removeFromRight(spacing); + + propertyTemplatePathArea.removeFromLeft(margin); + propertyTemplatePathEditor.setBounds(propertyTemplatePathArea); + } + } + + void SelectedRowPropertiesComponent::valueTreePropertyChanged(juce::ValueTree& treeWhosePropertyHasChanged, const juce::Identifier& property) + { + auto treeType = treeWhosePropertyHasChanged.getType(); + + if(treeType == IDs::hierarchyMapping && property == IDs::selectedRow || + treeType == IDs::hierarchyMappingNode && (property == IDs::objectType || property == IDs::propertyTemplatePathEnabled) || + treeType == IDs::featureSupport && property == IDs::applyTemplateFeatureEnabled) + { + triggerAsyncUpdate(); + } + } + + void SelectedRowPropertiesComponent::valueTreeChildAdded(juce::ValueTree& parentTree, juce::ValueTree& childWhichHasBeenAdded) + { + auto treeType = parentTree.getType(); + + if(treeType == IDs::hierarchyMapping || treeType == IDs::languages) + { + triggerAsyncUpdate(); + } + } + + void SelectedRowPropertiesComponent::valueTreeChildRemoved(juce::ValueTree& parentTree, juce::ValueTree& childWhichHasBeenRemoved, int indexFromWhichChildWasRemoved) + { + if(parentTree.getType() == IDs::hierarchyMapping) + { + triggerAsyncUpdate(); + } + } + + void SelectedRowPropertiesComponent::valueTreeChildOrderChanged(juce::ValueTree& parentTreeWhoseChildrenHaveMoved, int oldIndex, int newIndex) + { + if(parentTreeWhoseChildrenHaveMoved.getType() == IDs::hierarchyMapping) + { + triggerAsyncUpdate(); + } + } + + void SelectedRowPropertiesComponent::handleAsyncUpdate() + { + refreshComponent(); + } +} // namespace AK::WwiseTransfer diff --git a/src/shared/UI/SelectedRowPropertiesComponent.h b/src/shared/UI/SelectedRowPropertiesComponent.h @@ -0,0 +1,74 @@ +#pragma once + +#include "Core/WaapiClient.h" +#include "CustomDrawableButton.h" +#include "Model/Import.h" +#include "ValidatableTextEditor.h" +#include "WildcardSelector.h" + +#include <juce_gui_basics/juce_gui_basics.h> + +namespace AK::WwiseTransfer +{ + class SelectedRowPropertiesComponent + : public juce::GroupComponent + , public juce::ValueTree::Listener + , public juce::AsyncUpdater + { + public: + SelectedRowPropertiesComponent(juce::ValueTree appState, WaapiClient& waapiClient); + ~SelectedRowPropertiesComponent() override; + + void resized() override; + + private: + juce::Label objectTypeLabel; + juce::Label objectNameLabel; + juce::Label propertyTemplatePathLabel; + juce::ComboBox objectTypeComboBox; + ValidatableTextEditor objectNameEditor; + ValidatableTextEditor propertyTemplatePathEditor; + juce::ToggleButton propertyTemplateToggleButton; + WildcardSelector wildcardSelector; + CustomDrawableButton propertyTemplatePathSyncButton; + juce::ComboBox objectLanguageComboBox; + + juce::ValueTree applicationState; + + juce::ValueTree hierarchyMapping; + juce::CachedValue<int> selectedRow; + + juce::ValueTree hierarchyMappingNode; + juce::CachedValue<juce::String> objectName; + juce::CachedValue<bool> objectNameValid; + juce::CachedValue<juce::String> objectNameErrorMessage; + juce::CachedValue<Wwise::ObjectType> objectType; + juce::CachedValue<juce::String> propertyTemplatePath; + juce::CachedValue<Wwise::ObjectType> propertyTemplatePathType; + juce::CachedValue<bool> propertyTemplatePathEnabled; + juce::CachedValue<bool> propertyTemplatePathValid; + + juce::CachedValue<bool> applyTemplateFeatureEnabled; + + juce::ValueTree emptyHierarchyMappingNode; + + juce::ValueTree languages; + juce::CachedValue<juce::String> objectLanguage; + + WaapiClient& waapiClient; + + void valueTreePropertyChanged(juce::ValueTree& treeWhosePropertyHasChanged, const juce::Identifier& property) override; + void valueTreeChildAdded(juce::ValueTree& parentTree, juce::ValueTree& childWhichHasBeenAdded) override; + void valueTreeChildRemoved(juce::ValueTree& parentTree, juce::ValueTree& childWhichHasBeenRemoved, int indexFromWhichChildWasRemoved) override; + void valueTreeChildOrderChanged(juce::ValueTree& parentTreeWhoseChildrenHaveMoved, int oldIndex, int newIndex) override; + + void handleAsyncUpdate() override; + void refreshComponent(); + void updatePropertyTemplatePath(); + void updatePropertyTemplateSection(); + + void paint(juce::Graphics& g) override; + + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(SelectedRowPropertiesComponent); + }; +} // namespace AK::WwiseTransfer diff --git a/src/shared/UI/SimpleListBox.cpp b/src/shared/UI/SimpleListBox.cpp @@ -0,0 +1,66 @@ +#include "SimpleListBox.h" + +namespace AK::WwiseTransfer +{ + SimpleListBoxModel::SimpleListBoxModel(const std::vector<juce::String>& items) + : items(items) + , selectedRowValue(juce::var(0)) + { + } + + int SimpleListBoxModel::getNumRows() + { + return items.size(); + } + + void SimpleListBoxModel::paintListBoxItem(int rowNumber, juce::Graphics& g, int width, int height, bool rowIsSelected) + { + if(rowIsSelected) + g.fillAll(juce::LookAndFeel::getDefaultLookAndFeel().findColour(juce::TextEditor::highlightColourId)); + + g.setColour(juce::Colours::white); + g.setFont(height * 0.7f); + + if(rowNumber < items.size()) + { + g.drawText(items.at(rowNumber), 5, 0, width, height, + juce::Justification::centredLeft, true); + } + } + + void SimpleListBoxModel::listBoxItemClicked(int row, const juce::MouseEvent&) + { + selectedRowValue = row; + } + + juce::Value& SimpleListBoxModel::getSelectedRowValue() + { + return selectedRowValue; + } + + SimpleListBox::SimpleListBox(const std::vector<juce::String>& items) + : model(items) + { + model.getSelectedRowValue().addListener(this); + + setModel(&model); + } + + SimpleListBox::~SimpleListBox() + { + model.getSelectedRowValue().removeListener(this); + } + + juce::Value& SimpleListBox::getSelectedRowValue() + { + return model.getSelectedRowValue(); + } + + void SimpleListBox::valueChanged(juce::Value& value) + { + auto& selectedRowValue = model.getSelectedRowValue(); + + if(value.refersToSameSourceAs(selectedRowValue) && selectedRowValue != getSelectedRow()) + selectRow(selectedRowValue.getValue()); + } +} // namespace AK::WwiseTransfer diff --git a/src/shared/UI/SimpleListBox.h b/src/shared/UI/SimpleListBox.h @@ -0,0 +1,41 @@ +#pragma once + +#include <juce_gui_basics/juce_gui_basics.h> + +namespace AK::WwiseTransfer +{ + class SimpleListBoxModel + : public juce::ListBoxModel + { + public: + SimpleListBoxModel(const std::vector<juce::String>& items); + + int getNumRows() override; + void paintListBoxItem(int rowNumber, juce::Graphics& g, int width, int height, bool rowIsSelected) override; + void listBoxItemClicked(int row, const juce::MouseEvent&) override; + juce::Value& getSelectedRowValue(); + + private: + const std::vector<juce::String>& items; + juce::Value selectedRowValue; + + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(SimpleListBoxModel); + }; + + class SimpleListBox + : public juce::ListBox + , public juce::Value::Listener + { + public: + SimpleListBox(const std::vector<juce::String>& items); + ~SimpleListBox(); + + juce::Value& getSelectedRowValue(); + void valueChanged(juce::Value& value) override; + + private: + SimpleListBoxModel model; + + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(SimpleListBox); + }; +} // namespace AK::WwiseTransfer diff --git a/src/shared/UI/Splitter.cpp b/src/shared/UI/Splitter.cpp @@ -0,0 +1,33 @@ +#include "Splitter.h" + +namespace AK::WwiseTransfer +{ + namespace SplitterConstants + { + constexpr int padding = 2; + constexpr int lineHeight = 2; + constexpr int lineCenterOffset = 1; + } // namespace SplitterConstants + + void Splitter::paintButton(juce::Graphics& g, bool shouldDrawButtonAsHighlighted, bool shouldDrawButtonAsDown) + { + using namespace SplitterConstants; + + auto area = getLocalBounds(); + auto triangleArea = area.removeFromRight(area.getHeight()); + + g.setColour(getLookAndFeel().findColour(juce::GroupComponent::outlineColourId)); + + juce::Path path; + if(getToggleState()) + path.addTriangle(triangleArea.getCentre().withX(triangleArea.getX()).toFloat(), triangleArea.getTopRight().toFloat(), triangleArea.getBottomRight().toFloat()); + else + path.addTriangle(triangleArea.getBottomLeft().toFloat(), triangleArea.getCentre().withY(triangleArea.getY()).toFloat(), triangleArea.getBottomRight().toFloat()); + + g.fillPath(path); + + auto lineRect = juce::Rectangle(area.getX(), area.getCentreY() - lineCenterOffset, area.getWidth() - padding, lineHeight); + + g.fillRect(lineRect); + } +} // namespace AK::WwiseTransfer diff --git a/src/shared/UI/Splitter.h b/src/shared/UI/Splitter.h @@ -0,0 +1,17 @@ +#pragma once + +#include <juce_gui_basics/juce_gui_basics.h> + +namespace AK::WwiseTransfer +{ + class Splitter : public juce::ToggleButton + { + public: + Splitter() = default; + + void paintButton(juce::Graphics& g, bool shouldDrawButtonAsHighlighted, bool shouldDrawButtonAsDown) override; + + private: + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(Splitter); + }; +} // namespace AK::WwiseTransfer diff --git a/src/shared/UI/TruncatableTextEditor.cpp b/src/shared/UI/TruncatableTextEditor.cpp @@ -0,0 +1,60 @@ +#include "TruncatableTextEditor.h" + +namespace AK::WwiseTransfer +{ + TruncatableTextEditor::TruncatableTextEditor() + : valueToTruncate(juce::var("")) + { + valueToTruncate.addListener(this); + } + + TruncatableTextEditor::~TruncatableTextEditor() + { + valueToTruncate.removeListener(this); + } + + void TruncatableTextEditor::valueChanged(juce::Value& value) + { + resetText(); + } + + juce::Value& TruncatableTextEditor::getValueToTruncate() + { + return valueToTruncate; + }; + + void TruncatableTextEditor::resized() + { + juce::TextEditor::resized(); + + resetText(); + } + + juce::String TruncatableTextEditor::getTooltip() + { + return valueToTruncate.getValue(); + } + + void TruncatableTextEditor::resetText() + { + auto indent = getLeftIndent() * 4; + + juce::String text = valueToTruncate.getValue(); + + auto trueTextSpace = getWidth() - juce::Font().getStringWidth("...") - indent; + + if(text.isNotEmpty() && juce::Font().getStringWidth(text) > trueTextSpace) + { + auto midPoint = 0; + while(juce::Font().getStringWidth(text) > trueTextSpace) + { + midPoint = juce::roundFloatToInt(float(text.length()) / 2.0f); + text = text.substring(0, midPoint) + text.substring(midPoint + 1); + } + + text = text.substring(0, midPoint) + "..." + text.substring(midPoint); + } + + setText(text); + }; +} // namespace AK::WwiseTransfer diff --git a/src/shared/UI/TruncatableTextEditor.h b/src/shared/UI/TruncatableTextEditor.h @@ -0,0 +1,26 @@ +#pragma once + +#include <juce_gui_basics/juce_gui_basics.h> + +namespace AK::WwiseTransfer +{ + class TruncatableTextEditor + : public juce::TextEditor + , public juce::Value::Listener + { + public: + TruncatableTextEditor(); + ~TruncatableTextEditor(); + + void valueChanged(juce::Value& value) override; + juce::Value& getValueToTruncate(); + void resized() override; + juce::String getTooltip() override; + + private: + juce::Value valueToTruncate; + juce::String lastValue; + + void resetText(); + }; +} // namespace AK::WwiseTransfer diff --git a/src/shared/UI/ValidatableTextEditor.cpp b/src/shared/UI/ValidatableTextEditor.cpp @@ -0,0 +1,69 @@ +#include "ValidatableTextEditor.h" + +namespace AK::WwiseTransfer +{ + ValidatableTextEditor::ValidatableTextEditor(const juce::String& componentName) + : juce::TextEditor(componentName) + , validationValue(juce::var(true)) + , errorMessageValue(juce::var("")) + { + onEscapeKey = [this] + { + setText(valueOnFocusGained); + valueOnFocusGained = ""; + moveKeyboardFocusToSibling(true); + }; + + onReturnKey = [this] + { + moveKeyboardFocusToSibling(true); + }; + + validationValue.addListener(this); + } + + ValidatableTextEditor::~ValidatableTextEditor() + { + validationValue.removeListener(this); + } + + juce::String ValidatableTextEditor::getTooltip() + { + return errorMessageValue.getValue(); + } + + void ValidatableTextEditor::focusGained(juce::Component::FocusChangeType focusChangeType) + { + valueOnFocusGained = getText(); + + juce::TextEditor::focusGained(focusChangeType); + } + + void ValidatableTextEditor::valueChanged(juce::Value& value) + { + if(value.refersToSameSourceAs(validationValue)) + refreshComponent(validationValue.getValue()); + } + + juce::Value& ValidatableTextEditor::getValidationValue() + { + return validationValue; + } + + juce::Value& ValidatableTextEditor::getErrorMessageValue() + { + return errorMessageValue; + } + + void ValidatableTextEditor::refreshComponent(bool isValid) + { + auto outlineColour = juce::LookAndFeel::getDefaultLookAndFeel().findColour(juce::TextEditor::outlineColourId); + + if(!isValid) + { + outlineColour = juce::Colours::crimson; + } + + setColour(juce::TextEditor::outlineColourId, outlineColour); + } +} // namespace AK::WwiseTransfer diff --git a/src/shared/UI/ValidatableTextEditor.h b/src/shared/UI/ValidatableTextEditor.h @@ -0,0 +1,32 @@ +#pragma once + +#include <juce_gui_basics/juce_gui_basics.h> + +namespace AK::WwiseTransfer +{ + class ValidatableTextEditor + : public juce::TextEditor + , public juce::Value::Listener + { + public: + explicit ValidatableTextEditor(const juce::String& componentName = juce::String()); + ~ValidatableTextEditor(); + + void valueChanged(juce::Value& value) override; + juce::String getTooltip() override; + + void focusGained(juce::Component::FocusChangeType focusChangeType) override; + + juce::Value& getValidationValue(); + juce::Value& getErrorMessageValue(); + + private: + void refreshComponent(bool isValid); + juce::Value validationValue; + juce::Value errorMessageValue; + + juce::String valueOnFocusGained; + + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(ValidatableTextEditor); + }; +} // namespace AK::WwiseTransfer diff --git a/src/shared/UI/WildcardSelector.cpp b/src/shared/UI/WildcardSelector.cpp @@ -0,0 +1,70 @@ +#include "WildcardSelector.h" + +#include <unordered_map> +#include <vector> + +namespace AK::WwiseTransfer +{ + namespace WildcardSelectorConstants + { + const std::unordered_map<juce::String, std::vector<juce::String>> wildcards = + { + {"Project Settings", {"$project", "$title", "$author", "$track", "$trackslashes", + "$tracknumber", "$folders", "$folders[X]", "$parent", "$marker", + "$marker(name)", "$marker(name)[s]", "$region", "$region(name)", "$region(name)[s]", + "$regionnumber", "$tempo", "$timesignature", "$fx", "$fx[X]"}}, + {"Project Order", {"$filenumber", "$filenumber[N]", "$filecount", "$note", "$note[X]", + "$natural", "$namenumber", "$timelineorder", "$timelineorder[N]", "$timelineorder_track", + "$timelineorder_track[N]"}}, + {"Media Item Information", {"$item", "$itemnumber", "$itemnotes", "$takemarker"}}, + {"Position/Length", {"$start", "$end", "$length", "$startbeats", "$endbeats", + "$lengthbeats", "$starttc", "$endtc", "$startframes", "$endframes", + "$lengthframes", "$startsecods", "$endseconds", "$lengthseconds"}}, + {"Output Format", {"$format", "$samplerate", "$sampleratek", "$bitdepth"}}, + {"Date/Time", {"$date", "$datetime", "$year", "$year2", "$month" + "$monthname", + "$day", "$dayname", "$hour", "$hour12", + "$ampm", "$minute", "$second"}}, + {"Computer Information", {"$user", "$computer"}}}; + } + + WildcardSelector::WildcardSelector() + : juce::TextButton("Wildcards") + { + onClick = [this] + { + showWildcardMenu(); + }; + } + + void WildcardSelector::showWildcardMenu() + { + using namespace WildcardSelectorConstants; + + auto opts = juce::PopupMenu::Options() + .withTargetComponent(this); + + juce::PopupMenu wildcardsMenu; + wildcardsMenu.setLookAndFeel(&getLookAndFeel()); + + for(auto categoryIter = wildcards.begin(); categoryIter != wildcards.end(); ++categoryIter) + { + juce::PopupMenu subMenu; + + for(auto wildcardListIter = categoryIter->second.begin(); wildcardListIter != categoryIter->second.end(); ++wildcardListIter) + { + auto action = [this, selectedItem = *wildcardListIter] + { + if(onItemSelected) + onItemSelected(selectedItem); + }; + + subMenu.addItem(*wildcardListIter, action); + } + + wildcardsMenu.addSubMenu(categoryIter->first, subMenu); + } + + wildcardsMenu.showMenuAsync(opts); + } +} // namespace AK::WwiseTransfer diff --git a/src/shared/UI/WildcardSelector.h b/src/shared/UI/WildcardSelector.h @@ -0,0 +1,21 @@ +#pragma once + +#include <juce_gui_basics/juce_gui_basics.h> +#include <memory> + +namespace AK::WwiseTransfer +{ + class WildcardSelector + : public juce::TextButton + { + public: + WildcardSelector(); + + std::function<void(const juce::String&)> onItemSelected; + + private: + void showWildcardMenu(); + + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(WildcardSelector); + }; +} // namespace AK::WwiseTransfer diff --git a/src/standalone/CMakeLists.txt b/src/standalone/CMakeLists.txt @@ -0,0 +1,25 @@ +include(Helpers) + +project(WwiseTransfer_Standalone) + +file(GLOB_RECURSE STANDALONE_SOURCES + "${PROJECT_SOURCE_DIR}/*.h" + "${PROJECT_SOURCE_DIR}/*.cpp") + +add_executable(${PROJECT_NAME} WIN32 MACOSX_BUNDLE) + +target_sources(${PROJECT_NAME} PRIVATE ${STANDALONE_SOURCES}) + +target_link_libraries(${PROJECT_NAME} + PRIVATE + WwiseTransfer_Shared +) + +target_compile_definitions(${PROJECT_NAME} + PRIVATE + JUCE_APPLICATION_NAME_STRING="${PROJECT_NAME}" +) + +source_group("Source Files" FILES ${STANDALONE_SOURCES}) + +build_juce_source_groups() diff --git a/src/standalone/Standalone.cpp b/src/standalone/Standalone.cpp @@ -0,0 +1,34 @@ +#include "Standalone.h" + +#include "StandaloneWindow.h" + +namespace AK::WwiseTransfer +{ + const juce::String ReaperWwiseTransferStandalone::getApplicationName() + { + return JUCE_APPLICATION_NAME_STRING; + } + + const juce::String ReaperWwiseTransferStandalone::getApplicationVersion() + { + return JUCE_APPLICATION_VERSION_STRING; + } + + bool ReaperWwiseTransferStandalone::moreThanOneInstanceAllowed() + { + return false; + } + + void ReaperWwiseTransferStandalone::initialise(const juce::String& commandLine) + { + juce::ignoreUnused(commandLine); + mainWindow.reset(new StandaloneWindow()); + } + + void ReaperWwiseTransferStandalone::shutdown() + { + mainWindow.reset(); + } + + START_JUCE_APPLICATION(ReaperWwiseTransferStandalone) +} // namespace AK::WwiseTransfer diff --git a/src/standalone/Standalone.h b/src/standalone/Standalone.h @@ -0,0 +1,22 @@ +#pragma once + +#include <juce_gui_basics/juce_gui_basics.h> +#include <memory> + +namespace AK::WwiseTransfer +{ + class StandaloneWindow; + + class ReaperWwiseTransferStandalone : public juce::JUCEApplication + { + public: + const juce::String getApplicationName() override; + const juce::String getApplicationVersion() override; + bool moreThanOneInstanceAllowed() override; + void initialise(const juce::String& commandLine) override; + void shutdown() override; + + private: + std::unique_ptr<StandaloneWindow> mainWindow; + }; +} // namespace AK::WwiseTransfer diff --git a/src/standalone/StandaloneWindow.cpp b/src/standalone/StandaloneWindow.cpp @@ -0,0 +1,43 @@ +#include "StandaloneWindow.h" + +#include <limits> + +namespace AK::WwiseTransfer +{ + namespace StandaloneWindowConstants + { + constexpr int width = 600; + constexpr int height = 800; + constexpr int minWidth = 420; + constexpr int minHeight = 650; + } // namespace StandaloneWindowConstants + + StandaloneWindow::StandaloneWindow() + : juce::ResizableWindow(JUCE_APPLICATION_NAME_STRING, true) + { + using namespace StandaloneWindowConstants; + + juce::LookAndFeel::setDefaultLookAndFeel(&lookAndFeel); + + mainContentComponent.reset(new MainComponent(stubContext, JUCE_APPLICATION_NAME_STRING)); + + setContentNonOwned(mainContentComponent.get(), true); + centreWithSize(width, height); + setResizable(true, true); + setResizeLimits(minWidth, minHeight, (std::numeric_limits<int>::max)(), (std::numeric_limits<int>::max)()); + setVisible(true); + } + + int StandaloneWindow::getDesktopWindowStyleFlags() const + { + return juce::ComponentPeer::windowHasCloseButton | juce::ComponentPeer::windowHasTitleBar | + juce::ComponentPeer::windowIsResizable | juce::ComponentPeer::windowHasMinimiseButton | + juce::ComponentPeer::windowAppearsOnTaskbar | juce::ComponentPeer::windowHasMaximiseButton; + } + + void StandaloneWindow::userTriedToCloseWindow() + { + setVisible(false); + juce::JUCEApplication::getInstance()->systemRequestedQuit(); + } +} // namespace AK::WwiseTransfer diff --git a/src/standalone/StandaloneWindow.h b/src/standalone/StandaloneWindow.h @@ -0,0 +1,21 @@ +#pragma once + +#include "StubContext.h" +#include "UI/MainComponent.h" + +namespace AK::WwiseTransfer +{ + class StandaloneWindow : public juce::ResizableWindow + { + public: + StandaloneWindow(); + + int getDesktopWindowStyleFlags() const override; + void userTriedToCloseWindow() override; + + private: + std::unique_ptr<MainComponent> mainContentComponent; + CustomLookAndFeel lookAndFeel; + StubContext stubContext; + }; +} // namespace AK::WwiseTransfer diff --git a/src/standalone/StubContext.cpp b/src/standalone/StubContext.cpp diff --git a/src/standalone/StubContext.h b/src/standalone/StubContext.h @@ -0,0 +1,38 @@ +#pragma once + +#include "Core/DawContext.h" + +#include <vector> + +namespace AK::WwiseTransfer +{ + class StubContext + : public DawContext + { + public: + std::vector<Import::Item> getImportItems(Import::Options options) override + { + return std::vector<Import::Item>{Import::Item("test", Wwise::ObjectType::SoundSFX, "\\A\\B\\C", juce::String(), juce::String(), juce::String())}; + } + + void renderImportItems() override + { + } + + // Inherited via DawContext + juce::String getSessionName() override + { + return juce::String(); + }; + + bool saveState(juce::ValueTree applicationState) override + { + return true; + }; + + juce::ValueTree retrieveState() override + { + return juce::ValueTree(); + } + }; +} // namespace AK::WwiseTransfer diff --git a/src/test/CMakeLists.txt b/src/test/CMakeLists.txt @@ -0,0 +1,23 @@ +include(Helpers) + +project(WwiseTransfer_Test) + +file(GLOB_RECURSE TEST_SOURCES + "${PROJECT_SOURCE_DIR}/*.h" + "${PROJECT_SOURCE_DIR}/*.cpp") + +add_executable(${PROJECT_NAME}) + +target_sources(${PROJECT_NAME} PRIVATE ${TEST_SOURCES}) + +target_link_libraries(${PROJECT_NAME} + PRIVATE + WwiseTransfer_Shared + PUBLIC + Catch2WithMain + trompeloeil::trompeloeil +) + +source_group("Source Files" FILES ${TEST_SOURCES}) + +build_juce_source_groups() +\ No newline at end of file diff --git a/src/test/ImportHelperTest.cpp b/src/test/ImportHelperTest.cpp @@ -0,0 +1,216 @@ +#include "ImportHelperTest.h" + +namespace AK::WwiseTransfer::Test +{ + TEST_CASE("hierarchyMappingNodeToValueTree") + { + auto testValues = TestTreeHierarchyValues(); + auto hierarchyMappingNode = testValues.generateHierarchyMappingNode(); + + auto valueTree = ImportHelper::hierarchyMappingNodeToValueTree(hierarchyMappingNode); + testValueTreeEquality(valueTree, testValues); + } + + TEST_CASE("hierachyMappingNodeListToValueTree") + { + auto indexLimit = GENERATE(1, 3); + auto nodes = std::vector<Import::HierarchyMappingNode>(); + auto testValuesVector = std::vector<TestTreeHierarchyValues>(); + + for (int index = 0; index < indexLimit; index++) + { + auto testValues = TestTreeHierarchyValues(index); + testValuesVector.emplace_back(testValues); + auto hierarchyMappingNode = testValues.generateHierarchyMappingNode(); + nodes.emplace_back(hierarchyMappingNode); + } + + auto valueTrees = ImportHelper::hierachyMappingNodeListToValueTree(nodes); + + for (int index = 0; index < indexLimit; index++) + { + testValueTreeEquality(valueTrees.getChild(index), testValuesVector[index]); + } + } + + TEST_CASE("valueTreeToHiarchyMappingNode") + { + auto testValues = TestTreeHierarchyValues(); + auto valueTree = testValues.generateValueTree(); + + auto hierarchyMapping = ImportHelper::valueTreeToHiarchyMappingNode(valueTree); + testHierarchyMappingEquality(hierarchyMapping, testValues); + } + + TEST_CASE("valueTreeToPreviewItem") + { + auto testValues = TestTreePreviewItemValues(); + auto valueTree = testValues.generateValueTree(); + auto previewItem = ImportHelper::valueTreeToPreviewItem(valueTree); + + REQUIRE(previewItem.audioFilePath == testValues.audioFilePath); + REQUIRE(previewItem.name == testValues.objectName); + REQUIRE(previewItem.objectStatus == testValues.objectStatus); + REQUIRE(previewItem.type == testValues.objectType); + REQUIRE(previewItem.wavStatus == testValues.wavStatus); + } + + TEST_CASE("previewItemToValueTree") + { + auto testValues = TestTreePreviewItemValues(); + auto previewItem = testValues.generatePreviewItem(); + auto testPath = "\\test\\path"; + + auto valueTree = ImportHelper::previewItemToValueTree(testPath, previewItem); + + REQUIRE(valueTree.getType().toString() == testPath); + REQUIRE(valueTree.getProperty(IDs::objectName) == testValues.objectName); + REQUIRE(valueTree.getProperty(IDs::audioFilePath) == testValues.audioFilePath); + REQUIRE(valueTree.getProperty(IDs::objectType) == juce::VariantConverter<Wwise::ObjectType>::toVar(testValues.objectType)); + REQUIRE(valueTree.getProperty(IDs::objectStatus) == juce::VariantConverter<Import::ObjectStatus>::toVar(testValues.objectStatus)); + REQUIRE(valueTree.getProperty(IDs::wavStatus) == juce::VariantConverter<Import::WavStatus>::toVar(testValues.wavStatus)); + } + + TEST_CASE("valueTreeToHierarchyMappingNodeList") + { + auto indexLimit = GENERATE(1, 3); + auto valueTrees = juce::ValueTree("root"); + auto testValuesVector = std::vector<TestTreeHierarchyValues>(); + + for (int index = 0; index < indexLimit; index++) + { + auto testValues = TestTreeHierarchyValues(index); + testValuesVector.emplace_back(testValues); + auto valueTree = testValues.generateValueTree(); + valueTrees.appendChild(valueTree, nullptr); + } + + auto hierarchyList = ImportHelper::valueTreeToHierarchyMappingNodeList(valueTrees); + + for (int index = 0; index < indexLimit; index++) + { + testHierarchyMappingEquality(hierarchyList[index], testValuesVector[index]); + } + } + + TEST_CASE("hierarchyMappingToPath") + { + auto indexLimit = GENERATE(1, 3); + auto nodes = std::vector<Import::HierarchyMappingNode>(); + auto testValuesVector = std::vector<TestTreeHierarchyValues>(); + + for (int index = 0; index < indexLimit; index++) + { + auto testValues = TestTreeHierarchyValues(index); + testValuesVector.emplace_back(testValues); + auto hierarchyMappingNode = testValues.generateHierarchyMappingNode(); + nodes.emplace_back(hierarchyMappingNode); + } + + auto fullPath = ImportHelper::hierarchyMappingToPath(nodes); + + juce::StringArray pathList; + pathList.addTokens(fullPath, "\\", ""); + pathList.removeEmptyStrings(); + + for (int index = 0; index < pathList.size(); index++) + { + REQUIRE(pathList[index].contains(testValuesVector[index].objectName)); + REQUIRE(pathList[index].contains(WwiseHelper::objectTypeToReadableString(testValuesVector[index].objectType))); + } + } + + TEST_CASE("containerNameExistsOptionToString") + { + REQUIRE(ImportHelper::containerNameExistsOptionToString(Import::ContainerNameExistsOption::CreateNew) == "createNew"); + REQUIRE(ImportHelper::containerNameExistsOptionToString(Import::ContainerNameExistsOption::Replace) == "replaceExisting"); + REQUIRE(ImportHelper::containerNameExistsOptionToString(Import::ContainerNameExistsOption::UseExisting) == "useExisting"); + REQUIRE(ImportHelper::containerNameExistsOptionToString(Import::ContainerNameExistsOption::Unknown) == "notImplemented"); + } + + TEST_CASE("stringToContainerNameExistsOption") + { + REQUIRE(ImportHelper::stringToContainerNameExistsOption("createNew") == Import::ContainerNameExistsOption::CreateNew); + REQUIRE(ImportHelper::stringToContainerNameExistsOption("replace") == Import::ContainerNameExistsOption::Replace); + REQUIRE(ImportHelper::stringToContainerNameExistsOption("useExisting") == Import::ContainerNameExistsOption::UseExisting); + REQUIRE(ImportHelper::stringToContainerNameExistsOption("notImplemented") == Import::ContainerNameExistsOption::Unknown); + REQUIRE(ImportHelper::stringToContainerNameExistsOption("asdfasdf") == Import::ContainerNameExistsOption::Unknown); + } + + TEST_CASE("containerNameExistsOptionToReadableString") + { + REQUIRE(ImportHelper::containerNameExistsOptionToReadableString(Import::ContainerNameExistsOption::CreateNew) == "Create New"); + REQUIRE(ImportHelper::containerNameExistsOptionToReadableString(Import::ContainerNameExistsOption::Replace) == "Replace"); + REQUIRE(ImportHelper::containerNameExistsOptionToReadableString(Import::ContainerNameExistsOption::UseExisting) == "Use Existing"); + REQUIRE(ImportHelper::containerNameExistsOptionToReadableString(Import::ContainerNameExistsOption::Unknown) == "Not Implemented"); + } + + TEST_CASE("audioFilenameExistsOptionToReadableString") + { + REQUIRE(ImportHelper::audioFilenameExistsOptionToReadableString(Import::AudioFilenameExistsOption::Replace) == "Replace"); + REQUIRE(ImportHelper::audioFilenameExistsOptionToReadableString(Import::AudioFilenameExistsOption::UseExisting) == "Use Existing"); + } + + TEST_CASE("applyTemplateOptionToReadableString") + { + REQUIRE(ImportHelper::applyTemplateOptionToReadableString(Import::ApplyTemplateOption::Always) == "Always"); + REQUIRE(ImportHelper::applyTemplateOptionToReadableString(Import::ApplyTemplateOption::NewObjectCreationOnly) == "New Object Creation Only"); + } + + TEST_CASE("objectStatusToReadableString") + { + REQUIRE(ImportHelper::objectStatusToReadableString(Import::ObjectStatus::New) == "New"); + REQUIRE(ImportHelper::objectStatusToReadableString(Import::ObjectStatus::Replaced) == "Replaced"); + REQUIRE(ImportHelper::objectStatusToReadableString(Import::ObjectStatus::NewRenamed) == "New (Renamed)"); + REQUIRE(ImportHelper::objectStatusToReadableString(Import::ObjectStatus::NoChange) == "No Change"); + } + + TEST_CASE("wavStatusToReadableString") + { + REQUIRE(ImportHelper::wavStatusToReadableString(Import::WavStatus::New) == "New"); + REQUIRE(ImportHelper::wavStatusToReadableString(Import::WavStatus::Replaced) == "Replaced"); + REQUIRE(ImportHelper::wavStatusToReadableString(Import::WavStatus::Unknown) == ""); + } + + TEST_CASE("importItemsToHash") + { + + SECTION("Equality Check") + { + auto itemCount = GENERATE(0, 1, 3, 1000); + auto testItems = std::vector<Import::Item>(); + for (int index = 0; index < itemCount; index++) + { + auto testValue = TestImportItemValues(index); + auto testItem = testValue.generateImportItem(); + + testItems.emplace_back(testItem); + } + + REQUIRE(ImportHelper::importItemsToHash(testItems) == ImportHelper::importItemsToHash(testItems)); + } + SECTION("Difference Check") + { + auto evenIndex = GENERATE(2, 3, 2000, 2001); + auto testItems1 = std::vector<Import::Item>(); + auto testItems2 = std::vector<Import::Item>(); + + for (int index = 0; index < evenIndex; index++) + { + auto testValue = TestImportItemValues(index); + auto testItem = testValue.generateImportItem(); + + if (index % 2 == 0) + { + testItems1.emplace_back(testItem); + } + else + { + testItems2.emplace_back(testItem); + } + } + + REQUIRE(ImportHelper::importItemsToHash(testItems1) != ImportHelper::importItemsToHash(testItems2)); + } + } +} // namespace AK::WwiseTransfer::Test diff --git a/src/test/ImportHelperTest.h b/src/test/ImportHelperTest.h @@ -0,0 +1,186 @@ +#include "Helpers/ImportHelper.h" +#include "Model/Import.h" +#include "Model/IDs.h" + +#include <catch2/catch_all.hpp> +#include <catch2/catch_test_macros.hpp> +#include <juce_core/juce_core.h> + +namespace AK::WwiseTransfer::Test +{ + struct TestTreeHierarchyValues + { + juce::String objectName; + bool objectNameValid = true; + juce::String objectNameErrorMsg; + Wwise::ObjectType objectType; + bool typeValid; + juce::String typeErrorMsg; + juce::String propertyTemplatePath; + bool propertyTemplatePathEnabled; + bool propertyTemplatePathValid; + juce::String propertyTemplatePathErrorMsg; + juce::String language; + + TestTreeHierarchyValues(int index = 0) + { + juce::String strIndex(index); + + objectName = "TestName_" + strIndex; + objectNameValid = true; + objectNameErrorMsg = "Test Name Error Message " + strIndex; + objectType = Wwise::ObjectType::RandomContainer; + typeValid = true; + typeErrorMsg = "Test Type Error Message " + strIndex; + propertyTemplatePath = ""; + propertyTemplatePathEnabled = false; + propertyTemplatePathValid = true; + propertyTemplatePathErrorMsg = "Test Property Template Path Error Message " + strIndex; + language = "English"; + } + + inline Import::HierarchyMappingNode generateHierarchyMappingNode() const + { + auto hierarchyMappingNode = Import::HierarchyMappingNode( + objectName, + objectNameValid, + objectNameErrorMsg, + objectType, + typeValid, + typeErrorMsg, + propertyTemplatePath, + propertyTemplatePathEnabled, + propertyTemplatePathValid, + propertyTemplatePathErrorMsg, + language + ); + + return hierarchyMappingNode; + } + + inline juce::ValueTree generateValueTree() const + { + juce::ValueTree valueTree(IDs::hierarchyMappingNode); + valueTree.setProperty(IDs::objectName, objectName, nullptr); + valueTree.setProperty(IDs::objectNameValid, objectNameValid, nullptr); + valueTree.setProperty(IDs::objectNameErrorMessage, objectNameErrorMsg, nullptr); + valueTree.setProperty(IDs::objectType, juce::VariantConverter<Wwise::ObjectType>::toVar(objectType), nullptr); + valueTree.setProperty(IDs::objectTypeValid, typeValid, nullptr); + valueTree.setProperty(IDs::objectTypeErrorMessage, typeErrorMsg, nullptr); + valueTree.setProperty(IDs::propertyTemplatePath, propertyTemplatePath, nullptr); + valueTree.setProperty(IDs::propertyTemplatePathEnabled, propertyTemplatePathEnabled, nullptr); + valueTree.setProperty(IDs::propertyTemplatePathValid, propertyTemplatePathValid, nullptr); + valueTree.setProperty(IDs::propertyTemplatePathErrorMessage, propertyTemplatePathErrorMsg, nullptr); + valueTree.setProperty(IDs::objectLanguage, language, nullptr); + + return valueTree; + } + }; + + struct TestTreePreviewItemValues + { + juce::String objectName; + Wwise::ObjectType objectType; + juce::String audioFilePath; + Import::ObjectStatus objectStatus; + Import::WavStatus wavStatus; + + TestTreePreviewItemValues(int index = 0) + { + juce::String strIndex(index); + objectName = "TestName_" + strIndex; + objectType = Wwise::ObjectType::RandomContainer; + audioFilePath = "\\test\\audio\\file\\path"; + objectStatus = Import::ObjectStatus::New; + wavStatus = Import::WavStatus::New; + } + + inline juce::ValueTree generateValueTree() const + { + juce::ValueTree valueTree(IDs::hierarchyMappingNode); + + valueTree.setProperty(IDs::objectName, objectName, nullptr); + valueTree.setProperty(IDs::audioFilePath, audioFilePath, nullptr); + valueTree.setProperty(IDs::objectType, juce::VariantConverter<Wwise::ObjectType>::toVar(objectType), nullptr); + valueTree.setProperty(IDs::wavStatus, juce::VariantConverter<Import::WavStatus>::toVar(wavStatus), nullptr); + valueTree.setProperty(IDs::objectStatus, juce::VariantConverter<Import::ObjectStatus>::toVar(objectStatus), nullptr); + + return valueTree; + } + + inline Import::PreviewItem generatePreviewItem() const + { + return { + objectName, + objectType, + objectStatus, + audioFilePath, + wavStatus + }; + } + }; + + struct TestImportItemValues + { + juce::String name; + Wwise::ObjectType type; + juce::String path; + juce::String originalsSubFolder; + juce::String audioFilePath; + juce::String renderFilePath; + + TestImportItemValues(int index = 0) + { + juce::String strIndex(index); + name = "TestName_" + strIndex; + type = Wwise::ObjectType::PhysicalFolder; + path = "\\test\\item\\path_" + strIndex; + originalsSubFolder = "testFolder"; + audioFilePath = "\\test\\item\\audio\\path_" + strIndex; + renderFilePath = "\\test\\item\\render\\path_" + strIndex; + } + + inline Import::Item generateImportItem() const + { + return + { + name, + type, + path, + originalsSubFolder, + audioFilePath, + renderFilePath + }; + } + }; + + inline void testValueTreeEquality(const juce::ValueTree& valueTree, const TestTreeHierarchyValues& values) + { + REQUIRE(valueTree.getProperty(IDs::objectName) == values.objectName); + REQUIRE(valueTree.getProperty(IDs::objectNameValid).equals(values.objectNameValid)); + REQUIRE(valueTree.getProperty(IDs::objectNameErrorMessage) == values.objectNameErrorMsg); + REQUIRE(juce::VariantConverter<Wwise::ObjectType>::fromVar(valueTree.getProperty(IDs::objectType)) == values.objectType); + REQUIRE(valueTree.getProperty(IDs::objectTypeValid).equals(values.typeValid)); + REQUIRE(valueTree.getProperty(IDs::objectTypeErrorMessage) == values.typeErrorMsg); + REQUIRE(valueTree.getProperty(IDs::propertyTemplatePath) == values.propertyTemplatePath); + REQUIRE(valueTree.getProperty(IDs::propertyTemplatePathEnabled).equals(values.propertyTemplatePathEnabled)); + REQUIRE(valueTree.getProperty(IDs::propertyTemplatePathValid).equals(values.propertyTemplatePathValid)); + REQUIRE(valueTree.getProperty(IDs::propertyTemplatePathErrorMessage) == values.propertyTemplatePathErrorMsg); + REQUIRE(valueTree.getProperty(IDs::objectLanguage) == values.language); + } + + inline void testHierarchyMappingEquality(const Import::HierarchyMappingNode& node, const TestTreeHierarchyValues& values) + { + REQUIRE(node.name == values.objectName); + REQUIRE(node.nameValid == values.objectNameValid); + REQUIRE(node.nameErrorMessage == values.objectNameErrorMsg); + REQUIRE(node.type == values.objectType); + REQUIRE(node.typeValid == values.typeValid); + REQUIRE(node.typeErrorMessage == values.typeErrorMsg); + REQUIRE(node.propertyTemplatePath == values.propertyTemplatePath); + REQUIRE(node.propertyTemplatePathEnabled == values.propertyTemplatePathEnabled); + REQUIRE(node.propertyTemplatePathValid == values.propertyTemplatePathValid); + REQUIRE(node.propertyTemplatePathErrorMessage == values.propertyTemplatePathErrorMsg); + REQUIRE(node.language == values.language); + } +} // namespace AK::WwiseTransfer::Test diff --git a/src/test/Mock.cpp b/src/test/Mock.cpp @@ -0,0 +1,29 @@ +#include <catch2/catch_all.hpp> +#include <catch2/catch_test_macros.hpp> +#include <catch2/trompeloeil.hpp> +#include "Core/WaapiClient.h" + +namespace AK::WwiseTransfer::Test +{ + class MockWaapiClient : public AK::WwiseTransfer::WaapiClient + { + public: + MAKE_MOCK4(connect, bool(char*, unsigned int, AK::WwiseAuthoringAPI::disconnectHandler_t, int)); + }; + + TEST_CASE("connect example") + { + using trompeloeil::_; // wild card for matching any value + + MockWaapiClient client; + + REQUIRE_CALL(client, connect(_, 8080, nullptr, -1)) + .RETURN(true); + + ALLOW_CALL(client, connect(_, 8000, nullptr, -1)) + .RETURN(false); + + REQUIRE(client.connect("testurl", 8080, nullptr, -1)); + REQUIRE_FALSE(client.connect("testurl", 8000, nullptr, -1)); + } +} // AK::WwiseTransfer::Test diff --git a/src/test/PersistanceHelperTest.cpp b/src/test/PersistanceHelperTest.cpp @@ -0,0 +1,85 @@ +#include "PersistanceHelperTest.h" + + +namespace AK::WwiseTransfer::Test +{ + TEST_CASE("hierarchyMappingToPresetData") + { + auto childrenCount = 3; + + auto rootValueTree = juce::ValueTree(IDs::hierarchyMapping); + auto mappingNodeValuesVector = std::vector<TestHierarchyMappingNodeValues>(); + + for (int index = 1; index <= childrenCount; index++) + { + auto mappingNodeValues = TestHierarchyMappingNodeValues(index); + mappingNodeValuesVector.emplace_back(mappingNodeValues); + + auto childValueTree = mappingNodeValues.generateValueTree(); + rootValueTree.appendChild(childValueTree, nullptr); + } + + SECTION("Without Removed Properties") + { + auto presetData = PersistanceHelper::hierarchyMappingToPresetData(rootValueTree); + auto parsedData = juce::parseXML(presetData); + + for (int index = 0; index < childrenCount; index++) + { + auto childPreset = parsedData.get()->getChildElement(index); + testHierarchyMappingPresetDataEquality(*childPreset, mappingNodeValuesVector[index]); + } + } + + SECTION("With Removed Properties") + { + for (int index = 0; index < childrenCount; index++) + { + auto childTree = rootValueTree.getChild(index); + addPropertiesToRemove(childTree); + } + + auto presetData = PersistanceHelper::hierarchyMappingToPresetData(rootValueTree); + auto parsedData = juce::parseXML(presetData); + + for (int index = 0; index < childrenCount; index++) + { + auto childPreset = parsedData.get()->getChildElement(index); + testHierarchyMappingPresetDataEquality(*childPreset, mappingNodeValuesVector[index]); + testHierarchyMappingPresetRemovedProperties(*childPreset); + } + } + } + + TEST_CASE("hierarchyMappingToPresetData: Empty Value Tree") + { + auto valueTree = juce::ValueTree(); + auto presetData = PersistanceHelper::hierarchyMappingToPresetData(valueTree); + + REQUIRE(presetData.isEmpty()); + } + + TEST_CASE("presetDataToHierarchyMapping") + { + auto rootValueTree = juce::ValueTree(IDs::hierarchyMapping); + + auto childMappingValues = TestHierarchyMappingNodeValues(); + auto childValueTree = childMappingValues.generateValueTree(); + + rootValueTree.addChild(childValueTree, 0, nullptr); + auto rootPresetData = rootValueTree.toXmlString(); + auto valueTree = PersistanceHelper::presetDataToHierarchyMapping(rootPresetData); + + for (int index = 0; index < valueTree.getNumChildren(); index++) + { + testHierarchyMappingValueTreeEquality(valueTree.getChild(index), childMappingValues); + } + } + + TEST_CASE("presetDataToHierarchyMapping: Empty String") + { + auto hierarchyMapping = PersistanceHelper::presetDataToHierarchyMapping(""); + + REQUIRE_FALSE(hierarchyMapping.isValid()); + } +} // namespace AK::WwiseTransfer::Test +\ No newline at end of file diff --git a/src/test/PersistanceHelperTest.h b/src/test/PersistanceHelperTest.h @@ -0,0 +1,108 @@ +#include "Helpers/PersistanceHelper.h" +#include "Model/Import.h" +#include "Model/IDs.h" +#include <catch2/catch_all.hpp> +#include <catch2/catch_test_macros.hpp> +#include <juce_core/juce_core.h> +using namespace juce; + +namespace AK::WwiseTransfer::Test +{ + struct TestHierarchyMappingNodeValues + { + juce::String objectName; + bool objectNameValid = true; + juce::String objectNameErrorMsg; + Wwise::ObjectType objectType; + juce::String propertyTemplatePath; + bool propertyTemplatePathEnabled; + juce::String language; + juce::Identifier identifier; + + TestHierarchyMappingNodeValues(int index = 0) + { + juce::String strIndex(index); + + objectName = "TestName_" + strIndex; + objectNameValid = true; + objectNameErrorMsg = "Test Name Error Message " + strIndex; + objectType = Wwise::ObjectType::RandomContainer; + propertyTemplatePath = "test\\template\\path"; + propertyTemplatePathEnabled = false; + language = "English"; + identifier = IDs::hierarchyMappingNode; + } + + inline juce::ValueTree generateValueTree() const + { + juce::ValueTree valueTree(identifier); + valueTree.setProperty(IDs::objectName, objectName, nullptr); + valueTree.setProperty(IDs::objectNameValid, objectNameValid, nullptr); + valueTree.setProperty(IDs::objectNameErrorMessage, objectNameErrorMsg, nullptr); + valueTree.setProperty(IDs::objectType, juce::VariantConverter<Wwise::ObjectType>::toVar(objectType), nullptr); + valueTree.setProperty(IDs::propertyTemplatePath, propertyTemplatePath, nullptr); + valueTree.setProperty(IDs::propertyTemplatePathEnabled, propertyTemplatePathEnabled, nullptr); + valueTree.setProperty(IDs::objectLanguage, language, nullptr); + + return valueTree; + } + + inline juce::XmlElement generateXMLElement() const + { + auto xmlElement = juce::XmlElement(identifier); + xmlElement.setAttribute(IDs::objectName, objectName); + xmlElement.setAttribute(IDs::objectNameValid, objectNameValid); + xmlElement.setAttribute(IDs::objectNameErrorMessage, objectNameErrorMsg); + xmlElement.setAttribute(IDs::objectType, WwiseHelper::objectTypeToReadableString(objectType)); + xmlElement.setAttribute(IDs::propertyTemplatePath, propertyTemplatePath); + xmlElement.setAttribute(IDs::propertyTemplatePathEnabled, propertyTemplatePathEnabled); + xmlElement.setAttribute(IDs::objectLanguage, language); + + return xmlElement; + } + }; + + inline void addPropertiesToRemove(juce::ValueTree valueTree) + { + valueTree.setProperty(IDs::objectTypeValid, true, nullptr); + valueTree.setProperty(IDs::objectTypeErrorMessage, "Type Error Message", nullptr); + valueTree.setProperty(IDs::propertyTemplatePathValid, true, nullptr); + valueTree.setProperty(IDs::propertyTemplatePathErrorMessage, "Property Template Path Error Message", nullptr); + } + + inline void testHierarchyMappingPresetDataEquality(const juce::XmlElement& presetData, const TestHierarchyMappingNodeValues& values) + { + REQUIRE(presetData.getTagName() == values.identifier.toString()); + REQUIRE(presetData.getStringAttribute(IDs::objectName.toString()) == values.objectName); + REQUIRE(presetData.getStringAttribute(IDs::objectNameValid.toString()) == juce::String(static_cast<int>(values.objectNameValid))); + REQUIRE(presetData.getStringAttribute(IDs::objectNameErrorMessage.toString()) == values.objectNameErrorMsg); + REQUIRE(presetData.getStringAttribute(IDs::objectType.toString()) == juce::String(static_cast<int>(values.objectType))); + REQUIRE(presetData.getStringAttribute(IDs::propertyTemplatePath.toString()) == values.propertyTemplatePath); + REQUIRE(presetData.getStringAttribute(IDs::propertyTemplatePathEnabled.toString()) == juce::String(static_cast<int>(values.propertyTemplatePathEnabled))); + REQUIRE(presetData.getStringAttribute(IDs::objectLanguage.toString()) == values.language); + } + + inline void testHierarchyMappingPresetRemovedProperties(const juce::XmlElement& presetData) + { + REQUIRE(presetData.getStringAttribute(IDs::objectTypeValid.toString()).isEmpty()); + REQUIRE(presetData.getStringAttribute(IDs::objectTypeErrorMessage.toString()).isEmpty()); + REQUIRE(presetData.getStringAttribute(IDs::propertyTemplatePathValid.toString()).isEmpty()); + REQUIRE(presetData.getStringAttribute(IDs::propertyTemplatePathErrorMessage.toString()).isEmpty()); + } + + inline void testHierarchyMappingValueTreeEquality(juce::ValueTree valueTree, const TestHierarchyMappingNodeValues& values) + { + // PersistanceHelper::presetDataToHierarchyMapping sets hardcoded data to newly created valueTree + REQUIRE(valueTree.getProperty(IDs::objectName) == values.objectName); + REQUIRE(valueTree.getProperty(IDs::objectNameValid)); + REQUIRE(juce::VariantConverter<juce::String>::fromVar(valueTree.getProperty(IDs::objectNameErrorMessage)).isEmpty()); + REQUIRE(juce::VariantConverter<Wwise::ObjectType>::fromVar(valueTree.getProperty(IDs::objectType)) == values.objectType); + REQUIRE(valueTree.getProperty(IDs::objectTypeValid)); + REQUIRE(juce::VariantConverter<juce::String>::fromVar(valueTree.getProperty(IDs::objectTypeErrorMessage)).isEmpty()); + REQUIRE(valueTree.getProperty(IDs::propertyTemplatePath) == values.propertyTemplatePath); + REQUIRE(valueTree.getProperty(IDs::propertyTemplatePathEnabled).equals(values.propertyTemplatePathEnabled)); + REQUIRE(valueTree.getProperty(IDs::propertyTemplatePathValid)); + REQUIRE(juce::VariantConverter<juce::String>::fromVar(valueTree.getProperty(IDs::propertyTemplatePathErrorMessage)).isEmpty()); + REQUIRE(valueTree.getProperty(IDs::objectLanguage) == values.language); + } +} // namespace AK::WwiseTransfer::Test +\ No newline at end of file diff --git a/src/test/Test.cpp b/src/test/Test.cpp @@ -0,0 +1,153 @@ +#include "Helpers/WaapiHelper.h" +#include "Helpers/WwiseHelper.h" + +#include <catch2/catch_all.hpp> +#include <catch2/catch_test_macros.hpp> +#include <juce_core/juce_core.h> +#include <memory> + +namespace AK::WwiseTransfer +{ + class WaapiHelperTests + { + }; + + class WwiseHelperTests + { + }; + + class WwiseModelTests + { + }; + +#pragma region WaapiHelperTests + TEST_CASE_METHOD(WaapiHelperTests, "WaapiHelper::executeWithRetry: retries for max attempts when function returns false") + { + int counter = 0; + auto alwaysFails = [&counter] + { + counter++; + return false; + }; + + WaapiHelper::executeWithRetry(alwaysFails, 250, 5); + + REQUIRE(counter == 5); + } + + TEST_CASE_METHOD(WaapiHelperTests, "WaapiHelper::executeWithRetry: does not retry when function returns true") + { + int counter = 0; + auto alwaysSucceeds = [&counter] + { + counter++; + return true; + }; + + WaapiHelper::executeWithRetry(alwaysSucceeds, 250, 5); + + REQUIRE(counter == 1); + } + + TEST_CASE_METHOD(WaapiHelperTests, "WaapiHelper::executeWithRetry: stops retrying as soon as function returns true, on second try") + { + int counter = 0; + bool returnValue = true; + auto succeedsOnSecondTry = [&counter, &returnValue] + { + counter++; + returnValue = !returnValue; + return returnValue; + }; + + WaapiHelper::executeWithRetry(succeedsOnSecondTry, 250, 5); + + REQUIRE(counter == 2); + } +#pragma endregion WaapiHelperTests + +#pragma region WwiseHelperTests + TEST_CASE_METHOD(WwiseHelperTests, "WwiseHelper::pathToPathParts") + { + std::vector<juce::String> paths{ + "\\Actor-Mixer Hierarchy\\Default Work Unit\\object", + "Actor-Mixer Hierarchy\\Default Work Unit\\object\\"}; + + for(auto& path : paths) + { + auto parts = WwiseHelper::pathToPathParts(path); + + REQUIRE(parts.size() == (size_t)3); + REQUIRE(parts[0] == juce::String("Actor-Mixer Hierarchy")); + REQUIRE(parts[1] == juce::String("Default Work Unit")); + REQUIRE(parts[2] == juce::String("object")); + } + } + + TEST_CASE_METHOD(WwiseHelperTests, "WwiseHelper::pathToObjectName") + { + std::vector<std::pair<juce::String, juce::String>> getObjectNameTestCases{ + {"\\Actor-Mixer Hierarchy\\Default Work Unit\\object", "object"}, + {"\\Actor-Mixer Hierarchy\\Default Work Unit\\<SoundSFX>object", "object"}, + }; + + for(auto& testCase : getObjectNameTestCases) + { + REQUIRE(WwiseHelper::pathToObjectName(testCase.first) == testCase.second); + } + } + + TEST_CASE_METHOD(WwiseHelperTests, "WwiseHelper::pathToAncestorPaths") + { + juce::String path = "\\Actor-Mixer Hierarchy\\Default Work Unit\\object"; + + auto ancestors = WwiseHelper::pathToAncestorPaths(path); + + REQUIRE(ancestors.size() == (size_t)2); + REQUIRE(ancestors[0] == juce::String("\\Actor-Mixer Hierarchy")); + REQUIRE(ancestors[1] == juce::String("\\Actor-Mixer Hierarchy\\Default Work Unit")); + } + + TEST_CASE_METHOD(WwiseHelperTests, "WwiseHelper::getCommonAncestor") + { + juce::String path1 = "\\Actor-Mixer Hierarchy\\Default Work Unit\\Container"; + juce::String path2 = "\\Actor-Mixer Hierarchy\\Default Work Unit\\Container\\Object"; + juce::String path3 = "\\Actor-Mixer Hierarchy\\Default Work Unit\\Container2\\Object2"; + juce::String path4 = "\\Default Work Unit"; + + REQUIRE(WwiseHelper::getCommonAncestor(path1, path2) == juce::String("\\Actor-Mixer Hierarchy\\Default Work Unit\\Container")); + REQUIRE(WwiseHelper::getCommonAncestor(path2, path3) == juce::String("\\Actor-Mixer Hierarchy\\Default Work Unit")); + REQUIRE(WwiseHelper::getCommonAncestor(path3, path4) == juce::String("")); + } +#pragma endregion WwiseHelperTests + +#pragma region WwiseModelTests + TEST_CASE_METHOD(WwiseModelTests, "Wwise::Version") + { + Wwise::Version v2022_1_0_0{2022, 1, 0, 0}; + Wwise::Version v2021_2_1_0{2021, 2, 1, 0}; + Wwise::Version v2021_3_1_0{2021, 3, 1, 0}; + Wwise::Version v2021_2_2_0{2021, 2, 2, 0}; + Wwise::Version v2021_2_1_1{2021, 2, 1, 1}; + + REQUIRE(v2022_1_0_0 >= v2022_1_0_0); + REQUIRE(v2022_1_0_0 <= v2022_1_0_0); + REQUIRE(v2022_1_0_0 == v2022_1_0_0); + + REQUIRE(v2022_1_0_0 > v2021_2_1_0); + REQUIRE(v2022_1_0_0 >= v2021_2_1_0); + REQUIRE(v2022_1_0_0 != v2021_2_1_0); + + REQUIRE(v2021_2_1_0 < v2021_3_1_0); + REQUIRE(v2021_2_1_0 <= v2021_3_1_0); + REQUIRE(v2021_2_1_0 != v2021_3_1_0); + + REQUIRE(v2021_2_1_0 < v2021_2_2_0); + REQUIRE(v2021_2_1_0 != v2021_2_2_0); + + REQUIRE(v2021_2_1_0 < v2021_2_1_1); + REQUIRE(v2021_2_1_0 <= v2021_2_1_1); + REQUIRE(v2021_2_1_0 != v2021_2_1_1); + } +#pragma endregion WwiseModelTests +} // namespace AK::WwiseTransfer diff --git a/src/test/WwiseHelperTests.cpp b/src/test/WwiseHelperTests.cpp @@ -0,0 +1,274 @@ +#include "WwiseHelperTests.h" + +namespace AK::WwiseTransfer::Test +{ + TEST_CASE("objectTypeToReadableString") + { + for (const auto& typeStringPair : objectTypeStringMap) + { + REQUIRE(WwiseHelper::objectTypeToReadableString(typeStringPair.first) == typeStringPair.second); + } + } + + TEST_CASE("stringToObjectType") + { + for (const auto& typeStringPair : objectTypeStringMap) + { + REQUIRE(WwiseHelper::stringToObjectType(typeStringPair.second) == typeStringPair.first); + } + } + + TEST_CASE("buildObjectPathNode") + { + const auto testName = "testObject"; + + for (const auto& objectType : objectTypes) + { + auto expectedResult = "\\<" + WwiseHelper::objectTypeToReadableString(objectType) + ">" + testName; + REQUIRE(WwiseHelper::buildObjectPathNode(objectType, testName) == expectedResult); + } + } + + TEST_CASE("pathToPathWithoutObjectTypes") + { + const auto testName = "testObject"; + const auto expectedResult = "\\testObject"; + + for (const auto& objectType : objectTypes) + { + auto buildObjectPath = WwiseHelper::buildObjectPathNode(objectType, testName); + REQUIRE(WwiseHelper::pathToPathWithoutObjectTypes(buildObjectPath) == expectedResult); + } + } + + TEST_CASE("pathToPathParts") + { + SECTION("Wwise Object Directory") + { + auto testPath = "\\test\\path\\directory\\multiple"; + + REQUIRE(WwiseHelper::pathToPathParts(testPath) == std::vector<juce::String> { "test", "path", "directory", "multiple" }); + } + SECTION("Wwise Object Type Directory") + { + auto testPath = "\\<testObject>testName\\path\\directory\\multiple"; + + REQUIRE(WwiseHelper::pathToPathParts(testPath) == std::vector<juce::String> { "<testObject>testName", "path", "directory", "multiple" }); + } + + } + + TEST_CASE("pathToAncestorPaths") + { + SECTION("Wwise Object Directory") + { + auto testPath = "\\test\\path\\directory\\multiple"; + + REQUIRE(WwiseHelper::pathToAncestorPaths(testPath) == std::vector<juce::String> { "\\test", "\\test\\path", "\\test\\path\\directory" }); + } + + SECTION("Wwise Object Type Directory") + { + auto testPath = "\\<testObject>testName\\path\\directory\\multiple"; + + REQUIRE(WwiseHelper::pathToAncestorPaths(testPath) == std::vector<juce::String> { "\\<testObject>testName", "\\<testObject>testName\\path", "\\<testObject>testName\\path\\directory" }); + } + } + + TEST_CASE("pathToObjectName") + { + SECTION("Wwise Object Directory") + { + auto testPath = "\\test\\path\\directory\\multiple"; + + REQUIRE(WwiseHelper::pathToObjectName(testPath) == "multiple"); + } + + SECTION("Wwise Object Type Directory") + { + auto testPath = "\\<testObject>testName\\path\\directory\\multiple"; + + REQUIRE(WwiseHelper::pathToObjectName(testPath) == "multiple"); + } + } + + TEST_CASE("pathToObjectType") + { + auto testName = "testObjectName"; + + SECTION("Wwise::ObjectType") + { + for (const auto& objectType : objectTypes) + { + auto buildObjectPath = WwiseHelper::buildObjectPathNode(objectType, testName); + + REQUIRE(WwiseHelper::pathToObjectType(buildObjectPath) == objectType); + } + } + + SECTION("Actor-Mixer Hierarchy") + { + auto testPath = "\\Actor-Mixer Hierarchy"; + + REQUIRE(WwiseHelper::pathToObjectType(testPath) == Wwise::ObjectType::ActorMixer); + } + } + + TEST_CASE("versionToValueTree") + { + SECTION("Non-Null Values") + { + auto year = 2022; + auto major = 1; + auto minor = 10; + auto build = 123456; + + auto version = Wwise::Version + { + year, + major, + minor, + build + }; + + auto versionTree = WwiseHelper::versionToValueTree(version); + + REQUIRE(juce::VariantConverter<int>::fromVar(versionTree.getProperty(IDs::year)) == year); + REQUIRE(juce::VariantConverter<int>::fromVar(versionTree.getProperty(IDs::major)) == major); + REQUIRE(juce::VariantConverter<int>::fromVar(versionTree.getProperty(IDs::minor)) == minor); + REQUIRE(juce::VariantConverter<int>::fromVar(versionTree.getProperty(IDs::build)) == build); + } + + SECTION("Null Values") + { + auto version = Wwise::Version(); + + auto versionTree = WwiseHelper::versionToValueTree(version); + + juce::var nullVar; + + REQUIRE(versionTree.getProperty(IDs::year) == nullVar); + REQUIRE(versionTree.getProperty(IDs::major) == nullVar); + REQUIRE(versionTree.getProperty(IDs::minor) == nullVar); + REQUIRE(versionTree.getProperty(IDs::build) == nullVar); + } + } + + TEST_CASE("valueTreeToVersion") + { + SECTION("Non-Null Values") + { + auto year = 2022; + auto major = 1; + auto minor = 10; + auto build = 123456; + + auto versionTree = juce::ValueTree(IDs::version); + + versionTree.setProperty(IDs::year, year, nullptr); + versionTree.setProperty(IDs::major, major, nullptr); + versionTree.setProperty(IDs::minor, minor, nullptr); + versionTree.setProperty(IDs::build, build, nullptr); + + auto version = WwiseHelper::valueTreeToVersion(versionTree); + + REQUIRE(version.year == year); + REQUIRE(version.major == major); + REQUIRE(version.minor == minor); + REQUIRE(version.build == build); + } + + SECTION("Null Values") + { + auto versionTree = juce::ValueTree(IDs::version); + + auto version = WwiseHelper::valueTreeToVersion(versionTree); + + REQUIRE(version.year == 0); + REQUIRE(version.major == 0); + REQUIRE(version.minor == 0); + REQUIRE(version.build == 0); + } + } + + TEST_CASE("languagesToValueTree") + { + auto languages = std::vector<juce::String>(); + SECTION("Empty") + { + auto languageTreeRoot = WwiseHelper::languagesToValueTree(languages); + + REQUIRE(languageTreeRoot.getNumChildren() == 0); + REQUIRE(languageTreeRoot.getType() == IDs::languages); + } + + SECTION("Non-Empty") + { + languages = { "English", "French", "Ukranian" }; + + auto languageTreeRoot = WwiseHelper::languagesToValueTree(languages); + + REQUIRE(languageTreeRoot.getNumChildren() == languages.size()); + REQUIRE(languageTreeRoot.getType() == IDs::languages); + + for (int index = 0; index < languages.size(); index++) + { + REQUIRE(languageTreeRoot.getChild(index).getProperty(IDs::languageName) == languages[index]); + REQUIRE(languageTreeRoot.getChild(index).getType() == IDs::language); + } + } + } + + TEST_CASE("valueTreeToLanguages") + { + auto languagesValueTree = juce::ValueTree(IDs::languages); + + SECTION("Empty") + { + auto langauges = WwiseHelper::valueTreeToLanguages(languagesValueTree); + + REQUIRE_THAT(langauges, Catch::Matchers::IsEmpty()); + } + + SECTION("Non-Empty") + { + auto languages = std::vector<juce::String>{ "English", "French", "Ukranian" }; + + for (const auto& language : languages) + { + auto childValueTree = juce::ValueTree(IDs::language); + childValueTree.setProperty(IDs::languageName, language, nullptr); + languagesValueTree.appendChild(childValueTree, nullptr); + } + + REQUIRE_THAT(WwiseHelper::valueTreeToLanguages(languagesValueTree), Catch::Matchers::Equals(languages)); + } + } + + TEST_CASE("getCommonAncestor") + { + SECTION("Folder Directory") + { + auto testPath1 = "\\test\\common\\ancestor\\folder1"; + auto testPath2 = "\\test\\common\\ancestor\\folder2"; + + REQUIRE(WwiseHelper::getCommonAncestor(testPath1, testPath2) == "\\test\\common\\ancestor"); + } + + SECTION("Object Type Directory") + { + auto testPath1 = "\\test\\<object type>testName\\ancestor\\folder1"; + auto testPath2 = "\\test\\<object type>testName\\ancestor\\folder2"; + + REQUIRE(WwiseHelper::getCommonAncestor(testPath1, testPath2) == "\\test\\<object type>testName\\ancestor"); + } + + SECTION("No Common Ancestors") + { + auto testPath1 = "\\no\\common\\ancestors"; + auto testPath2 = "\\without\\same\\subpath"; + + REQUIRE(WwiseHelper::getCommonAncestor(testPath1, testPath2) == ""); + } + } +} // namespace AK::WwiseTransfer:Test diff --git a/src/test/WwiseHelperTests.h b/src/test/WwiseHelperTests.h @@ -0,0 +1,42 @@ +#include "Helpers/WwiseHelper.h" +#include "Model/Import.h" + +#include <catch2/catch_all.hpp> +#include <catch2/catch_test_macros.hpp> +#include <juce_core/juce_core.h> +#include <memory> + +namespace AK::WwiseTransfer::Test +{ + std::unordered_map <Wwise::ObjectType, juce::String> objectTypeStringMap{ + {Wwise::ObjectType::ActorMixer, "Actor Mixer"}, + {Wwise::ObjectType::AudioFileSource, "Audio File Source"}, + {Wwise::ObjectType::BlendContainer, "Blend Container"}, + {Wwise::ObjectType::PhysicalFolder, "Physical Folder"}, + {Wwise::ObjectType::RandomContainer, "Random Container"}, + {Wwise::ObjectType::SequenceContainer, "Sequence Container"}, + {Wwise::ObjectType::SoundSFX, "Sound SFX"}, + {Wwise::ObjectType::SoundVoice, "Sound Voice"}, + {Wwise::ObjectType::SwitchContainer, "Switch Container"}, + {Wwise::ObjectType::VirtualFolder, "Virtual Folder"}, + {Wwise::ObjectType::WorkUnit, "Work Unit"}, + {Wwise::ObjectType::Sound, "Sound"}, + {Wwise::ObjectType::Unknown, "Unknown"} + }; + + std::vector <Wwise::ObjectType> objectTypes{ + Wwise::ObjectType::ActorMixer, + Wwise::ObjectType::AudioFileSource, + Wwise::ObjectType::BlendContainer, + Wwise::ObjectType::PhysicalFolder, + Wwise::ObjectType::RandomContainer, + Wwise::ObjectType::SequenceContainer, + Wwise::ObjectType::SoundSFX, + Wwise::ObjectType::SoundVoice, + Wwise::ObjectType::SwitchContainer, + Wwise::ObjectType::VirtualFolder, + Wwise::ObjectType::WorkUnit, + Wwise::ObjectType::Sound, + Wwise::ObjectType::Unknown + }; +} // namespace AK::WwiseTransfer:Test