├── .gitignore ├── CMakeLists.txt ├── LICENSE.txt ├── Readme.md ├── c_gain_test_plugin └── cgain.c ├── generate_header ├── generate_header.c └── scripts │ ├── .gitignore │ ├── clang_helpers.py │ ├── data_classes.py │ ├── file_string.py │ ├── generate_header_compilation.py │ ├── interface_convert.py │ ├── pyproject.toml │ ├── templates │ └── header_compilation.h │ ├── test │ ├── __init__.py │ ├── headers │ │ ├── enums.h │ │ ├── enums_expected.h │ │ ├── funknown.h │ │ ├── interfaces.h │ │ ├── interfaces_expected.h │ │ ├── structs.h │ │ ├── structs_expected.h │ │ ├── typedefs.h │ │ ├── typedefs_expected.h │ │ ├── types.h │ │ ├── variables.h │ │ ├── variables_expected.h │ │ ├── vst_interfaces.h │ │ ├── vst_interfaces_expected.h │ │ └── vsttypes.h │ └── test_conversion.py │ └── uv.lock └── validate_interfaces ├── cxx.cpp ├── main.c └── test2.c /.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | .idea/ 3 | /build/ 4 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.15.0) 2 | 3 | ############################################################################################### 4 | ## Default Options 5 | ############################################################################################### 6 | 7 | set(SMTG_PLUGINTERFACES_REPO_TYPE_DEFAULT git) 8 | set(SMTG_PLUGINTERFACES_REPO_DEFAULT https://github.com/steinbergmedia/vst3_pluginterfaces.git) 9 | set(SMTG_PLUGINTERFACES_GIT_TAG_DEFAULT HEAD) 10 | 11 | ############################################################################################### 12 | ## Options 13 | ############################################################################################### 14 | 15 | set(SMTG_PLUGINTERFACES_REPO_TYPE 16 | ${SMTG_PLUGINTERFACES_REPO_TYPE_DEFAULT} 17 | CACHE STRING "The VST3 pluginterfaces (API) repository type (git or file)" 18 | ) 19 | set(SMTG_PLUGINTERFACES_REPO 20 | ${SMTG_PLUGINTERFACES_REPO_DEFAULT} 21 | CACHE STRING "The VST3 pluginterfaces (API) repository" 22 | ) 23 | set(SMTG_PLUGINTERFACES_GIT_TAG 24 | ${SMTG_PLUGINTERFACES_GIT_TAG_DEFAULT} 25 | CACHE STRING "The VST3 pluginterfaces (API) git tag" 26 | ) 27 | 28 | ############################################################################################### 29 | ## Fetch the VST API repository 30 | ############################################################################################### 31 | 32 | if(${SMTG_PLUGINTERFACES_REPO_TYPE} STREQUAL git) 33 | include(FetchContent) 34 | 35 | FetchContent_Declare( 36 | pluginterfaces 37 | GIT_REPOSITORY ${SMTG_PLUGINTERFACES_REPO} 38 | GIT_TAG ${SMTG_PLUGINTERFACES_GIT_TAG} 39 | GIT_SHALLOW TRUE 40 | GIT_PROGRESS TRUE 41 | SOURCE_DIR "${CMAKE_BINARY_DIR}/_deps/pluginterfaces" 42 | ) 43 | message(STATUS "Git clone pluginterfaces") 44 | FetchContent_Populate(pluginterfaces) 45 | message(STATUS "Git clone pluginterfaces done.") 46 | 47 | elseif(${SMTG_PLUGINTERFACES_REPO_TYPE} STREQUAL file) 48 | execute_process(COMMAND /bin/rm -rf "${CMAKE_BINARY_DIR}/_deps/pluginterfaces") 49 | execute_process(COMMAND /bin/mkdir -p "${CMAKE_BINARY_DIR}/_deps") 50 | execute_process(COMMAND /bin/cp -R ${SMTG_PLUGINTERFACES_REPO} "${CMAKE_BINARY_DIR}/_deps/pluginterfaces") 51 | set(pluginterfaces_SOURCE_DIR ${CMAKE_BINARY_DIR}/_deps/pluginterfaces) 52 | else() 53 | message(FATAL_ERROR "Wrong repo type") 54 | endif() 55 | 56 | ############################################################################################### 57 | ## Prepare Python 58 | ############################################################################################### 59 | find_package (Python3) 60 | 61 | set(venv_dir ${CMAKE_BINARY_DIR}/venv) 62 | message(STATUS "Execute: ${Python3_EXECUTABLE} -m venv ${venv_dir}") 63 | execute_process(COMMAND ${Python3_EXECUTABLE} -m venv ${venv_dir}) 64 | if(APPLE) 65 | set(venv_python_exe ${venv_dir}/bin/python) 66 | elseif(WIN32) 67 | set(venv_python_exe ${venv_dir}/Scripts/python.exe) 68 | endif() 69 | 70 | message(STATUS "Execute: ${venv_python_exe} -m pip install --upgrade pip") 71 | execute_process(COMMAND ${venv_python_exe} -m pip install --upgrade pip) 72 | 73 | foreach(library libclang==18.1.* clang==18.1.* jinja2) 74 | message(STATUS "Execute: ${venv_python_exe} -m pip install ${library}") 75 | execute_process(COMMAND ${venv_python_exe} -m pip install ${library}) 76 | endforeach() 77 | 78 | ############################################################################################### 79 | ## Project 80 | ############################################################################################### 81 | 82 | project( 83 | VST3_C_API_GENERATOR 84 | VERSION 1.0.0 85 | ) 86 | 87 | ############################################################################################### 88 | ## Generate Interface Target 89 | ############################################################################################### 90 | 91 | add_executable(Generate_Header generate_header/generate_header.c generate_header/scripts) 92 | target_include_directories(Generate_Header PRIVATE ${CMAKE_BINARY_DIR}) 93 | 94 | if(APPLE) 95 | set(sysroot_arg "-isysroot;${CMAKE_OSX_SYSROOT}") 96 | endif() 97 | 98 | add_custom_command( 99 | TARGET Generate_Header 100 | PRE_BUILD 101 | WORKING_DIRECTORY ${CMAKE_BINARY_DIR} 102 | COMMAND ${venv_python_exe} ${CMAKE_CURRENT_SOURCE_DIR}/generate_header/scripts/generate_header_compilation.py ${pluginterfaces_SOURCE_DIR} 103 | COMMAND ${venv_python_exe} ${CMAKE_CURRENT_SOURCE_DIR}/generate_header/scripts/interface_convert.py ${CMAKE_BINARY_DIR}/_deps/pluginterfaces/vst/header_compilation.h ${sysroot_arg} 104 | POST_BUILD 105 | COMMAND ${CMAKE_COMMAND} -E rm -f ${CMAKE_BINARY_DIR}/_deps/pluginterfaces/vst/header_compilation.h 106 | ) 107 | 108 | ############################################################################################### 109 | ## Validate Interface Target 110 | ############################################################################################### 111 | 112 | add_executable(Validate_Interfaces 113 | validate_interfaces/main.c 114 | validate_interfaces/test2.c 115 | validate_interfaces/cxx.cpp 116 | "${CMAKE_BINARY_DIR}/_deps/pluginterfaces" 117 | ) 118 | target_include_directories(Validate_Interfaces PRIVATE "${CMAKE_BINARY_DIR}" "${pluginterfaces_SOURCE_DIR}/..") 119 | target_compile_features(Validate_Interfaces 120 | PUBLIC 121 | cxx_std_17 122 | ) 123 | add_dependencies(Validate_Interfaces Generate_Header) 124 | 125 | ############################################################################################### 126 | ## CGain Target 127 | ############################################################################################### 128 | 129 | add_library(C_Gain_Test MODULE c_gain_test_plugin/cgain.c) 130 | target_include_directories(C_Gain_Test PRIVATE ${CMAKE_BINARY_DIR}) 131 | 132 | if(APPLE) 133 | set_target_properties(C_Gain_Test 134 | PROPERTIES 135 | BUNDLE TRUE 136 | XCODE_ATTRIBUTE_GENERATE_PKGINFO_FILE YES 137 | XCODE_ATTRIBUTE_WRAPPER_EXTENSION vst3 138 | ) 139 | else() 140 | set_target_properties(C_Gain_Test 141 | PROPERTIES 142 | SUFFIX ".vst3") 143 | endif() 144 | 145 | add_dependencies(C_Gain_Test Validate_Interfaces) 146 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------------- 2 | // LICENSE 3 | // (c) 2022, Steinberg Media Technologies GmbH, All Rights Reserved 4 | //----------------------------------------------------------------------------- 5 | This license applies only to files referencing this license, 6 | for other files of the Software Development Kit the respective embedded license text 7 | is applicable. The license can be found at: www.steinberg.net/sdklicenses_vst3 8 | 9 | This Software Development Kit is licensed under the terms of the Steinberg VST3 License, 10 | or alternatively under the terms of the General Public License (GPL) Version 3. 11 | You may use the Software Development Kit according to either of these licenses as it is 12 | most appropriate for your project on a case-by-case basis (commercial or not). 13 | 14 | a) Proprietary Steinberg VST3 License 15 | The Software Development Kit may not be distributed in parts or its entirety 16 | without prior written agreement by Steinberg Media Technologies GmbH. 17 | The SDK must not be used to re-engineer or manipulate any technology used 18 | in any Steinberg or Third-party application or software module, 19 | unless permitted by law. 20 | Neither the name of the Steinberg Media Technologies GmbH nor the names of its 21 | contributors may be used to endorse or promote products derived from this 22 | software without specific prior written permission. 23 | Before publishing a software under the proprietary license, you need to obtain a copy 24 | of the License Agreement signed by Steinberg Media Technologies GmbH. 25 | The Steinberg VST SDK License Agreement can be found at: 26 | www.steinberg.net/en/company/developers.html 27 | 28 | THE SDK IS PROVIDED BY STEINBERG MEDIA TECHNOLOGIES GMBH "AS IS" AND 29 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 30 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 31 | IN NO EVENT SHALL STEINBERG MEDIA TECHNOLOGIES GMBH BE LIABLE FOR ANY DIRECT, 32 | INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 33 | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 34 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 35 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 36 | OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 37 | OF THE POSSIBILITY OF SUCH DAMAGE. 38 | 39 | b) General Public License (GPL) Version 3 40 | Details of these licenses can be found at: www.gnu.org/licenses/gpl-3.0.html 41 | Please refer to the Steinberg VST usage guidelines for the use of VST, VST logo and VST 42 | compatible logos: 43 | https://steinbergmedia.github.io/vst3_dev_portal/pages/VST+3+Licensing/Usage+guidelines.html 44 | //---------------------------------------------------------------------------------- 45 | -------------------------------------------------------------------------------- /Readme.md: -------------------------------------------------------------------------------- 1 | ## VST3 C API Generator 2 | 3 | This repository contains scripts for generating and testing the C API from the VST3 c++ SDK 4 | 5 | --- 6 | 7 | The `generate_header` folder contains the scripts to create the `vst3_c_api.h` header file 8 | 9 | The `validate_interafaces` folder contains c and c++ source files to validate the generated header 10 | 11 | The `c_gain_test_plugin` folder contains a simple VST3 Plug-in written in C 12 | 13 | --- 14 | 15 | To build it use cmake: 16 | 17 | mkdir build 18 | cd build 19 | cmake ../ 20 | cmake --build . 21 | 22 | --- 23 | 24 | Check the LICENSE.txt for the license 25 | -------------------------------------------------------------------------------- /c_gain_test_plugin/cgain.c: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------ 2 | // Flags : clang-format SMTGSequencer 3 | // Project : VST3 C API Generator 4 | // Filename : cgain.c 5 | // Created by : nzorn, 07/2022 6 | // Description : Example VST3 Plug-in using the C API 7 | //------------------------------------------------------------------------ 8 | 9 | //----------------------------------------------------------------------------- 10 | // This file is part of a Steinberg SDK. It is subject to the license terms 11 | // in the LICENSE file found in the top-level directory of this distribution 12 | // and at www.steinberg.net/sdklicenses. 13 | // No part of the SDK, including this file, may be copied, modified, propagated, 14 | // or distributed except according to the terms contained in the LICENSE file. 15 | //----------------------------------------------------------------------------- 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | #include "vst3_c_api.h" 24 | 25 | static size_t pointerOffset = sizeof (void*); 26 | 27 | int compare_iid (const Steinberg_TUID id1, const Steinberg_TUID id2) 28 | { 29 | return memcmp (id1, id2, sizeof (Steinberg_TUID)) == 0; 30 | } 31 | 32 | static const Steinberg_TUID audioProcessorUID = 33 | SMTG_INLINE_UID (0xD87D8E9C, 0xE4514B02, 0xB9FCF354, 0xFAC9219C); 34 | 35 | static const Steinberg_TUID editControllerUID = 36 | SMTG_INLINE_UID (0xBACB8EB9, 0xAFAD4C09, 0x90D5893E, 0xCE6D94AD); 37 | 38 | struct AGainAudioProcessorVtbl 39 | { 40 | Steinberg_Vst_IComponentVtbl component; 41 | Steinberg_Vst_IConnectionPointVtbl connectionPoint; 42 | Steinberg_Vst_IAudioProcessorVtbl audioProcessor; 43 | Steinberg_Vst_IProcessContextRequirementsVtbl processContextRequirements; 44 | }; 45 | 46 | typedef struct 47 | { 48 | const struct Steinberg_Vst_IComponentVtbl* componentVtbl; 49 | const struct Steinberg_Vst_IConnectionPointVtbl* connectionPointVtbl; 50 | const struct Steinberg_Vst_IAudioProcessorVtbl* audioProcessorVtbl; 51 | const struct Steinberg_Vst_IProcessContextRequirementsVtbl* processContextRequirementsVtbl; 52 | Steinberg_int32 refCount; 53 | struct Steinberg_Vst_IConnectionPoint* connectionPoint; 54 | float fGain; 55 | } AGainAudioProcessor; 56 | 57 | struct AGainEditControllerVtbl 58 | { 59 | Steinberg_Vst_IEditControllerVtbl editController; 60 | Steinberg_Vst_IConnectionPointVtbl connectionPoint; 61 | Steinberg_Vst_IEditController2Vtbl editController2; 62 | }; 63 | 64 | typedef struct 65 | { 66 | const struct Steinberg_Vst_IEditControllerVtbl* editControllerVtbl; 67 | const struct Steinberg_Vst_IConnectionPointVtbl* connectionPointVtbl; 68 | const struct Steinberg_Vst_IEditController2Vtbl* editController2Vtbl; 69 | Steinberg_int32 refCount; 70 | Steinberg_Vst_ParamValue gainParam; 71 | } AGainEditController; 72 | 73 | struct AGainFactoryVtbl 74 | { 75 | Steinberg_IPluginFactory2Vtbl pluginFactory; 76 | }; 77 | 78 | typedef struct 79 | { 80 | const struct Steinberg_IPluginFactory2Vtbl* pluginFactoryVtbl; 81 | struct Steinberg_PClassInfo2 classes[2]; 82 | struct Steinberg_PFactoryInfo factoryInfo; 83 | } AGainFactory; 84 | 85 | /*----------------------------------------------------------------------------------------------------------------------------- 86 | Audio Processor Methods*/ 87 | 88 | Steinberg_uint32 SMTG_STDMETHODCALLTYPE AGainProcessor_AddRef (void* thisInterface) 89 | { 90 | AGainAudioProcessor* instance = (AGainAudioProcessor*)thisInterface; 91 | instance->refCount += 1; 92 | return instance->refCount; 93 | } 94 | 95 | Steinberg_uint32 SMTG_STDMETHODCALLTYPE AGainProcessor_AddRef_ConnectionPoint (void* thisInterface) 96 | { 97 | return AGainProcessor_AddRef ((void*)((int64_t)thisInterface - pointerOffset)); 98 | } 99 | 100 | Steinberg_uint32 SMTG_STDMETHODCALLTYPE AGainProcessor_AddRef_AudioProcessor (void* thisInterface) 101 | { 102 | return AGainProcessor_AddRef ((void*)((int64_t)thisInterface - (pointerOffset * 2))); 103 | } 104 | 105 | Steinberg_uint32 SMTG_STDMETHODCALLTYPE 106 | AGainProcessor_AddRef_ProcessContextRequirements (void* thisInterface) 107 | { 108 | return AGainProcessor_AddRef ((void*)((int64_t)thisInterface - (pointerOffset * 3))); 109 | } 110 | 111 | Steinberg_uint32 SMTG_STDMETHODCALLTYPE AGainProcessor_Release (void* thisInterface) 112 | { 113 | AGainAudioProcessor* instance = (AGainAudioProcessor*)thisInterface; 114 | if (instance->refCount == 1) 115 | { 116 | free (instance); 117 | return 0; 118 | } 119 | instance->refCount -= 1; 120 | return instance->refCount; 121 | } 122 | 123 | Steinberg_uint32 SMTG_STDMETHODCALLTYPE AGainProcessor_Release_ConnectionPoint (void* thisInterface) 124 | { 125 | return AGainProcessor_Release ((void*)((int64_t)thisInterface - pointerOffset)); 126 | } 127 | 128 | Steinberg_uint32 SMTG_STDMETHODCALLTYPE AGainProcessor_Release_AudioProcessor (void* thisInterface) 129 | { 130 | return AGainProcessor_Release ((void*)((int64_t)thisInterface - (pointerOffset * 2))); 131 | } 132 | 133 | Steinberg_uint32 SMTG_STDMETHODCALLTYPE 134 | AGainProcessor_Release_ProcessContextRequirements (void* thisInterface) 135 | { 136 | return AGainProcessor_Release ((void*)((int64_t)thisInterface - (pointerOffset * 3))); 137 | } 138 | 139 | Steinberg_tresult SMTG_STDMETHODCALLTYPE AGainProcessor_QueryInterface (void* thisInterface, 140 | const Steinberg_TUID iid, 141 | void** obj) 142 | { 143 | AGainAudioProcessor* instance = (AGainAudioProcessor*)thisInterface; 144 | if (compare_iid (Steinberg_FUnknown_iid, iid)) 145 | { 146 | AGainProcessor_AddRef (thisInterface); 147 | *obj = instance; 148 | return Steinberg_kResultTrue; 149 | } 150 | if (compare_iid (Steinberg_IPluginBase_iid, iid)) 151 | { 152 | AGainProcessor_AddRef (thisInterface); 153 | *obj = instance; 154 | return Steinberg_kResultTrue; 155 | } 156 | if (compare_iid (Steinberg_Vst_IComponent_iid, iid)) 157 | { 158 | AGainProcessor_AddRef (thisInterface); 159 | *obj = instance; 160 | return Steinberg_kResultTrue; 161 | } 162 | if (compare_iid (Steinberg_Vst_IConnectionPoint_iid, iid)) 163 | { 164 | AGainProcessor_AddRef (thisInterface); 165 | *obj = (void*)((int64_t)instance + pointerOffset); 166 | return Steinberg_kResultTrue; 167 | } 168 | if (compare_iid (Steinberg_Vst_IAudioProcessor_iid, iid)) 169 | { 170 | AGainProcessor_AddRef (thisInterface); 171 | *obj = (void*)((int64_t)instance + (pointerOffset * 2)); 172 | return Steinberg_kResultTrue; 173 | } 174 | if (compare_iid (Steinberg_Vst_IProcessContextRequirements_iid, iid)) 175 | { 176 | AGainProcessor_AddRef (thisInterface); 177 | *obj = (void*)((int64_t)instance + (pointerOffset * 3)); 178 | return Steinberg_kResultTrue; 179 | } 180 | *obj = NULL; 181 | return Steinberg_kResultFalse; 182 | } 183 | 184 | Steinberg_tresult SMTG_STDMETHODCALLTYPE AGainProcessor_QueryInterface_ConnectionPoint ( 185 | void* thisInterface, const Steinberg_TUID iid, void** obj) 186 | { 187 | return AGainProcessor_QueryInterface ((void*)((int64_t)thisInterface - pointerOffset), iid, 188 | obj); 189 | } 190 | 191 | Steinberg_tresult SMTG_STDMETHODCALLTYPE AGainProcessor_QueryInterface_AudioProcessor ( 192 | void* thisInterface, const Steinberg_TUID iid, void** obj) 193 | { 194 | return AGainProcessor_QueryInterface ((void*)((int64_t)thisInterface - (pointerOffset * 2)), 195 | iid, obj); 196 | } 197 | 198 | Steinberg_tresult SMTG_STDMETHODCALLTYPE AGainProcessor_QueryInterface_ProcessContextRequirements ( 199 | void* thisInterface, const Steinberg_TUID iid, void** obj) 200 | { 201 | return AGainProcessor_QueryInterface ((void*)((int64_t)thisInterface - (pointerOffset * 3)), 202 | iid, obj); 203 | } 204 | 205 | Steinberg_tresult SMTG_STDMETHODCALLTYPE 206 | AGainProcessor_Initialize (void* thisInterface, struct Steinberg_FUnknown* context) 207 | { 208 | return Steinberg_kResultOk; 209 | } 210 | 211 | Steinberg_tresult SMTG_STDMETHODCALLTYPE AGainProcessor_Terminate (void* thisInterface) 212 | { 213 | return Steinberg_kResultOk; 214 | }; 215 | 216 | Steinberg_tresult SMTG_STDMETHODCALLTYPE 217 | AGainProcessor_Connect (void* thisInterface, struct Steinberg_Vst_IConnectionPoint* other) 218 | { 219 | AGainAudioProcessor* instance = (AGainAudioProcessor*)((int64_t)thisInterface - pointerOffset); 220 | instance->connectionPoint = other; 221 | return Steinberg_kResultTrue; 222 | } 223 | 224 | Steinberg_tresult SMTG_STDMETHODCALLTYPE 225 | AGainProcessor_Disconnect (void* thisInterface, struct Steinberg_Vst_IConnectionPoint* other) 226 | { 227 | AGainAudioProcessor* instance = (AGainAudioProcessor*)((int64_t)thisInterface - pointerOffset); 228 | instance->connectionPoint = NULL; 229 | return Steinberg_kResultTrue; 230 | } 231 | 232 | Steinberg_tresult SMTG_STDMETHODCALLTYPE 233 | AGainProcessor_Notify (void* thisInterface, struct Steinberg_Vst_IMessage* message) 234 | { 235 | return Steinberg_kResultOk; 236 | } 237 | 238 | Steinberg_tresult SMTG_STDMETHODCALLTYPE 239 | AGainProcessor_GetControllerClassId (void* thisInterface, Steinberg_TUID classId) 240 | { 241 | memcpy (classId, editControllerUID, sizeof (Steinberg_TUID)); 242 | return Steinberg_kResultTrue; 243 | } 244 | 245 | Steinberg_tresult SMTG_STDMETHODCALLTYPE AGainProcessor_SetIoMode (void* thisInterface, 246 | Steinberg_Vst_IoMode mode) 247 | { 248 | return Steinberg_kResultOk; 249 | }; 250 | 251 | Steinberg_int32 SMTG_STDMETHODCALLTYPE AGainProcessor_GetBusCount (void* thisInterface, 252 | Steinberg_Vst_MediaType type, 253 | Steinberg_Vst_BusDirection dir) 254 | { 255 | if (type == Steinberg_Vst_MediaTypes_kAudio) 256 | { 257 | return 1; 258 | } 259 | return 0; 260 | } 261 | 262 | Steinberg_tresult SMTG_STDMETHODCALLTYPE AGainProcessor_GetBusInfo ( 263 | void* thisInterface, Steinberg_Vst_MediaType type, Steinberg_Vst_BusDirection dir, 264 | Steinberg_int32 index, struct Steinberg_Vst_BusInfo* bus) 265 | { 266 | if (type == Steinberg_Vst_MediaTypes_kEvent) 267 | { 268 | return Steinberg_kResultFalse; 269 | } 270 | static const Steinberg_char16 name_string[] = {'b', 'u', 's'}; 271 | memcpy (bus->name, name_string, sizeof (name_string)); 272 | bus->channelCount = 2; 273 | bus->flags = Steinberg_Vst_BusInfo_BusFlags_kDefaultActive; 274 | bus->direction = dir; 275 | bus->mediaType = type; 276 | bus->busType = Steinberg_Vst_BusTypes_kMain; 277 | return Steinberg_kResultTrue; 278 | } 279 | 280 | Steinberg_tresult SMTG_STDMETHODCALLTYPE 281 | AGainProcessor_GetRoutingInfo (void* thisInterface, struct Steinberg_Vst_RoutingInfo* inInfo, 282 | struct Steinberg_Vst_RoutingInfo* outInfo) 283 | { 284 | return Steinberg_kNotImplemented; 285 | } 286 | 287 | Steinberg_tresult SMTG_STDMETHODCALLTYPE AGainProcessor_ActivateBus (void* thisInterface, 288 | Steinberg_Vst_MediaType type, 289 | Steinberg_Vst_BusDirection dir, 290 | Steinberg_int32 index, 291 | Steinberg_TBool state) 292 | { 293 | if (type == Steinberg_Vst_MediaTypes_kEvent) 294 | { 295 | return Steinberg_kResultFalse; 296 | } 297 | return Steinberg_kResultTrue; 298 | } 299 | 300 | Steinberg_tresult SMTG_STDMETHODCALLTYPE AGainProcessor_SetActive (void* thisInterface, 301 | Steinberg_TBool state) 302 | { 303 | return Steinberg_kResultTrue; 304 | } 305 | 306 | Steinberg_tresult SMTG_STDMETHODCALLTYPE AGainProcessor_SetState (void* thisInterface, 307 | struct Steinberg_IBStream* state) 308 | { 309 | if (state == NULL) 310 | { 311 | return Steinberg_kInvalidArgument; 312 | } 313 | AGainAudioProcessor* instance = (AGainAudioProcessor*)thisInterface; 314 | return state->lpVtbl->read (state, &instance->fGain, sizeof (instance->fGain), NULL); 315 | } 316 | 317 | Steinberg_tresult SMTG_STDMETHODCALLTYPE AGainProcessor_GetState (void* thisInterface, 318 | struct Steinberg_IBStream* state) 319 | { 320 | if (state == NULL) 321 | { 322 | return Steinberg_kInvalidArgument; 323 | } 324 | AGainAudioProcessor* instance = (AGainAudioProcessor*)thisInterface; 325 | return state->lpVtbl->write (state, &instance->fGain, sizeof (instance->fGain), NULL); 326 | } 327 | 328 | Steinberg_tresult SMTG_STDMETHODCALLTYPE AGainProcessor_SetBusArrangements ( 329 | void* thisInterface, Steinberg_Vst_SpeakerArrangement* inputs, Steinberg_int32 numIns, 330 | Steinberg_Vst_SpeakerArrangement* outputs, Steinberg_int32 numOuts) 331 | { 332 | if (numIns != numOuts || numIns != 1) 333 | { 334 | return Steinberg_kResultFalse; 335 | } 336 | if (inputs[0] != outputs[0] || inputs[0] != Steinberg_Vst_SpeakerArr_kStereo) 337 | { 338 | return Steinberg_kResultFalse; 339 | } 340 | return Steinberg_kResultTrue; 341 | } 342 | 343 | Steinberg_tresult SMTG_STDMETHODCALLTYPE 344 | AGainProcessor_GetBusArrangement (void* thisInterface, Steinberg_Vst_BusDirection dir, 345 | Steinberg_int32 index, Steinberg_Vst_SpeakerArrangement* arr) 346 | { 347 | if (index != 0) 348 | { 349 | return Steinberg_kInvalidArgument; 350 | } 351 | *arr = Steinberg_Vst_SpeakerArr_kStereo; 352 | return Steinberg_kResultTrue; 353 | } 354 | 355 | Steinberg_tresult SMTG_STDMETHODCALLTYPE 356 | AGainProcessor_CanProcessSampleSize (void* thisInterface, Steinberg_int32 symbolicSampleSize) 357 | { 358 | return symbolicSampleSize == Steinberg_Vst_SymbolicSampleSizes_kSample32 ? 359 | Steinberg_kResultTrue : 360 | Steinberg_kResultFalse; 361 | } 362 | 363 | Steinberg_uint32 SMTG_STDMETHODCALLTYPE AGainProcessor_GetLatencySamples (void* thisInterface) 364 | { 365 | return 0; 366 | } 367 | 368 | Steinberg_tresult SMTG_STDMETHODCALLTYPE 369 | AGainProcessor_SetupProcessing (void* thisInterface, struct Steinberg_Vst_ProcessSetup* setup) 370 | { 371 | return Steinberg_kResultTrue; 372 | } 373 | 374 | Steinberg_tresult SMTG_STDMETHODCALLTYPE AGainProcessor_SetProcessing (void* thisInterface, 375 | Steinberg_TBool state) 376 | { 377 | return Steinberg_kResultTrue; 378 | } 379 | 380 | Steinberg_tresult SMTG_STDMETHODCALLTYPE 381 | AGainProcessor_Process (void* thisInterface, struct Steinberg_Vst_ProcessData* data) 382 | { 383 | AGainAudioProcessor* instance = 384 | (AGainAudioProcessor*)((int64_t)thisInterface - (pointerOffset * 2)); 385 | Steinberg_Vst_IParameterChanges* paramChanges = data->inputParameterChanges; 386 | if (paramChanges) 387 | { 388 | Steinberg_int32 numParamsChanged = paramChanges->lpVtbl->getParameterCount (paramChanges); 389 | 390 | for (Steinberg_int32 i = 0; i < numParamsChanged; i++) 391 | { 392 | Steinberg_Vst_IParamValueQueue* paramQueue = 393 | paramChanges->lpVtbl->getParameterData (paramChanges, i); 394 | if (paramQueue) 395 | { 396 | Steinberg_Vst_ParamValue value; 397 | Steinberg_int32 sampleOffset; 398 | Steinberg_int32 numPoints = paramQueue->lpVtbl->getPointCount (paramQueue); 399 | if (numPoints > 0 && 400 | paramQueue->lpVtbl->getPoint (paramQueue, numPoints - 1, &sampleOffset, 401 | &value) == Steinberg_kResultTrue) 402 | { 403 | 404 | instance->fGain = (float)value; 405 | } 406 | } 407 | } 408 | } 409 | if (!data || data->numSamples == 0 || data->inputs == 0 || data->outputs == 0) 410 | { 411 | return Steinberg_kResultTrue; 412 | } 413 | float fGain2 = 2.f * instance->fGain; 414 | for (int channel_index = 0; channel_index < data->inputs[0].numChannels; channel_index++) 415 | { 416 | for (int sample_index = 0; sample_index < data->numSamples; sample_index++) 417 | { 418 | float sampleInput = 419 | data->inputs[0] 420 | .Steinberg_Vst_AudioBusBuffers_channelBuffers32[channel_index][sample_index]; 421 | data->outputs[0] 422 | .Steinberg_Vst_AudioBusBuffers_channelBuffers32[channel_index][sample_index] = 423 | sampleInput * fGain2; 424 | } 425 | } 426 | 427 | return Steinberg_kResultTrue; 428 | } 429 | 430 | Steinberg_uint32 SMTG_STDMETHODCALLTYPE AGainProcessor_GetTailSamples (void* thisInterface) 431 | { 432 | return 0; 433 | } 434 | 435 | Steinberg_uint32 SMTG_STDMETHODCALLTYPE 436 | AGainProcessor_getProcessContextRequirements (void* thisInterface) 437 | { 438 | return 0; 439 | } 440 | 441 | /*----------------------------------------------------------------------------------------------------------------------------- 442 | Edit Controller methods*/ 443 | 444 | Steinberg_uint32 SMTG_STDMETHODCALLTYPE AGainController_AddRef (void* thisInterface) 445 | { 446 | AGainEditController* instance = (AGainEditController*)thisInterface; 447 | instance->refCount += 1; 448 | return instance->refCount; 449 | } 450 | 451 | Steinberg_uint32 SMTG_STDMETHODCALLTYPE AGainController_AddRef_ConnectionPoint (void* thisInterface) 452 | { 453 | return AGainController_AddRef ((void*)((int64_t)thisInterface - pointerOffset)); 454 | } 455 | 456 | Steinberg_uint32 SMTG_STDMETHODCALLTYPE AGainController_AddRef_EditController2 (void* thisInterface) 457 | { 458 | return AGainController_AddRef ((void*)((int64_t)thisInterface - (pointerOffset * 2))); 459 | } 460 | 461 | Steinberg_uint32 SMTG_STDMETHODCALLTYPE AGainController_Release (void* thisInterface) 462 | { 463 | AGainEditController* instance = (AGainEditController*)thisInterface; 464 | if (instance->refCount == 1) 465 | { 466 | free (instance); 467 | return 0; 468 | } 469 | instance->refCount -= 1; 470 | return instance->refCount; 471 | } 472 | 473 | Steinberg_uint32 SMTG_STDMETHODCALLTYPE 474 | AGainController_Release_ConnectionPoint (void* thisInterface) 475 | { 476 | return AGainController_Release ((void*)((int64_t)thisInterface - pointerOffset)); 477 | } 478 | 479 | Steinberg_uint32 SMTG_STDMETHODCALLTYPE 480 | AGainController_Release_EditController2 (void* thisInterface) 481 | { 482 | return AGainController_Release ((void*)((int64_t)thisInterface - (pointerOffset * 2))); 483 | } 484 | 485 | Steinberg_tresult SMTG_STDMETHODCALLTYPE AGainController_QueryInterface (void* thisInterface, 486 | const Steinberg_TUID iid, 487 | void** obj) 488 | { 489 | AGainEditController* instance = (AGainEditController*)thisInterface; 490 | if (compare_iid (Steinberg_FUnknown_iid, iid)) 491 | { 492 | AGainController_AddRef (thisInterface); 493 | *obj = instance; 494 | return Steinberg_kResultTrue; 495 | } 496 | if (compare_iid (Steinberg_IPluginBase_iid, iid)) 497 | { 498 | AGainController_AddRef (thisInterface); 499 | *obj = instance; 500 | return Steinberg_kResultTrue; 501 | } 502 | if (compare_iid (Steinberg_Vst_IEditController_iid, iid)) 503 | { 504 | AGainController_AddRef (thisInterface); 505 | *obj = instance; 506 | return Steinberg_kResultTrue; 507 | } 508 | if (compare_iid (Steinberg_Vst_IConnectionPoint_iid, iid)) 509 | { 510 | AGainController_AddRef (thisInterface); 511 | *obj = (void*)((int64_t)instance + pointerOffset); 512 | return Steinberg_kResultTrue; 513 | } 514 | if (compare_iid (Steinberg_Vst_IEditController2_iid, iid)) 515 | { 516 | AGainController_AddRef (thisInterface); 517 | *obj = (void*)((int64_t)instance + (pointerOffset * 2)); 518 | return Steinberg_kResultTrue; 519 | } 520 | *obj = NULL; 521 | return Steinberg_kNoInterface; 522 | } 523 | 524 | Steinberg_tresult SMTG_STDMETHODCALLTYPE AGainController_QueryInterface_ConnectionPoint ( 525 | void* thisInterface, const Steinberg_TUID iid, void** obj) 526 | { 527 | return AGainController_QueryInterface ((void*)((int64_t)thisInterface - pointerOffset), iid, 528 | obj); 529 | } 530 | 531 | Steinberg_tresult SMTG_STDMETHODCALLTYPE AGainController_QueryInterface_EditController2 ( 532 | void* thisInterface, const Steinberg_TUID iid, void** obj) 533 | { 534 | return AGainController_QueryInterface ((void*)((int64_t)thisInterface - (pointerOffset * 2)), 535 | iid, obj); 536 | } 537 | 538 | Steinberg_tresult SMTG_STDMETHODCALLTYPE 539 | AGainController_Initialize (void* thisInterface, struct Steinberg_FUnknown* context) 540 | { 541 | return Steinberg_kResultTrue; 542 | } 543 | 544 | Steinberg_tresult SMTG_STDMETHODCALLTYPE AGainController_Terminate (void* thisInterface) 545 | { 546 | return Steinberg_kNotImplemented; 547 | } 548 | 549 | Steinberg_tresult SMTG_STDMETHODCALLTYPE 550 | AGainController_Connect (void* thisInterface, struct Steinberg_Vst_IConnectionPoint* other) 551 | { 552 | return Steinberg_kNotImplemented; 553 | } 554 | 555 | Steinberg_tresult SMTG_STDMETHODCALLTYPE 556 | AGainController_Disconnect (void* thisInterface, struct Steinberg_Vst_IConnectionPoint* other) 557 | { 558 | return Steinberg_kNotImplemented; 559 | } 560 | 561 | Steinberg_tresult SMTG_STDMETHODCALLTYPE 562 | AGainController_Notify (void* thisInterface, struct Steinberg_Vst_IMessage* message) 563 | { 564 | return Steinberg_kNotImplemented; 565 | } 566 | 567 | Steinberg_tresult SMTG_STDMETHODCALLTYPE 568 | AGainController_SetComponentState (void* thisInterface, struct Steinberg_IBStream* state) 569 | { 570 | return Steinberg_kNotImplemented; 571 | } 572 | 573 | Steinberg_tresult SMTG_STDMETHODCALLTYPE AGainController_SetState (void* thisInterface, 574 | struct Steinberg_IBStream* state) 575 | { 576 | if (state == NULL) 577 | { 578 | return Steinberg_kInvalidArgument; 579 | } 580 | AGainEditController* instance = (AGainEditController*)thisInterface; 581 | return state->lpVtbl->read (state, &instance->gainParam, sizeof (instance->gainParam), NULL); 582 | } 583 | 584 | Steinberg_tresult SMTG_STDMETHODCALLTYPE AGainController_GetState (void* thisInterface, 585 | struct Steinberg_IBStream* state) 586 | { 587 | if (state == NULL) 588 | { 589 | return Steinberg_kInvalidArgument; 590 | } 591 | AGainEditController* instance = (AGainEditController*)thisInterface; 592 | return state->lpVtbl->write (state, &instance->gainParam, sizeof (instance->gainParam), NULL); 593 | } 594 | 595 | Steinberg_int32 SMTG_STDMETHODCALLTYPE AGainController_GetParameterCount (void* thisInterface) 596 | { 597 | return 1; 598 | } 599 | 600 | Steinberg_tresult SMTG_STDMETHODCALLTYPE AGainController_GetParameterInfo ( 601 | void* thisInterface, Steinberg_int32 paramIndex, struct Steinberg_Vst_ParameterInfo* info) 602 | { 603 | info->defaultNormalizedValue = 0; 604 | info->id = 55; 605 | info->stepCount = 0; 606 | info->flags = Steinberg_Vst_ParameterInfo_ParameterFlags_kCanAutomate; 607 | info->defaultNormalizedValue = 0.5f; 608 | info->unitId = Steinberg_Vst_kRootUnitId; 609 | static const Steinberg_char16 title_string[] = {'G', 'a', 'i', 'n'}; 610 | memcpy (info->title, title_string, sizeof (title_string)); 611 | static const Steinberg_char16 units_string[] = {'d', 'B'}; 612 | memcpy (info->units, units_string, sizeof (units_string)); 613 | 614 | return Steinberg_kResultTrue; 615 | } 616 | 617 | Steinberg_Vst_ParamValue SMTG_STDMETHODCALLTYPE AGainController_NormalizedParamToPlain ( 618 | void* thisInterface, Steinberg_Vst_ParamID id, Steinberg_Vst_ParamValue valueNormalized) 619 | { 620 | return 6.02061f + 20 * log10f ((float)valueNormalized); 621 | } 622 | 623 | Steinberg_Vst_ParamValue SMTG_STDMETHODCALLTYPE AGainController_PlainParamToNormalized ( 624 | void* thisInterface, Steinberg_Vst_ParamID id, Steinberg_Vst_ParamValue plainValue) 625 | { 626 | return expf (logf (10.f) * ((float)plainValue - 6.02061f) / 20.f); 627 | } 628 | 629 | Steinberg_tresult SMTG_STDMETHODCALLTYPE AGainController_GetParamStringByValue ( 630 | void* thisInterface, Steinberg_Vst_ParamID id, Steinberg_Vst_ParamValue valueNormalized, 631 | Steinberg_Vst_String128 string) 632 | { 633 | Steinberg_Vst_ParamValue plainValue = 634 | AGainController_NormalizedParamToPlain (thisInterface, id, valueNormalized); 635 | 636 | char buffer[32]; 637 | snprintf (buffer, 31, "%f", plainValue); 638 | buffer[31] = 0; 639 | 640 | char* bufptr = buffer; 641 | while (*bufptr != '\0') 642 | { 643 | *string = *bufptr; 644 | ++string; 645 | ++bufptr; 646 | } 647 | return Steinberg_kResultOk; 648 | } 649 | 650 | Steinberg_tresult SMTG_STDMETHODCALLTYPE AGainController_GetParamValueByString ( 651 | void* thisInterface, Steinberg_Vst_ParamID id, Steinberg_Vst_TChar* string, 652 | Steinberg_Vst_ParamValue* valueNormalized) 653 | { 654 | return Steinberg_kNotImplemented; 655 | } 656 | 657 | Steinberg_Vst_ParamValue SMTG_STDMETHODCALLTYPE 658 | AGainController_GetParamNormalized (void* thisInterface, Steinberg_Vst_ParamID id) 659 | { 660 | AGainEditController* instance = (AGainEditController*)thisInterface; 661 | return instance->gainParam; 662 | } 663 | 664 | Steinberg_tresult SMTG_STDMETHODCALLTYPE AGainController_SetParamNormalized ( 665 | void* thisInterface, Steinberg_Vst_ParamID id, Steinberg_Vst_ParamValue value) 666 | { 667 | AGainEditController* instance = (AGainEditController*)thisInterface; 668 | instance->gainParam = value; 669 | return Steinberg_kResultTrue; 670 | } 671 | 672 | Steinberg_tresult SMTG_STDMETHODCALLTYPE AGainController_SetComponentHandler ( 673 | void* thisInterface, struct Steinberg_Vst_IComponentHandler* handler) 674 | { 675 | return Steinberg_kNotImplemented; 676 | } 677 | 678 | struct Steinberg_IPlugView* SMTG_STDMETHODCALLTYPE 679 | AGainController_CreateView (void* thisInterface, Steinberg_FIDString name) 680 | { 681 | return NULL; 682 | } 683 | 684 | Steinberg_tresult SMTG_STDMETHODCALLTYPE AGainController_SetKnobMode (void* thisInterface, 685 | Steinberg_Vst_KnobMode mode) 686 | { 687 | return Steinberg_kNotImplemented; 688 | } 689 | 690 | Steinberg_tresult SMTG_STDMETHODCALLTYPE AGainController_OpenHelp (void* thisInterface, 691 | Steinberg_TBool onlyCheck) 692 | { 693 | return Steinberg_kNotImplemented; 694 | } 695 | 696 | Steinberg_tresult SMTG_STDMETHODCALLTYPE AGainController_OpenAboutBox (void* thisInterface, 697 | Steinberg_TBool onlyCheck) 698 | { 699 | return Steinberg_kNotImplemented; 700 | } 701 | 702 | static const struct AGainAudioProcessorVtbl kAGainAudioProcessorVtbl = { 703 | {AGainProcessor_QueryInterface, AGainProcessor_AddRef, AGainProcessor_Release, 704 | AGainProcessor_Initialize, AGainProcessor_Terminate, AGainProcessor_GetControllerClassId, 705 | AGainProcessor_SetIoMode, AGainProcessor_GetBusCount, AGainProcessor_GetBusInfo, 706 | AGainProcessor_GetRoutingInfo, AGainProcessor_ActivateBus, AGainProcessor_SetActive, 707 | AGainProcessor_SetState, AGainProcessor_GetState}, 708 | {AGainProcessor_QueryInterface_ConnectionPoint, AGainProcessor_AddRef_ConnectionPoint, 709 | AGainProcessor_Release_ConnectionPoint, AGainProcessor_Connect, AGainProcessor_Disconnect, 710 | AGainProcessor_Notify}, 711 | {AGainProcessor_QueryInterface_AudioProcessor, AGainProcessor_AddRef_AudioProcessor, 712 | AGainProcessor_Release_AudioProcessor, AGainProcessor_SetBusArrangements, 713 | AGainProcessor_GetBusArrangement, AGainProcessor_CanProcessSampleSize, 714 | AGainProcessor_GetLatencySamples, AGainProcessor_SetupProcessing, AGainProcessor_SetProcessing, 715 | AGainProcessor_Process, AGainProcessor_GetTailSamples}, 716 | {AGainProcessor_QueryInterface_ProcessContextRequirements, 717 | AGainProcessor_AddRef_ProcessContextRequirements, 718 | AGainProcessor_Release_ProcessContextRequirements, 719 | AGainProcessor_getProcessContextRequirements}, 720 | }; 721 | 722 | static const struct AGainEditControllerVtbl kAGainEditControllerVtbl = { 723 | {AGainController_QueryInterface, AGainController_AddRef, AGainController_Release, 724 | AGainController_Initialize, AGainController_Terminate, AGainController_SetComponentState, 725 | AGainController_SetState, AGainController_GetState, AGainController_GetParameterCount, 726 | AGainController_GetParameterInfo, AGainController_GetParamStringByValue, 727 | AGainController_GetParamValueByString, AGainController_NormalizedParamToPlain, 728 | AGainController_PlainParamToNormalized, AGainController_GetParamNormalized, 729 | AGainController_SetParamNormalized, AGainController_SetComponentHandler, 730 | AGainController_CreateView}, 731 | {AGainController_QueryInterface_ConnectionPoint, AGainController_AddRef_ConnectionPoint, 732 | AGainController_Release_ConnectionPoint, AGainController_Connect, AGainController_Disconnect, 733 | AGainController_Notify}, 734 | {AGainController_QueryInterface_EditController2, AGainController_AddRef_EditController2, 735 | AGainController_Release_EditController2, AGainController_SetKnobMode, AGainController_OpenHelp, 736 | AGainController_OpenAboutBox}}; 737 | 738 | /* methods derived from "Steinberg_FUnknown": */ 739 | Steinberg_uint32 SMTG_STDMETHODCALLTYPE AGainFactory_AddRef (void* thisInterface) 740 | { 741 | return 100; 742 | } 743 | 744 | Steinberg_uint32 SMTG_STDMETHODCALLTYPE AGainFactory_Release (void* thisInterface) 745 | { 746 | return 100; 747 | } 748 | 749 | Steinberg_tresult SMTG_STDMETHODCALLTYPE AGainFactory_QueryInterface (void* thisInterface, 750 | const Steinberg_TUID iid, 751 | void** obj) 752 | { 753 | if (compare_iid (iid, Steinberg_FUnknown_iid)) 754 | { 755 | AGainFactory_AddRef (thisInterface); 756 | *obj = thisInterface; 757 | return Steinberg_kResultTrue; 758 | } 759 | if (compare_iid (iid, Steinberg_IPluginFactory_iid)) 760 | { 761 | AGainFactory_AddRef (thisInterface); 762 | *obj = thisInterface; 763 | return Steinberg_kResultTrue; 764 | } 765 | if (compare_iid (iid, Steinberg_IPluginFactory2_iid)) 766 | { 767 | AGainFactory_AddRef (thisInterface); 768 | *obj = thisInterface; 769 | return Steinberg_kResultTrue; 770 | } 771 | *obj = NULL; 772 | return Steinberg_kNoInterface; 773 | } 774 | 775 | /* methods derived from "Steinberg_IPluginFactory": */ 776 | Steinberg_tresult SMTG_STDMETHODCALLTYPE 777 | AGainFactory_GetFactoryInfo (void* thisInterface, struct Steinberg_PFactoryInfo* info) 778 | { 779 | if (info == 0) 780 | { 781 | return Steinberg_kInvalidArgument; 782 | } 783 | AGainFactory* factory = (AGainFactory*)thisInterface; 784 | memcpy (info, &factory->factoryInfo, sizeof (struct Steinberg_PFactoryInfo)); 785 | return Steinberg_kResultTrue; 786 | } 787 | 788 | Steinberg_int32 SMTG_STDMETHODCALLTYPE AGainFactory_CountClasses (void* thisInterface) 789 | { 790 | return 2; 791 | } 792 | 793 | Steinberg_tresult SMTG_STDMETHODCALLTYPE AGainFactory_GetClassInfo ( 794 | void* thisInterface, Steinberg_int32 index, struct Steinberg_PClassInfo* info) 795 | { 796 | return Steinberg_kNotImplemented; 797 | } 798 | 799 | Steinberg_tresult SMTG_STDMETHODCALLTYPE AGainFactory_CreateInstance (void* thisInterface, 800 | Steinberg_FIDString cid, 801 | Steinberg_FIDString iid, 802 | void** obj) 803 | { 804 | AGainFactory* factory = (AGainFactory*)thisInterface; 805 | if (compare_iid (cid, factory->classes[0].cid)) 806 | { 807 | AGainAudioProcessor* instance = (AGainAudioProcessor*)malloc (sizeof (AGainAudioProcessor)); 808 | instance->componentVtbl = &kAGainAudioProcessorVtbl.component; 809 | instance->connectionPointVtbl = &kAGainAudioProcessorVtbl.connectionPoint; 810 | instance->audioProcessorVtbl = &kAGainAudioProcessorVtbl.audioProcessor; 811 | instance->processContextRequirementsVtbl = 812 | &kAGainAudioProcessorVtbl.processContextRequirements; 813 | instance->refCount = 0; 814 | instance->connectionPoint = NULL; 815 | instance->fGain = 0.5f; 816 | return instance->componentVtbl->queryInterface (instance, iid, obj); 817 | } 818 | if (compare_iid (cid, factory->classes[1].cid)) 819 | { 820 | AGainEditController* instance = (AGainEditController*)malloc (sizeof (AGainEditController)); 821 | instance->editControllerVtbl = &kAGainEditControllerVtbl.editController; 822 | instance->connectionPointVtbl = &kAGainEditControllerVtbl.connectionPoint; 823 | instance->editController2Vtbl = &kAGainEditControllerVtbl.editController2; 824 | instance->refCount = 0; 825 | instance->gainParam = 0.5f; 826 | *obj = instance; 827 | return instance->editControllerVtbl->queryInterface (instance, iid, obj); 828 | } 829 | return Steinberg_kResultFalse; 830 | } 831 | 832 | /* methods defined in "Steinberg_IPluginFactory2": */ 833 | Steinberg_tresult SMTG_STDMETHODCALLTYPE AGainFactory_GetClassInfo2 ( 834 | void* thisInterface, Steinberg_int32 index, struct Steinberg_PClassInfo2* info) 835 | { 836 | if (index > 1 || info == 0) 837 | { 838 | return Steinberg_kInvalidArgument; 839 | } 840 | AGainFactory* factory = (AGainFactory*)thisInterface; 841 | memcpy (info, &factory->classes[index], sizeof (struct Steinberg_PClassInfo2)); 842 | return Steinberg_kResultTrue; 843 | } 844 | 845 | static const struct AGainFactoryVtbl kAGainPluginFactoryVtbl = { 846 | {AGainFactory_QueryInterface, AGainFactory_AddRef, AGainFactory_Release, 847 | AGainFactory_GetFactoryInfo, AGainFactory_CountClasses, AGainFactory_GetClassInfo, 848 | AGainFactory_CreateInstance, AGainFactory_GetClassInfo2}}; 849 | 850 | #ifndef SMTG_EXPORT_SYMBOL 851 | #if __APPLE__ 852 | #define SMTG_EXPORT_SYMBOL __attribute__ ((visibility ("default"))) 853 | #else 854 | #define SMTG_EXPORT_SYMBOL __declspec (dllexport) 855 | #endif 856 | #endif // SMTG_EXPORT_SYMBOL 857 | 858 | SMTG_EXPORT_SYMBOL Steinberg_IPluginFactory* SMTG_STDMETHODCALLTYPE GetPluginFactory () 859 | { 860 | static AGainFactory againFactory; 861 | static int32_t once = 1; 862 | if (once) 863 | { 864 | once = 0; 865 | 866 | againFactory.pluginFactoryVtbl = &kAGainPluginFactoryVtbl.pluginFactory; 867 | 868 | strcpy (againFactory.factoryInfo.vendor, "Steinberg"); 869 | strcpy (againFactory.factoryInfo.email, "info@steinberg.net"); 870 | strcpy (againFactory.factoryInfo.url, "steinberg.net"); 871 | againFactory.factoryInfo.flags = 16; 872 | 873 | memcpy (againFactory.classes[0].cid, audioProcessorUID, sizeof (Steinberg_TUID)); 874 | againFactory.classes[0].cardinality = Steinberg_PClassInfo_ClassCardinality_kManyInstances; 875 | strcpy (againFactory.classes[0].category, "Audio Module Class"); 876 | strcpy (againFactory.classes[0].name, "C-AGain"); 877 | againFactory.classes[0].classFlags = Steinberg_Vst_ComponentFlags_kDistributable; 878 | strcpy (againFactory.classes[0].subCategories, "Fx"); 879 | strcpy (againFactory.classes[0].vendor, "Steinberg"); 880 | strcpy (againFactory.classes[0].version, "1.0.0"); 881 | strcpy (againFactory.classes[0].sdkVersion, "3.7.6"); 882 | 883 | memcpy (againFactory.classes[1].cid, editControllerUID, sizeof (Steinberg_TUID)); 884 | againFactory.classes[1].cardinality = Steinberg_PClassInfo_ClassCardinality_kManyInstances; 885 | strcpy (againFactory.classes[1].category, "Component Controller Class"); 886 | strcpy (againFactory.classes[1].name, "C-AGain"); 887 | againFactory.classes[1].classFlags = Steinberg_Vst_ComponentFlags_kDistributable; 888 | strcpy (againFactory.classes[1].subCategories, "Fx"); 889 | strcpy (againFactory.classes[1].vendor, "Steinberg"); 890 | strcpy (againFactory.classes[1].version, "1.0.0"); 891 | strcpy (againFactory.classes[1].sdkVersion, "3.7.6"); 892 | } 893 | 894 | return (Steinberg_IPluginFactory*)&againFactory; 895 | } 896 | 897 | #if __APPLE__ 898 | 899 | SMTG_EXPORT_SYMBOL Steinberg_TBool bundleEntry (void* bundleRef) 900 | { 901 | return 1; 902 | } 903 | SMTG_EXPORT_SYMBOL Steinberg_TBool bundleExit (void* bundleRef) 904 | { 905 | return 1; 906 | } 907 | 908 | #else 909 | 910 | SMTG_EXPORT_SYMBOL Steinberg_TBool InitDll () 911 | { 912 | return 1; 913 | } 914 | 915 | SMTG_EXPORT_SYMBOL Steinberg_TBool ExitDll () 916 | { 917 | return 1; 918 | } 919 | 920 | #endif // __APPLE__ 921 | -------------------------------------------------------------------------------- /generate_header/generate_header.c: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------------- 2 | // This file is part of a Steinberg SDK. It is subject to the license terms 3 | // in the LICENSE file found in the top-level directory of this distribution 4 | // and at www.steinberg.net/sdklicenses. 5 | // No part of the SDK, including this file, may be copied, modified, propagated, 6 | // or distributed except according to the terms contained in the LICENSE file. 7 | //----------------------------------------------------------------------------- 8 | 9 | int main() { 10 | return 0; 11 | } -------------------------------------------------------------------------------- /generate_header/scripts/.gitignore: -------------------------------------------------------------------------------- 1 | /.venv/ 2 | *.pyc 3 | -------------------------------------------------------------------------------- /generate_header/scripts/clang_helpers.py: -------------------------------------------------------------------------------- 1 | # ----------------------------------------------------------------------------- 2 | # This file is part of a Steinberg SDK. It is subject to the license terms 3 | # in the LICENSE file found in the top-level directory of this distribution 4 | # and at www.steinberg.net/sdklicenses. 5 | # No part of the SDK, including this file, may be copied, modified, propagated, 6 | # or distributed except according to the terms contained in the LICENSE file. 7 | # ----------------------------------------------------------------------------- 8 | 9 | from pathlib import Path 10 | from typing import List 11 | 12 | import clang 13 | from clang.cindex import CursorKind, TypeKind, Cursor, Type 14 | # noinspection PyProtectedMember 15 | from clang.cindex import TokenGroup as TGroup 16 | 17 | 18 | def set_library_path(): 19 | if clang.cindex.Config.library_path: 20 | return 21 | libclang_path = Path(clang.__file__).parent / 'native' 22 | clang.cindex.Config.set_library_path(str(libclang_path)) 23 | 24 | 25 | def create_translation_unit(header_path: Path, include_path: str, clang_args: [List[str]] = None) -> Type: 26 | set_library_path() 27 | args = ['-I', include_path, '-x', 'c++-header'] 28 | if clang_args: 29 | args.extend(clang_args) 30 | return clang.cindex.Index.create().parse(header_path, args) 31 | 32 | 33 | def is_kind(cursor_or_type: [Cursor, Type], kind: str) -> bool: 34 | if type(cursor_or_type) == Cursor: 35 | kind_class = CursorKind 36 | else: 37 | kind_class = TypeKind 38 | return cursor_or_type.kind == kind_class.__dict__.get(kind, None) 39 | 40 | 41 | def is_not_kind(cursor_or_type: [Cursor, Type], kind: str) -> bool: 42 | return not is_kind(cursor_or_type, kind) 43 | 44 | 45 | def is_valid(cursor_type: Type) -> bool: 46 | return is_not_kind(cursor_type, 'INVALID') 47 | 48 | 49 | TokenGroup = TGroup 50 | -------------------------------------------------------------------------------- /generate_header/scripts/data_classes.py: -------------------------------------------------------------------------------- 1 | #----------------------------------------------------------------------------- 2 | # This file is part of a Steinberg SDK. It is subject to the license terms 3 | # in the LICENSE file found in the top-level directory of this distribution 4 | # and at www.steinberg.net/sdklicenses. 5 | # No part of the SDK, including this file, may be copied, modified, propagated, 6 | # or distributed except according to the terms contained in the LICENSE file. 7 | #----------------------------------------------------------------------------- 8 | 9 | from typing import List 10 | from typing import Union as UnionType 11 | 12 | 13 | class Container(list): 14 | def __contains__(self, name: str) -> bool: 15 | for element in self: 16 | if element.name == name: 17 | return True 18 | return False 19 | 20 | def __getitem__(self, name_or_index: UnionType[str, int, slice]): 21 | if type(name_or_index) != str: 22 | return super().__getitem__(name_or_index) 23 | for element in self: 24 | if element.name == name_or_index: 25 | return element 26 | return None 27 | 28 | 29 | class Base: 30 | def __init__(self, name: str = None, source_location: str = None): 31 | self._name = name 32 | self._source_location = source_location 33 | 34 | @property 35 | def name(self) -> str: 36 | return self._name 37 | 38 | @property 39 | def source_location(self) -> str: 40 | return self._source_location 41 | 42 | 43 | class Enum(Base): 44 | def __init__(self, name: str, source_location: str): 45 | super().__init__(name, source_location) 46 | self._enumerators = [] 47 | 48 | @property 49 | def enumerators(self) -> List[str]: 50 | return self._enumerators 51 | 52 | def add_enumerator(self, name, expression): 53 | enumerator = name 54 | if expression: 55 | enumerator += f' = {expression}' 56 | self._enumerators.append(enumerator) 57 | 58 | 59 | class Interface(Base): 60 | def __init__(self, name: str, source_location: str, description: str): 61 | super().__init__(name, source_location) 62 | self._description = description 63 | self._base_classes = [] 64 | self._methods = [] 65 | self._iid = None 66 | 67 | @property 68 | def description(self) -> str: 69 | return self._description 70 | 71 | @property 72 | def methods(self) -> List[str]: 73 | return self._methods 74 | 75 | @property 76 | def base_classes(self) -> List['Interface']: 77 | result = [] 78 | for base_class in self._base_classes: 79 | for base_base_class in base_class.base_classes: 80 | if base_base_class not in result: 81 | result.append(base_base_class) 82 | if base_class not in result: 83 | result.append(base_class) 84 | return result 85 | 86 | @property 87 | def iid(self) -> str: 88 | return self._iid 89 | 90 | # noinspection SpellCheckingInspection 91 | def add_method(self, name: str, return_type: str, args: List[str]): 92 | method = f'{return_type} (SMTG_STDMETHODCALLTYPE* {name}) (void* thisInterface' 93 | if args: 94 | method += ', ' + ', '.join(args) 95 | method += ');' 96 | self._methods.append(method) 97 | 98 | def add_base_class(self, base_interface: 'Interface'): 99 | self._base_classes.append(base_interface) 100 | 101 | def set_iid(self, token1, token2, token3, token4): 102 | self._iid = 'static const Steinberg_TUID {}_iid = SMTG_INLINE_UID ({}, {}, {}, {});'.format(self.name, token1, token2, 103 | token3, token4) 104 | 105 | 106 | class Struct(Base): 107 | def __init__(self, name: str, source_location: str): 108 | super().__init__(name, source_location) 109 | self._members = [] 110 | 111 | @property 112 | def members(self): 113 | return self._members 114 | 115 | def add_member(self, member): 116 | self._members.append(member) 117 | 118 | 119 | class Variable(Base): 120 | def __init__(self, name: str, value_type: str, value: str): 121 | super().__init__(name) 122 | self._value_type = value_type 123 | self._value = value 124 | 125 | def __str__(self): 126 | return f'static {self._value_type} {self.name} = {self._value};' 127 | 128 | 129 | class Union(Base): 130 | def __init__(self, parent: str): 131 | super().__init__(parent) 132 | self._members = [] 133 | 134 | @property 135 | def members(self): 136 | return self._members 137 | 138 | def add_member(self, member): 139 | self._members.append(member) 140 | 141 | 142 | class Typedef(Base): 143 | def __init__(self, name: str, return_type: str): 144 | super().__init__(name) 145 | self._return_type = return_type 146 | 147 | def __str__(self): 148 | return f'typedef {self._return_type} {self.name};' 149 | -------------------------------------------------------------------------------- /generate_header/scripts/file_string.py: -------------------------------------------------------------------------------- 1 | #----------------------------------------------------------------------------- 2 | # This file is part of a Steinberg SDK. It is subject to the license terms 3 | # in the LICENSE file found in the top-level directory of this distribution 4 | # and at www.steinberg.net/sdklicenses. 5 | # No part of the SDK, including this file, may be copied, modified, propagated, 6 | # or distributed except according to the terms contained in the LICENSE file. 7 | #----------------------------------------------------------------------------- 8 | 9 | class FileString(str): 10 | def __new__(cls, content=''): 11 | return super().__new__(cls, content) 12 | 13 | def __truediv__(self, key): 14 | return FileString(self + key + '\n') 15 | -------------------------------------------------------------------------------- /generate_header/scripts/generate_header_compilation.py: -------------------------------------------------------------------------------- 1 | #----------------------------------------------------------------------------- 2 | # This file is part of a Steinberg SDK. It is subject to the license terms 3 | # in the LICENSE file found in the top-level directory of this distribution 4 | # and at www.steinberg.net/sdklicenses. 5 | # No part of the SDK, including this file, may be copied, modified, propagated, 6 | # or distributed except according to the terms contained in the LICENSE file. 7 | #----------------------------------------------------------------------------- 8 | 9 | import sys 10 | from datetime import date 11 | from pathlib import Path 12 | 13 | from jinja2 import Environment, FileSystemLoader 14 | 15 | 16 | # noinspection SpellCheckingInspection 17 | def _generate_header(pluginterfaces_path, result_path): 18 | blocklist = ['ivsttestplugprovider.h'] 19 | pluginterfaces_includes = [] 20 | for file in ['gui/iplugviewcontentscalesupport.h', 'gui/iplugview.h', 'base/ibstream.h']: 21 | pluginterfaces_includes.append(file) 22 | for file in (pluginterfaces_path / 'vst').iterdir(): 23 | if file.name in blocklist: 24 | continue 25 | pluginterfaces_includes.append('vst/{}'.format(file.name)) 26 | env = Environment(loader=FileSystemLoader(Path(__file__).parent / 'templates'), trim_blocks=True) 27 | template = env.get_template(result_path.name) 28 | file_name = result_path.relative_to(result_path.parents[2]) 29 | today = date.today().strftime("%m/%Y") 30 | content = template.render(file_name=file_name, date=today, pluginterfaces_includes=pluginterfaces_includes) 31 | with result_path.open('w') as result_file: 32 | result_file.write(content) 33 | return content 34 | 35 | 36 | # noinspection SpellCheckingInspection 37 | def main(): 38 | if len(sys.argv) < 2: 39 | print('Pluginterfaces source directory was not specified!') 40 | exit(1) 41 | pluginterfaces_path = Path(sys.argv[1]) 42 | result_path = pluginterfaces_path / 'vst' / 'header_compilation.h' 43 | print(_generate_header(pluginterfaces_path, result_path)) 44 | 45 | 46 | if __name__ == '__main__': 47 | main() 48 | -------------------------------------------------------------------------------- /generate_header/scripts/interface_convert.py: -------------------------------------------------------------------------------- 1 | #----------------------------------------------------------------------------- 2 | # This file is part of a Steinberg SDK. It is subject to the license terms 3 | # in the LICENSE file found in the top-level directory of this distribution 4 | # and at www.steinberg.net/sdklicenses. 5 | # No part of the SDK, including this file, may be copied, modified, propagated, 6 | # or distributed except according to the terms contained in the LICENSE file. 7 | #----------------------------------------------------------------------------- 8 | 9 | """ 10 | Documentation 11 | ------------------------------------------------------------------------------------------------------------------------ 12 | 13 | This script interprets C++-based COM header files and converts its main structures, that is interfaces, 14 | structs, unions, enums, typedefs and variable declarations into respective C-compatible variants. 15 | The results are assembled into a newly created header file which thus inherits the basic functionality 16 | of its original counterpart. 17 | 18 | This conversion is facilitated by the Libclang python bindings library which ports the main functions 19 | of the Clang compiler to python. Using this compiler, the translation unit of the original header file 20 | is established, an abstract syntax tree of nested cursor and token objects which represent the structure 21 | of the original file in an easily accessible way. These objects each contain data about their inherent 22 | characteristics which is selectively parsed and stored for later use when recreating the interfaces. 23 | 24 | The script is broken up into several smaller functions which can be sorted into three main categories, 25 | parsing functions, utility functions and generator functions. Parsing functions interpret the incoming 26 | cursor objects and sort the relevant data into various arrays, aided by the utility functions which 27 | mainly serve to reduce bloat and increase human readability by packaging commonly occurring 28 | structures into short expressions. The generator functions access the previously stored data 29 | to assemble a new C-compatible header file. 30 | 31 | The data storage is based on component-specific classes which serve to house and return the respective 32 | information, with one instance being created for each individual component that is parsed. They are 33 | then arranged in a storage structure which facilitates sequential access to the individual instances of 34 | each class, the return of class-specific data based on its name or a given extent and provides access 35 | to all stored names, approximating the functionality of a list. 36 | 37 | To function properly, the script must be supplied with the original C++ header file, as well as a 38 | working directory that houses all other files this header includes, as these will not be 39 | recognised otherwise. 40 | 41 | ------------------------------------------------------------------------------------------------------------------------ 42 | """ 43 | 44 | # ---------------------------------------------------------------------------------------------------------------------- 45 | # ----- script begin --------------------------------------------------------------------------------------------------- 46 | # ---------------------------------------------------------------------------------------------------------------------- 47 | 48 | # library import statements 49 | 50 | import re 51 | import sys 52 | from argparse import ArgumentParser, REMAINDER 53 | from pathlib import Path 54 | from typing import List 55 | from clang.cindex import SourceLocation, Cursor, Type 56 | from clang_helpers import create_translation_unit, TokenGroup, is_not_kind, is_valid, is_kind 57 | from data_classes import Enum, Container, Interface, Struct, Variable, Union, Typedef 58 | 59 | 60 | # ---------------------------------------------------------------------------------------------------------------------- 61 | # ----- parsing functions ---------------------------------------------------------------------------------------------- 62 | # ---------------------------------------------------------------------------------------------------------------------- 63 | 64 | 65 | def parse_header(cursor: Cursor): 66 | """excludes unusable parts and executes parse functions""" 67 | if is_not_kind(cursor, 'TRANSLATION_UNIT'): 68 | return 69 | root_path = normalise_link(str(Path(cursor.spelling).parents[2])) 70 | already_parsed_includes = [] 71 | for cursor_child in cursor.get_children(): 72 | cursor_child_location = normalise_link(cursor_child.location.file.name) 73 | if not cursor_child_location.startswith(root_path) or cursor_child_location in already_parsed_includes: 74 | continue 75 | already_parsed_includes.append(cursor_child_location) 76 | if parse_namespace(cursor_child): 77 | continue 78 | parsing(cursor_child) 79 | 80 | 81 | def parse_namespace(cursor: Cursor, namespace: str = '') -> bool: 82 | """recursively parses namespaces and executes parse functions""" 83 | if is_not_kind(cursor, 'NAMESPACE'): 84 | return False 85 | if namespace: 86 | namespace += '::' 87 | namespace += cursor.spelling 88 | for cursor_child in cursor.get_children(): 89 | if parse_namespace(cursor_child, namespace): 90 | continue 91 | parsing(cursor_child, namespace) 92 | return True 93 | 94 | 95 | def parsing(cursor: Cursor, namespace: str = ''): 96 | """executes specific parse functions""" 97 | parse_interfaces(cursor) 98 | parse_enum(cursor) 99 | parse_structs(cursor) 100 | parse_iid(cursor, namespace) 101 | store_typedefs(cursor, typedefs) 102 | parse_variables(cursor) 103 | 104 | 105 | # ----- parse typedefs ------------------------------------------------------------------------------------------------- 106 | 107 | def store_typedefs(cursor, typedef_list: Container): 108 | """executes typedef parse and stores value""" 109 | return_type, name = parse_typedefs(cursor) 110 | if return_type and name: 111 | typedef_list.append(Typedef(name, return_type)) 112 | 113 | 114 | # noinspection SpellCheckingInspection 115 | def parse_typedefs(cursor): 116 | """parses typedefs and formats output""" 117 | if is_not_kind(cursor, 'TYPEDEF_DECL') and is_not_kind(cursor, 'TYPE_ALIAS_DECL'): 118 | return None, None 119 | if is_kind(cursor.underlying_typedef_type, 'CONSTANTARRAY'): 120 | return_type = cursor.underlying_typedef_type.element_type 121 | name_string = '{}[{}]'.format(convert_type(cursor.type), cursor.underlying_typedef_type.element_count) 122 | else: 123 | return_type = cursor.underlying_typedef_type 124 | name_string = convert_cursor(cursor) 125 | return create_struct_prefix(return_type) + convert_type(return_type), name_string 126 | 127 | 128 | # ----- parse interfaces ----------------------------------------------------------------------------------------------- 129 | 130 | # noinspection SpellCheckingInspection 131 | def parse_interfaces(cursor): 132 | """executes all specific interface-related parse functions and stores information""" 133 | if is_not_kind(cursor, 'CLASS_DECL') or cursor.spelling in blocklist: 134 | return 135 | children = list(cursor.get_children()) 136 | if not children: 137 | return 138 | interface = Interface(convert_cursor(cursor), get_cursor_location(cursor.location), cursor.brief_comment) 139 | for cursor_child in children: 140 | store_typedefs(cursor_child, interface_typedefs) 141 | parse_enum(cursor_child) 142 | parse_inheritance(cursor_child, interface) 143 | parse_variables(cursor_child) 144 | parse_methods(cursor_child, interface) 145 | interfaces.append(interface) 146 | 147 | 148 | def parse_inheritance(cursor: Cursor, interface: Interface): 149 | """parses and stores information about interface inheritance""" 150 | if is_not_kind(cursor, 'CXX_BASE_SPECIFIER'): 151 | return 152 | base_interface_name = '' 153 | if is_kind(cursor.type, 'ELABORATED'): 154 | base_interface_name = create_namespace_prefix_for_type(cursor.type) 155 | base_interface_name += convert_namespace(cursor.type.spelling) 156 | if base_interface_name in interfaces: 157 | interface.add_base_class(interfaces[base_interface_name]) 158 | 159 | 160 | # ----- parse IIDs ----------------------------------------------------------------------------------------------------- 161 | 162 | # noinspection SpellCheckingInspection 163 | def parse_iid(cursor: Cursor, namespace: str): 164 | """parses and stores IIDs of interfaces""" 165 | if is_not_kind(cursor, 'VAR_DECL') or not cursor.spelling.endswith('_iid'): 166 | return 167 | id_tokens = get_token_spellings_from_extent(cursor) 168 | interface_name = convert_namespace(namespace) 169 | if interface_name: 170 | interface_name += '_' 171 | interface_name += id_tokens[2] 172 | if interface_name in interfaces: 173 | interfaces[interface_name].set_iid(id_tokens[4], id_tokens[6], id_tokens[8], id_tokens[10]) 174 | 175 | 176 | def get_token_spellings_from_extent(cursor: Cursor) -> List[str]: 177 | """uses tokens to return IID spellings as string""" 178 | cursor_tu = cursor.translation_unit 179 | extent = cursor_tu.get_extent(cursor.location.file.name, [cursor.extent.start.offset, cursor.extent.end.offset]) 180 | return [token.spelling for token in TokenGroup.get_tokens(cursor_tu, extent)] 181 | 182 | 183 | # ----- parse methods -------------------------------------------------------------------------------------------------- 184 | 185 | def parse_methods(cursor: Cursor, interface: Interface): 186 | """executes method argument parse function and stores returned string""" 187 | if is_not_kind(cursor, 'CXX_METHOD'): 188 | return 189 | method_name = cursor.spelling 190 | method_return_type = create_struct_prefix(cursor.result_type) + convert_type(cursor.result_type) 191 | method_args = _parse_method_arguments(cursor) 192 | interface.add_method(method_name, method_return_type, method_args) 193 | 194 | 195 | def _parse_method_arguments(cursor: Cursor) -> List[str]: 196 | """parses method arguments and returns formatted string""" 197 | result = [] 198 | for cursor_child in cursor.get_arguments(): 199 | argument_type = create_struct_prefix(cursor_child.type) + convert_type(cursor_child.type) 200 | name = _convert_method_args_name(cursor_child.spelling) 201 | result.append(f'{argument_type} {name}') 202 | return result 203 | 204 | 205 | def _convert_method_args_name(source: str) -> str: 206 | """specific conversion case, not otherwise covered by functions""" 207 | if source == '_iid': 208 | return 'iid' 209 | return source 210 | 211 | 212 | # ----- specific parse functions --------------------------------------------------------------------------------------- 213 | 214 | # noinspection SpellCheckingInspection 215 | def parse_variables(cursor): 216 | """parses and stores variable definition information""" 217 | if is_not_kind(cursor, 'VAR_DECL') or ( 218 | is_not_kind(cursor.type, 'ELABORATED') and is_not_kind(cursor.type, 'TYPEDEF')): 219 | return 220 | if is_kind(cursor.type, 'ELABORATED') and (cursor.displayname == 'iid' or 221 | cursor.displayname.endswith('_iid') or is_kind( 222 | cursor.type.get_canonical(), 'RECORD')): 223 | return 224 | variable_value = _visit_children(list(cursor.get_children())[-1]) 225 | variables.append(Variable(convert_cursor(cursor), convert_type(cursor.type), variable_value)) 226 | 227 | 228 | # noinspection SpellCheckingInspection 229 | def parse_structs(cursor): 230 | """parses, formats and stores struct information, executes union parse function""" 231 | if is_not_kind(cursor, 'STRUCT_DECL') or cursor.spelling in blocklist: 232 | return 233 | children = list(cursor.get_children()) 234 | if not children: 235 | # this is only a forward declaration 236 | return 237 | fields = [] 238 | for cursor_child in children: 239 | parse_union(convert_cursor(cursor), cursor_child) 240 | if parse_enum(cursor_child) or is_not_kind(cursor_child, 'FIELD_DECL'): 241 | continue 242 | cursor_child_type = cursor_child.type 243 | struct_args = '' 244 | if is_kind(cursor_child.type, 'CONSTANTARRAY'): 245 | cursor_child_type = cursor_child_type.element_type 246 | struct_args = _visit_children(list(cursor_child.get_children())[-1]) 247 | struct_return = create_struct_prefix(cursor_child_type) + convert_type(cursor_child_type) 248 | field = f'{struct_return} {cursor_child.spelling};' 249 | if struct_args: 250 | field = field[:-1] + f'[{struct_args}];' 251 | fields.append(field) 252 | if fields: 253 | struct = Struct(convert_cursor(cursor), get_cursor_location(cursor.location)) 254 | for field in fields: 255 | struct.add_member(field) 256 | structs.append(struct) 257 | 258 | 259 | # noinspection SpellCheckingInspection 260 | def parse_union(parent, cursor): 261 | """parses and stores union information within a struct""" 262 | if is_not_kind(cursor, 'UNION_DECL') or cursor.spelling in blocklist: 263 | return 264 | children = list(cursor.get_children()) 265 | if not children: 266 | # this is only a forward declaration 267 | return 268 | union = Union(parent) 269 | for cursor_child in children: 270 | if is_not_kind(cursor_child, 'FIELD_DECL'): 271 | continue 272 | member_return_type = create_struct_prefix(cursor_child.type) + convert_type(cursor_child.type) 273 | union.add_member('{} {}'.format(member_return_type, convert_cursor(cursor_child))) 274 | unions.append(union) 275 | 276 | 277 | # noinspection SpellCheckingInspection 278 | def parse_enum(cursor: Cursor) -> bool: 279 | """parses and stores enum information""" 280 | if is_not_kind(cursor, 'ENUM_DECL'): 281 | return False 282 | if not cursor.spelling or cursor.spelling.startswith('(unnamed enum'): 283 | return True 284 | enum = Enum(convert_cursor(cursor), get_cursor_location(cursor.location)) 285 | for cursor_child in cursor.get_children(): 286 | if is_not_kind(cursor_child, 'ENUM_CONSTANT_DECL'): 287 | continue 288 | enumerator_name = create_namespace_prefix(cursor_child) + cursor_child.spelling 289 | enumerator_expression = _visit_children(cursor_child, use_definitions=False) 290 | enum.add_enumerator(enumerator_name, enumerator_expression) 291 | enums.append(enum) 292 | return True 293 | 294 | 295 | # ---------------------------------------------------------------------------------------------------------------------- 296 | # ----- utility functions ---------------------------------------------------------------------------------------------- 297 | # ---------------------------------------------------------------------------------------------------------------------- 298 | 299 | 300 | def _get_binary_operator(cursor: Cursor, children: List[Cursor]) -> str: 301 | """returns token spelling after passing extent of first cursor child""" 302 | child_tokens = list(children[0].get_tokens()) 303 | if not child_tokens: 304 | raise Exception('No tokens found') 305 | child_extent_length = children[0].extent.end.offset - children[0].extent.start.offset 306 | child_extent_end = child_tokens[0].extent.start.offset + child_extent_length 307 | for token in cursor.get_tokens(): 308 | if token.extent.start.offset < child_extent_end: 309 | continue 310 | return token.spelling 311 | return '' 312 | 313 | 314 | # noinspection SpellCheckingInspection 315 | def _visit_children(cursor: Cursor, use_definitions: bool = True) -> str: 316 | """analyses cursor children, formats and returns string based on CursorKind""" 317 | if not list(cursor.get_tokens()): 318 | cursor_tokens = get_token_spellings_from_extent(cursor) 319 | if len(cursor_tokens) == 1: 320 | return cursor_tokens[0] 321 | children = list(cursor.get_children()) 322 | if is_kind(cursor, 'BINARY_OPERATOR'): 323 | operator = _get_binary_operator(cursor, children) 324 | return '{} {} {}'.format(_visit_children(children[0], use_definitions), operator, 325 | _visit_children(children[1], use_definitions)) 326 | elif is_kind(cursor, 'PAREN_EXPR'): 327 | return '({})'.format(_visit_children(children[0], use_definitions)) 328 | elif is_kind(cursor, 'UNARY_OPERATOR'): 329 | operator = list(cursor.get_tokens())[0].spelling 330 | return '{}{}'.format(operator, _visit_children(children[0], use_definitions)) 331 | elif is_kind(cursor, 'DECL_REF_EXPR'): 332 | if use_definitions: 333 | return _visit_children(cursor.get_definition(), use_definitions) 334 | else: 335 | return convert_cursor(cursor) 336 | elif is_kind(cursor, 'UNEXPOSED_EXPR') or is_kind(cursor, 'ENUM_CONSTANT_DECL'): 337 | if children: 338 | return _visit_children(children[0], use_definitions) 339 | return '' 340 | elif is_kind(cursor, 'VAR_DECL'): 341 | return _visit_children(children[-1], use_definitions) 342 | elif is_kind(cursor, 'CSTYLE_CAST_EXPR') or is_kind(cursor, 'CXX_FUNCTIONAL_CAST_EXPR')\ 343 | or is_kind(cursor, "CXX_STATIC_CAST_EXPR"): 344 | return '({}) {}'.format(convert_namespace(children[0].spelling), _visit_children(children[1]), use_definitions) 345 | elif is_kind(cursor, 'INTEGER_LITERAL') or is_kind(cursor, 'STRING_LITERAL'): 346 | if cursor.spelling: 347 | return cursor.spelling 348 | return list(cursor.get_tokens())[0].spelling 349 | else: 350 | raise TypeError('CursorKind: {} ist not supported!'.format(cursor.kind.name)) 351 | 352 | 353 | # noinspection SpellCheckingInspection 354 | def create_struct_prefix(cursor_type: Type) -> str: 355 | """checks if cursor is a struct and returns respective prefix""" 356 | pointee = cursor_type.get_pointee() 357 | while is_valid(pointee): 358 | cursor_type = pointee 359 | pointee = cursor_type.get_pointee() 360 | declaration = cursor_type.get_declaration() 361 | if is_kind(declaration, 'STRUCT_DECL') or is_kind(declaration, 'CLASS_DECL'): 362 | return 'struct ' 363 | return '' 364 | 365 | 366 | def normalise_link(source: str) -> str: 367 | """normalises link nomenclature""" 368 | return source.replace('\\', '/') 369 | 370 | 371 | def get_cursor_location(cursor_location: SourceLocation) -> str: 372 | """finds cursor's location and returns it as formatted string""" 373 | return 'Source: "{}", line {}'.format(_remove_build_path(cursor_location.file.name), cursor_location.line) 374 | 375 | 376 | def _remove_build_path(file_name: str) -> str: 377 | """removes devise-specific information from generated locations""" 378 | return re.sub('^.*(pluginterfaces/)', '\\1', normalise_link(file_name)) 379 | 380 | 381 | # ----- namespace functions -------------------------------------------------------------------------------------------- 382 | 383 | def convert_namespace(source: str) -> str: 384 | """formats given namespace prefix and returns it as string""" 385 | return source.replace('::', '_') 386 | 387 | 388 | def create_namespace_prefix(cursor: Cursor) -> str: 389 | """gets namespace, formats prefix and returns it as string""" 390 | namespaces = _get_namespaces(cursor) 391 | if not namespaces: 392 | return '' 393 | return '_'.join(namespaces) + '_' 394 | 395 | def create_namespace_prefix_for_type(cursor_type: Type) -> str: 396 | """gets namespace, formats prefix and returns it as string""" 397 | decl_cursor = cursor_type.get_declaration() 398 | namespaces = [] 399 | while decl_cursor: 400 | if is_kind(decl_cursor, 'NAMESPACE') or ( 401 | is_kind(decl_cursor, 'CLASS_DECL') and decl_cursor.spelling != cursor_type.spelling): 402 | namespaces.append(decl_cursor.spelling) 403 | decl_cursor = decl_cursor.semantic_parent 404 | if not namespaces: 405 | return '' 406 | return '_'.join(reversed(namespaces)) + '_' 407 | 408 | def _get_namespaces(cursor: Cursor) -> List[str]: 409 | """finds cursor's namespace and returns it as string""" 410 | cursor_definition = cursor.get_definition() 411 | if cursor_definition: 412 | cursor = cursor_definition 413 | cursor = cursor.lexical_parent 414 | namespaces = [] 415 | while cursor and is_not_kind(cursor, 'TRANSLATION_UNIT'): 416 | if cursor.spelling: 417 | if not (cursor.spelling.startswith('(unnamed ') or cursor.spelling.startswith('(anonymous ')): 418 | namespaces.append(cursor.spelling) 419 | cursor = cursor.lexical_parent 420 | namespaces.reverse() 421 | return namespaces 422 | 423 | 424 | # ----- conversion functions ------------------------------------------------------------------------------------------- 425 | 426 | 427 | def convert_cursor(cursor: Cursor) -> str: 428 | """attaches namespace prefix to cursor and returns formatted name as string""" 429 | return create_namespace_prefix(cursor) + cursor.spelling 430 | 431 | 432 | # noinspection SpellCheckingInspection 433 | def convert_type(cursor_type: Type) -> str: 434 | """checks for pointers/const and attaches respective prefix or suffix to returned type string""" 435 | num_pointers = 0 436 | num_consts = 0 437 | pointee = cursor_type.get_pointee() 438 | while is_valid(pointee): 439 | if cursor_type.is_const_qualified(): 440 | num_consts += 1 441 | if is_kind(cursor_type, 'RVALUEREFERENCE'): 442 | num_pointers += 1 443 | cursor_type = pointee 444 | num_pointers += 1 445 | pointee = cursor_type.get_pointee() 446 | result = '' 447 | if is_kind(cursor_type, 'ELABORATED'): 448 | result = create_namespace_prefix_for_type(cursor_type) 449 | if cursor_type.is_const_qualified(): 450 | result = 'const ' + result + re.sub('\\s*const\\s*', '', convert_namespace(cursor_type.spelling)) 451 | else: 452 | result += convert_namespace(cursor_type.spelling) 453 | if num_pointers: 454 | result += '*' * num_pointers + ' const' * num_consts 455 | return result 456 | 457 | 458 | # ---------------------------------------------------------------------------------------------------------------------- 459 | # ----- generator functions -------------------------------------------------------------------------------------------- 460 | # ---------------------------------------------------------------------------------------------------------------------- 461 | 462 | 463 | # noinspection SpellCheckingInspection 464 | def generate_standard(): 465 | """generates standard content for converted header, irrespective of parsed header file, returns string""" 466 | string = "/*-----------------------------------------------------------------------------\n" 467 | string += " This file is part of a Steinberg SDK. It is subject to the license terms\n" 468 | string += " in the LICENSE file found in the top-level directory of this distribution\n" 469 | string += " and at www.steinberg.net/sdklicenses. \n" 470 | string += " No part of the SDK, including this file, may be copied, modified, propagated,\n" 471 | string += " or distributed except according to the terms contained in the LICENSE file.\n" 472 | string += "-----------------------------------------------------------------------------*/\n" 473 | string += "\n" 474 | string += "/* This file is the autogenerated C API of the VST3 SDK */\n" 475 | string += "\n" 476 | string += "#pragma once\n" 477 | string += "\n" 478 | string += "#include \n" 479 | string += "\n" 480 | string += "#if _WIN32\n" 481 | string += "#define SMTG_STDMETHODCALLTYPE __stdcall\n" 482 | string += "#define SMTG_COM_COMPATIBLE 1\n" 483 | string += "#else\n" 484 | string += "#define SMTG_STDMETHODCALLTYPE\n" 485 | string += "#define SMTG_COM_COMPATIBLE 0\n" 486 | string += "#endif\n" 487 | string += "\n" 488 | string += "#ifndef __cplusplus\n" 489 | string += "typedef int16_t char16_t;\n" 490 | string += "#endif\n" 491 | string += "\n" 492 | string += "#if SMTG_COM_COMPATIBLE\n" 493 | string += "#define SMTG_INLINE_UID(l1, l2, l3, l4) \\\n" 494 | string += "{ \\\n" 495 | string += " (Steinberg_int8)(((Steinberg_uint32)(l1) & 0x000000FF) ), (Steinberg_int8)(((Steinberg_uint32)(l1) & 0x0000FF00) >> 8), \\\n" 496 | string += " (Steinberg_int8)(((Steinberg_uint32)(l1) & 0x00FF0000) >> 16), (Steinberg_int8)(((Steinberg_uint32)(l1) & 0xFF000000) >> 24), \\\n" 497 | string += " (Steinberg_int8)(((Steinberg_uint32)(l2) & 0x00FF0000) >> 16), (Steinberg_int8)(((Steinberg_uint32)(l2) & 0xFF000000) >> 24), \\\n" 498 | string += " (Steinberg_int8)(((Steinberg_uint32)(l2) & 0x000000FF) ), (Steinberg_int8)(((Steinberg_uint32)(l2) & 0x0000FF00) >> 8), \\\n" 499 | string += " (Steinberg_int8)(((Steinberg_uint32)(l3) & 0xFF000000) >> 24), (Steinberg_int8)(((Steinberg_uint32)(l3) & 0x00FF0000) >> 16), \\\n" 500 | string += " (Steinberg_int8)(((Steinberg_uint32)(l3) & 0x0000FF00) >> 8), (Steinberg_int8)(((Steinberg_uint32)(l3) & 0x000000FF) ), \\\n" 501 | string += " (Steinberg_int8)(((Steinberg_uint32)(l4) & 0xFF000000) >> 24), (Steinberg_int8)(((Steinberg_uint32)(l4) & 0x00FF0000) >> 16), \\\n" 502 | string += " (Steinberg_int8)(((Steinberg_uint32)(l4) & 0x0000FF00) >> 8), (Steinberg_int8)(((Steinberg_uint32)(l4) & 0x000000FF) ) \\\n" 503 | string += "}\n" 504 | string += "#else\n" 505 | string += "#define SMTG_INLINE_UID(l1, l2, l3, l4) \\\n" 506 | string += "{ \\\n" 507 | string += " (Steinberg_int8)(((Steinberg_uint32)(l1) & 0xFF000000) >> 24), (Steinberg_int8)(((Steinberg_uint32)(l1) & 0x00FF0000) >> 16), \\\n" 508 | string += " (Steinberg_int8)(((Steinberg_uint32)(l1) & 0x0000FF00) >> 8), (Steinberg_int8)(((Steinberg_uint32)(l1) & 0x000000FF) ), \\\n" 509 | string += " (Steinberg_int8)(((Steinberg_uint32)(l2) & 0xFF000000) >> 24), (Steinberg_int8)(((Steinberg_uint32)(l2) & 0x00FF0000) >> 16), \\\n" 510 | string += " (Steinberg_int8)(((Steinberg_uint32)(l2) & 0x0000FF00) >> 8), (Steinberg_int8)(((Steinberg_uint32)(l2) & 0x000000FF) ), \\\n" 511 | string += " (Steinberg_int8)(((Steinberg_uint32)(l3) & 0xFF000000) >> 24), (Steinberg_int8)(((Steinberg_uint32)(l3) & 0x00FF0000) >> 16), \\\n" 512 | string += " (Steinberg_int8)(((Steinberg_uint32)(l3) & 0x0000FF00) >> 8), (Steinberg_int8)(((Steinberg_uint32)(l3) & 0x000000FF) ), \\\n" 513 | string += " (Steinberg_int8)(((Steinberg_uint32)(l4) & 0xFF000000) >> 24), (Steinberg_int8)(((Steinberg_uint32)(l4) & 0x00FF0000) >> 16), \\\n" 514 | string += " (Steinberg_int8)(((Steinberg_uint32)(l4) & 0x0000FF00) >> 8), (Steinberg_int8)(((Steinberg_uint32)(l4) & 0x000000FF) ) \\\n" 515 | string += "}\n" 516 | string += "#endif\n" 517 | string += "\n" 518 | return string 519 | 520 | 521 | def generate_typedefs(typedefs_list: Container, comment: str): 522 | """generates formatted typedefs for converted header, returns string""" 523 | string = "" 524 | string += "/*----------------------------------------------------------------------------------------------------------------------\n" 525 | string += "----- {} {}\n".format(comment, '-' * (113 - len(comment))) 526 | string += "----------------------------------------------------------------------------------------------------------------------*/\n" 527 | string += "\n" 528 | for typedef in typedefs_list: 529 | string += "{}\n".format(typedef) 530 | string += "\n\n" 531 | return string 532 | 533 | 534 | def generate_forward(): 535 | """generates formatted forward declarations for converted header, returns string""" 536 | string = "" 537 | string += "/*----------------------------------------------------------------------------------------------------------------------\n" 538 | string += "----- Interface forward declarations -----------------------------------------------------------------------------------\n" 539 | string += "----------------------------------------------------------------------------------------------------------------------*/\n" 540 | string += "\n" 541 | for forward_interface in interfaces: 542 | string += "struct {};\n".format(forward_interface.name) 543 | string += "\n" 544 | string += "\n" 545 | string += "/*----------------------------------------------------------------------------------------------------------------------\n" 546 | string += "----- Struct forward declarations --------------------------------------------------------------------------------------\n" 547 | string += "----------------------------------------------------------------------------------------------------------------------*/\n" 548 | string += "\n" 549 | for forward_struct in structs: 550 | string += "struct {};\n".format(forward_struct.name) 551 | string += "\n\n" 552 | return string 553 | 554 | 555 | # noinspection SpellCheckingInspection 556 | def generate_return_types(): 557 | """generates further standard content for converted header, returns string""" 558 | string = "" 559 | string += "/*----------------------------------------------------------------------------------------------------------------------\n" 560 | string += "----- Result value definitions -----------------------------------------------------------------------------------------\n" 561 | string += "----------------------------------------------------------------------------------------------------------------------*/\n" 562 | string += "\n" 563 | string += "#if SMTG_COM_COMPATIBLE\n" 564 | string += "static const Steinberg_tresult Steinberg_kNoInterface = 0x80004002L;\n" 565 | string += "static const Steinberg_tresult Steinberg_kResultOk = 0x00000000L;\n" 566 | string += "static const Steinberg_tresult Steinberg_kResultTrue = 0x00000000L;\n" 567 | string += "static const Steinberg_tresult Steinberg_kResultFalse = 0x00000001L;\n" 568 | string += "static const Steinberg_tresult Steinberg_kInvalidArgument = 0x80070057L;\n" 569 | string += "static const Steinberg_tresult Steinberg_kNotImplemented = 0x80004001L;\n" 570 | string += "static const Steinberg_tresult Steinberg_kInternalError = 0x80004005L;\n" 571 | string += "static const Steinberg_tresult Steinberg_kNotInitialized = 0x8000FFFFL;\n" 572 | string += "static const Steinberg_tresult Steinberg_kOutOfMemory = 0x8007000EL;\n" 573 | string += "\n" 574 | string += "#else\n" 575 | string += "static const Steinberg_tresult Steinberg_kNoInterface = -1;\n" 576 | string += "static const Steinberg_tresult Steinberg_kResultOk = 0;\n" 577 | string += "static const Steinberg_tresult Steinberg_kResultTrue = 0;\n" 578 | string += "static const Steinberg_tresult Steinberg_kResultFalse = 1;\n" 579 | string += "static const Steinberg_tresult Steinberg_kInvalidArgument = 2;\n" 580 | string += "static const Steinberg_tresult Steinberg_kNotImplemented = 3;\n" 581 | string += "static const Steinberg_tresult Steinberg_kInternalError = 4;\n" 582 | string += "static const Steinberg_tresult Steinberg_kNotInitialized = 5;\n" 583 | string += "static const Steinberg_tresult Steinberg_kOutOfMemory = 6;\n" 584 | string += "#endif\n" 585 | string += "\n\n" 586 | return string 587 | 588 | 589 | def generate_enums(): 590 | """generates formatted enums for converted header, returns string""" 591 | string = "" 592 | string += "/*----------------------------------------------------------------------------------------------------------------------\n" 593 | string += "----- Enums ------------------------------------------------------------------------------------------------------------\n" 594 | string += "----------------------------------------------------------------------------------------------------------------------*/\n" 595 | string += "\n" 596 | for enum in enums: 597 | string += "/*----------------------------------------------------------------------------------------------------------------------\n" 598 | string += "{} */\n".format(enum.source_location) 599 | string += "\n" 600 | string += "typedef enum\n" 601 | string += "{\n" 602 | string += ",\n".join([f' {enumerator}' for enumerator in enum.enumerators]) 603 | string += "\n" 604 | string += "}} {};\n".format(enum.name) 605 | string += "\n" 606 | string += "\n" 607 | return string 608 | 609 | 610 | def generate_variables(): 611 | """generates formatted variables for converted header, returns string""" 612 | string = "" 613 | string += "/*----------------------------------------------------------------------------------------------------------------------\n" 614 | string += "----- Variable declarations --------------------------------------------------------------------------------------------\n" 615 | string += "----------------------------------------------------------------------------------------------------------------------*/\n" 616 | string += "\n" 617 | for variable in variables: 618 | string += "{}\n".format(variable) 619 | string += "\n\n" 620 | return string 621 | 622 | 623 | def generate_union(parent): 624 | """generates formatted unions within structs for converted header, returns string""" 625 | string = "" 626 | if parent in unions: 627 | union = unions[parent] 628 | string += " union\n {\n" 629 | for member in union.members: 630 | string += " {};\n".format(member) 631 | string += " };\n" 632 | return string 633 | 634 | 635 | def generate_structs(): 636 | """generates formatted structs for converted header, executes union generator function, returns string""" 637 | string = "" 638 | string += "/*----------------------------------------------------------------------------------------------------------------------\n" 639 | string += "----- Structs ----------------------------------------------------------------------------------------------------------\n" 640 | string += "----------------------------------------------------------------------------------------------------------------------*/\n" 641 | string += "\n" 642 | for struct in structs: 643 | string += "/*----------------------------------------------------------------------------------------------------------------------\n" 644 | string += "{} */\n".format(struct.source_location) 645 | string += "\n" 646 | string += "struct {}\n{{\n".format(struct.name) 647 | for field in struct.members: 648 | string += " {}\n".format(field) 649 | string += generate_union(struct.name) 650 | string += "};\n" 651 | string += "\n" 652 | string += "\n" 653 | return string 654 | 655 | 656 | # noinspection SpellCheckingInspection 657 | def generate_interface(): 658 | """generates formatted interfaces for converted header, executes method generator function, returns string""" 659 | string = "" 660 | string += "/*----------------------------------------------------------------------------------------------------------------------\n" 661 | string += "----- Interfaces -------------------------------------------------------------------------------------------------------\n" 662 | string += "----------------------------------------------------------------------------------------------------------------------*/\n" 663 | string += "\n" 664 | for interface in interfaces: 665 | string += "/*----------------------------------------------------------------------------------------------------------------------\n" 666 | string += "{} */\n".format(interface.source_location) 667 | string += "\n" 668 | string += "typedef struct {}Vtbl\n".format(interface.name) 669 | string += "{\n" 670 | for base_class in interface.base_classes: 671 | string += " /* methods derived from \"{}\": */\n".format(base_class.name) 672 | string += "\n".join([f' {method}' for method in base_class.methods]) 673 | string += "\n\n" 674 | if interface.methods: 675 | string += " /* methods defined in \"{}\": */\n".format(interface.name) 676 | string += "\n".join([f' {method}' for method in interface.methods]) 677 | string += "\n\n" 678 | string += "{} {}Vtbl;\n".format("}", interface.name) 679 | string += "\n" 680 | string += "typedef struct {}\n".format(interface.name) 681 | string += "{\n" 682 | string += " struct {}Vtbl* lpVtbl;\n".format(interface.name) 683 | string += "{} {};\n".format("}", interface.name) 684 | if interface.iid: 685 | string += "\n" 686 | string += "{}\n".format(interface.iid) 687 | string += "\n" 688 | return string 689 | 690 | 691 | def generate_conversion(): 692 | """executes individual generator functions, returns finalised string""" 693 | string = generate_standard() 694 | string += generate_typedefs(typedefs, 'Typedefs') 695 | string += generate_forward() 696 | string += generate_return_types() 697 | string += generate_typedefs(interface_typedefs, 'Interface typedefs') 698 | string += generate_enums() 699 | string += generate_variables() 700 | string += generate_structs() 701 | string += generate_interface() 702 | return string 703 | 704 | 705 | def print_info(): 706 | """prints information about header file, not necessary for generator process""" 707 | print("Number of enums: {}".format(len(enums))) 708 | for enum in enums: 709 | print(" {}".format(enum.name)) 710 | print() 711 | print("Number of structs: {}".format(len(structs))) 712 | for struct in structs: 713 | print(" {}".format(struct.name)) 714 | print() 715 | print("Number of interfaces: {}".format(len(interfaces))) 716 | print() 717 | for index, interface in enumerate(interfaces): 718 | print("Interface {}: {}".format(index + 1, interface.name)) 719 | print(interface.source_location) 720 | print("Info:", interface.description) 721 | print("Methods:") 722 | for method in interface.methods: 723 | match = re.search('SMTG_STDMETHODCALLTYPE\\*\\s+([^)]+)', method) 724 | if match: 725 | print(" {}".format(match.group(1))) 726 | print() 727 | print() 728 | 729 | 730 | # ----- Arrays --------------------------------------------------------------------------------------------------------- 731 | 732 | """defines all used storage structures""" 733 | interfaces = Container() 734 | unions = Container() 735 | structs = Container() 736 | enums = Container() 737 | typedefs = Container() 738 | interface_typedefs = Container() 739 | variables = Container() 740 | 741 | blocklist = ["FUID", "FReleaser"] 742 | 743 | 744 | def clear_arrays(): 745 | """clears all used storage structures""" 746 | global interfaces 747 | global unions 748 | global structs 749 | global enums 750 | global typedefs 751 | global interface_typedefs 752 | global variables 753 | 754 | interfaces.clear() 755 | unions.clear() 756 | structs.clear() 757 | enums.clear() 758 | typedefs.clear() 759 | interface_typedefs.clear() 760 | variables.clear() 761 | 762 | 763 | # ---------------------------------------------------------------------------------------------------------------------- 764 | # ----- main function -------------------------------------------------------------------------------------------------- 765 | # ---------------------------------------------------------------------------------------------------------------------- 766 | 767 | 768 | if __name__ == '__main__': 769 | 770 | """lets users define the output type""" 771 | print_header = True 772 | write_header = True 773 | 774 | """establishes translation unit""" 775 | parser = ArgumentParser(description='usage: {filename} [clang-args*]') 776 | parser.add_argument('filename', type=str) 777 | parser.add_argument('clang_args', nargs=REMAINDER) 778 | args = parser.parse_args() 779 | filename = args.filename 780 | if not filename: 781 | print('No filename was specified!') 782 | exit(1) 783 | include_path = normalise_link(str(Path(sys.argv[1]).parents[2])) 784 | tu = create_translation_unit(Path(filename), include_path, args.clang_args) 785 | 786 | """executes parsing and generator function""" 787 | parse_header(tu.cursor) 788 | header_content = generate_conversion() 789 | 790 | """outputs generated header as new header file""" 791 | if write_header: 792 | header_path = "vst3_c_api.h" 793 | with open(header_path, 'w') as h: 794 | h.write(header_content) 795 | 796 | """outputs generated header in console""" 797 | if print_header: 798 | print(header_content) 799 | print_info() 800 | -------------------------------------------------------------------------------- /generate_header/scripts/pyproject.toml: -------------------------------------------------------------------------------- 1 | [project] 2 | name = "c-api-generator" 3 | version = "0.0.0" 4 | requires-python = "==3.9.*" 5 | dependencies = [ 6 | "libclang", 7 | "clang==18.1.*", 8 | "jinja2" 9 | ] 10 | -------------------------------------------------------------------------------- /generate_header/scripts/templates/header_compilation.h: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------ 2 | // Project : VST SDK 3 | // 4 | // Category : Interfaces 5 | // Filename : {{ file_name }} 6 | // Created by : Steinberg, {{ date }} 7 | // Description : VST Edit Controller Interfaces 8 | // 9 | //----------------------------------------------------------------------------- 10 | // This file is part of a Steinberg SDK. It is subject to the license terms 11 | // in the LICENSE file found in the top-level directory of this distribution 12 | // and at www.steinberg.net/sdklicenses. 13 | // No part of the SDK, including this file, may be copied, modified, propagated, 14 | // or distributed except according to the terms contained in the LICENSE file. 15 | //----------------------------------------------------------------------------- 16 | 17 | #pragma once 18 | 19 | {% for include in pluginterfaces_includes %} 20 | #include "pluginterfaces/{{ include }}" 21 | {% endfor %} 22 | -------------------------------------------------------------------------------- /generate_header/scripts/test/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/steinbergmedia/vst3_c_api_generator/80640af21d26fc139fbbd5824de423e832a244d2/generate_header/scripts/test/__init__.py -------------------------------------------------------------------------------- /generate_header/scripts/test/headers/enums.h: -------------------------------------------------------------------------------- 1 | namespace Steinberg { 2 | 3 | class IBStream 4 | { 5 | enum IStreamSeekMode 6 | { 7 | kIBSeekSet = 0, 8 | kIBSeekCur, 9 | kIBSeekEnd 10 | }; 11 | 12 | enum 13 | { 14 | kURLSize = 256, 15 | kEmailSize = 128, 16 | kNameSize = 64 17 | }; 18 | }; 19 | 20 | namespace Vst { 21 | 22 | enum MediaTypes 23 | { 24 | kAudio = 0, 25 | kEvent, 26 | kNumMediaTypes 27 | }; 28 | 29 | class IAutomationState 30 | { 31 | enum AutomationStates 32 | { 33 | kNoAutomation = 0, 34 | kReadState = 1 << 0, 35 | kWriteState = 1 << 1, 36 | 37 | kReadWriteState = kReadState | kWriteState, 38 | }; 39 | }; 40 | 41 | }} 42 | -------------------------------------------------------------------------------- /generate_header/scripts/test/headers/enums_expected.h: -------------------------------------------------------------------------------- 1 | typedef enum 2 | { 3 | Steinberg_IBStream_IStreamSeekMode_kIBSeekSet = 0, 4 | Steinberg_IBStream_IStreamSeekMode_kIBSeekCur, 5 | Steinberg_IBStream_IStreamSeekMode_kIBSeekEnd 6 | } Steinberg_IBStream_IStreamSeekMode; 7 | 8 | typedef enum 9 | { 10 | Steinberg_Vst_MediaTypes_kAudio = 0, 11 | Steinberg_Vst_MediaTypes_kEvent, 12 | Steinberg_Vst_MediaTypes_kNumMediaTypes 13 | } Steinberg_Vst_MediaTypes; 14 | 15 | typedef enum 16 | { 17 | Steinberg_Vst_IAutomationState_AutomationStates_kNoAutomation = 0, 18 | Steinberg_Vst_IAutomationState_AutomationStates_kReadState = 1 << 0, 19 | Steinberg_Vst_IAutomationState_AutomationStates_kWriteState = 1 << 1, 20 | Steinberg_Vst_IAutomationState_AutomationStates_kReadWriteState = Steinberg_Vst_IAutomationState_AutomationStates_kReadState | Steinberg_Vst_IAutomationState_AutomationStates_kWriteState 21 | } Steinberg_Vst_IAutomationState_AutomationStates; -------------------------------------------------------------------------------- /generate_header/scripts/test/headers/funknown.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "types.h" 4 | 5 | namespace Steinberg { 6 | 7 | #define INLINE_UID(l1, l2, l3, l4) 8 | 9 | #define DECLARE_CLASS_IID(ClassName, l1, l2, l3, l4) \ 10 | static const ::Steinberg::TUID ClassName##_iid = INLINE_UID (l1, l2, l3, l4); 11 | 12 | class FUnknown 13 | { 14 | virtual tresult PLUGIN_API queryInterface (const TUID _iid, void** obj) = 0; 15 | 16 | virtual uint32 PLUGIN_API addRef () = 0; 17 | 18 | static const FUID iid; 19 | }; 20 | 21 | DECLARE_CLASS_IID (FUnknown, 0x00000000, 0x00000000, 0xC0000000, 0x00000046) 22 | 23 | } 24 | -------------------------------------------------------------------------------- /generate_header/scripts/test/headers/interfaces.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "funknown.h" 4 | #include "structs.h" 5 | 6 | namespace Steinberg { 7 | 8 | class IPluginFactory : public FUnknown 9 | { 10 | virtual tresult PLUGIN_API getFactoryInfo (PFactoryInfo* info) = 0; 11 | virtual int32 PLUGIN_API countClasses () = 0; 12 | virtual tresult PLUGIN_API createInstance (const FIDString& cid, FIDString _iid, void** obj) = 0; 13 | 14 | static const FUID iid; 15 | }; 16 | 17 | DECLARE_CLASS_IID (IPluginFactory, 0x7A4D811C, 0x52114A1F, 0xAED9D2EE, 0x0B43BF9F) 18 | 19 | class IPluginFactory2 : public IPluginFactory 20 | { 21 | virtual tresult PLUGIN_API getClassInfo2 (const int32* const index, PClassInfo2* info) = 0; 22 | 23 | static const FUID iid; 24 | }; 25 | 26 | DECLARE_CLASS_IID (IPluginFactory2, 0x0007B650, 0xF24B4C0B, 0xA464EDB9, 0xF00B2ABB) 27 | 28 | class IPluginFactory3 : public IPluginFactory2 29 | { 30 | virtual tresult PLUGIN_API getClassInfoUnicode (int32 index, PClassInfoW*& info) = 0; 31 | virtual tresult PLUGIN_API setHostContext (FUnknown* context) = 0; 32 | 33 | static const FUID iid; 34 | }; 35 | 36 | DECLARE_CLASS_IID (IPluginFactory3, 0x4555A2AB, 0xC1234E57, 0x9B122910, 0x36878931) 37 | 38 | class IPlugViewContentScaleSupport : public FUnknown 39 | { 40 | typedef float ScaleFactor; 41 | 42 | virtual tresult PLUGIN_API setContentScaleFactor (ScaleFactor factor /*in*/) = 0; 43 | 44 | static const FUID iid; 45 | }; 46 | 47 | DECLARE_CLASS_IID (IPlugViewContentScaleSupport, 0x65ED9690, 0x8AC44525, 0x8AADEF7A, 0x72EA703F) 48 | 49 | } -------------------------------------------------------------------------------- /generate_header/scripts/test/headers/interfaces_expected.h: -------------------------------------------------------------------------------- 1 | typedef struct Steinberg_FUnknownVtbl 2 | { 3 | /* methods defined in "Steinberg_FUnknown": */ 4 | Steinberg_tresult (SMTG_STDMETHODCALLTYPE* queryInterface) (void* thisInterface, const Steinberg_TUID iid, void** obj); 5 | Steinberg_uint32 (SMTG_STDMETHODCALLTYPE* addRef) (void* thisInterface); 6 | 7 | } Steinberg_FUnknownVtbl; 8 | 9 | typedef struct Steinberg_FUnknown 10 | { 11 | struct Steinberg_FUnknownVtbl* lpVtbl; 12 | } Steinberg_FUnknown; 13 | 14 | static const Steinberg_TUID Steinberg_FUnknown_iid = SMTG_INLINE_UID (0x00000000, 0x00000000, 0xC0000000, 0x00000046); 15 | 16 | typedef struct Steinberg_IPluginFactoryVtbl 17 | { 18 | /* methods derived from "Steinberg_FUnknown": */ 19 | Steinberg_tresult (SMTG_STDMETHODCALLTYPE* queryInterface) (void* thisInterface, const Steinberg_TUID iid, void** obj); 20 | Steinberg_uint32 (SMTG_STDMETHODCALLTYPE* addRef) (void* thisInterface); 21 | 22 | /* methods defined in "Steinberg_IPluginFactory": */ 23 | Steinberg_tresult (SMTG_STDMETHODCALLTYPE* getFactoryInfo) (void* thisInterface, struct Steinberg_PFactoryInfo* info); 24 | Steinberg_int32 (SMTG_STDMETHODCALLTYPE* countClasses) (void* thisInterface); 25 | Steinberg_tresult (SMTG_STDMETHODCALLTYPE* createInstance) (void* thisInterface, const Steinberg_FIDString* cid, Steinberg_FIDString iid, void** obj); 26 | 27 | } Steinberg_IPluginFactoryVtbl; 28 | 29 | typedef struct Steinberg_IPluginFactory 30 | { 31 | struct Steinberg_IPluginFactoryVtbl* lpVtbl; 32 | } Steinberg_IPluginFactory; 33 | 34 | static const Steinberg_TUID Steinberg_IPluginFactory_iid = SMTG_INLINE_UID (0x7A4D811C, 0x52114A1F, 0xAED9D2EE, 0x0B43BF9F); 35 | 36 | typedef struct Steinberg_IPluginFactory2Vtbl 37 | { 38 | /* methods derived from "Steinberg_FUnknown": */ 39 | Steinberg_tresult (SMTG_STDMETHODCALLTYPE* queryInterface) (void* thisInterface, const Steinberg_TUID iid, void** obj); 40 | Steinberg_uint32 (SMTG_STDMETHODCALLTYPE* addRef) (void* thisInterface); 41 | 42 | /* methods derived from "Steinberg_IPluginFactory": */ 43 | Steinberg_tresult (SMTG_STDMETHODCALLTYPE* getFactoryInfo) (void* thisInterface, struct Steinberg_PFactoryInfo* info); 44 | Steinberg_int32 (SMTG_STDMETHODCALLTYPE* countClasses) (void* thisInterface); 45 | Steinberg_tresult (SMTG_STDMETHODCALLTYPE* createInstance) (void* thisInterface, const Steinberg_FIDString* cid, Steinberg_FIDString iid, void** obj); 46 | 47 | /* methods defined in "Steinberg_IPluginFactory2": */ 48 | Steinberg_tresult (SMTG_STDMETHODCALLTYPE* getClassInfo2) (void* thisInterface, const Steinberg_int32* const index, struct Steinberg_PClassInfo2* info); 49 | 50 | } Steinberg_IPluginFactory2Vtbl; 51 | 52 | typedef struct Steinberg_IPluginFactory2 53 | { 54 | struct Steinberg_IPluginFactory2Vtbl* lpVtbl; 55 | } Steinberg_IPluginFactory2; 56 | 57 | static const Steinberg_TUID Steinberg_IPluginFactory2_iid = SMTG_INLINE_UID (0x0007B650, 0xF24B4C0B, 0xA464EDB9, 0xF00B2ABB); 58 | 59 | typedef struct Steinberg_IPluginFactory3Vtbl 60 | { 61 | /* methods derived from "Steinberg_FUnknown": */ 62 | Steinberg_tresult (SMTG_STDMETHODCALLTYPE* queryInterface) (void* thisInterface, const Steinberg_TUID iid, void** obj); 63 | Steinberg_uint32 (SMTG_STDMETHODCALLTYPE* addRef) (void* thisInterface); 64 | 65 | /* methods derived from "Steinberg_IPluginFactory": */ 66 | Steinberg_tresult (SMTG_STDMETHODCALLTYPE* getFactoryInfo) (void* thisInterface, struct Steinberg_PFactoryInfo* info); 67 | Steinberg_int32 (SMTG_STDMETHODCALLTYPE* countClasses) (void* thisInterface); 68 | Steinberg_tresult (SMTG_STDMETHODCALLTYPE* createInstance) (void* thisInterface, const Steinberg_FIDString* cid, Steinberg_FIDString iid, void** obj); 69 | 70 | /* methods derived from "Steinberg_IPluginFactory2": */ 71 | Steinberg_tresult (SMTG_STDMETHODCALLTYPE* getClassInfo2) (void* thisInterface, const Steinberg_int32* const index, struct Steinberg_PClassInfo2* info); 72 | 73 | /* methods defined in "Steinberg_IPluginFactory3": */ 74 | Steinberg_tresult (SMTG_STDMETHODCALLTYPE* getClassInfoUnicode) (void* thisInterface, Steinberg_int32 index, struct Steinberg_PClassInfoW** info); 75 | Steinberg_tresult (SMTG_STDMETHODCALLTYPE* setHostContext) (void* thisInterface, struct Steinberg_FUnknown* context); 76 | 77 | } Steinberg_IPluginFactory3Vtbl; 78 | 79 | typedef struct Steinberg_IPluginFactory3 80 | { 81 | struct Steinberg_IPluginFactory3Vtbl* lpVtbl; 82 | } Steinberg_IPluginFactory3; 83 | 84 | static const Steinberg_TUID Steinberg_IPluginFactory3_iid = SMTG_INLINE_UID (0x4555A2AB, 0xC1234E57, 0x9B122910, 0x36878931); 85 | 86 | typedef struct Steinberg_IPlugViewContentScaleSupportVtbl 87 | { 88 | /* methods derived from "Steinberg_FUnknown": */ 89 | Steinberg_tresult (SMTG_STDMETHODCALLTYPE* queryInterface) (void* thisInterface, const Steinberg_TUID iid, void** obj); 90 | Steinberg_uint32 (SMTG_STDMETHODCALLTYPE* addRef) (void* thisInterface); 91 | 92 | /* methods defined in "Steinberg_IPlugViewContentScaleSupport": */ 93 | Steinberg_tresult (SMTG_STDMETHODCALLTYPE* setContentScaleFactor) (void* thisInterface, Steinberg_IPlugViewContentScaleSupport_ScaleFactor factor); 94 | 95 | } Steinberg_IPlugViewContentScaleSupportVtbl; 96 | 97 | typedef struct Steinberg_IPlugViewContentScaleSupport 98 | { 99 | struct Steinberg_IPlugViewContentScaleSupportVtbl* lpVtbl; 100 | } Steinberg_IPlugViewContentScaleSupport; 101 | 102 | static const Steinberg_TUID Steinberg_IPlugViewContentScaleSupport_iid = SMTG_INLINE_UID (0x65ED9690, 0x8AC44525, 0x8AADEF7A, 0x72EA703F); -------------------------------------------------------------------------------- /generate_header/scripts/test/headers/structs.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "types.h" 4 | 5 | namespace Steinberg { 6 | 7 | struct PFactoryInfo 8 | { 9 | enum 10 | { 11 | kURLSize = 256, 12 | kEmailSize = kURLSize << 4, 13 | kNameSize = kEmailSize >> 3 14 | }; 15 | 16 | char8 vendor[kNameSize | 1]; 17 | char8 url[kURLSize]; 18 | char8 email[kEmailSize]; 19 | int32 flags; 20 | TUID cid; 21 | 22 | union 23 | { 24 | NoteOnEvent noteOn; ///< type == kNoteOnEvent 25 | NoteOffEvent noteOff; ///< type == kNoteOffEvent 26 | }; 27 | }; 28 | 29 | } 30 | -------------------------------------------------------------------------------- /generate_header/scripts/test/headers/structs_expected.h: -------------------------------------------------------------------------------- 1 | struct Steinberg_PFactoryInfo 2 | { 3 | Steinberg_char8 vendor[256 << 4 >> 3 | 1]; 4 | Steinberg_char8 url[256]; 5 | Steinberg_char8 email[256 << 4]; 6 | Steinberg_int32 flags; 7 | Steinberg_TUID cid; 8 | union 9 | { 10 | int Steinberg_PFactoryInfo_noteOn; 11 | int Steinberg_PFactoryInfo_noteOff; 12 | }; 13 | }; -------------------------------------------------------------------------------- /generate_header/scripts/test/headers/typedefs.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "types.h" 4 | 5 | namespace Steinberg { 6 | namespace Vst { 7 | 8 | enum MediaTypes 9 | { 10 | kAudio = 0, 11 | kEvent, 12 | kNumMediaTypes 13 | }; 14 | 15 | struct IContextMenuItem 16 | { 17 | }; 18 | 19 | class IContextMenu : public FUnknown 20 | { 21 | public: 22 | typedef IContextMenuItem Item; 23 | typedef MediaTypes ItemEvents; 24 | 25 | static const FUID iid; 26 | }; 27 | 28 | DECLARE_CLASS_IID (IContextMenu, 0x2E93C863, 0x0C9C4588, 0x97DBECF5, 0xAD17817D) 29 | 30 | }} 31 | -------------------------------------------------------------------------------- /generate_header/scripts/test/headers/typedefs_expected.h: -------------------------------------------------------------------------------- 1 | typedef int Steinberg_tchar; 2 | typedef char Steinberg_int8; 3 | typedef char Steinberg_char8; 4 | typedef long Steinberg_int32; 5 | typedef unsigned long Steinberg_uint32; 6 | typedef Steinberg_int32 Steinberg_UCoord; 7 | typedef Steinberg_int32 Steinberg_tresult; 8 | typedef Steinberg_int8 Steinberg_TUID[16]; 9 | typedef const Steinberg_char8* Steinberg_FIDString; 10 | typedef const Steinberg_tchar* Steinberg_CString; 11 | typedef Steinberg_int32 Steinberg_UnitID; 12 | typedef Steinberg_int32 Steinberg_ProgramListID; 13 | 14 | typedef struct Steinberg_Vst_IContextMenuItem Steinberg_Vst_IContextMenu_Item; 15 | typedef Steinberg_Vst_MediaTypes Steinberg_Vst_IContextMenu_ItemEvents; -------------------------------------------------------------------------------- /generate_header/scripts/test/headers/types.h: -------------------------------------------------------------------------------- 1 | namespace Steinberg { 2 | 3 | #ifdef UNICODE 4 | typedef char16 tchar; 5 | #else 6 | typedef char8 tchar; 7 | #endif 8 | 9 | typedef char int8; 10 | typedef char char8; 11 | typedef long int32; 12 | typedef unsigned long uint32; 13 | typedef int32 UCoord; 14 | typedef int32 tresult; 15 | typedef int8 TUID[16]; 16 | typedef const char8* FIDString 17 | typedef const tchar* CString; 18 | typedef int32 UnitID; 19 | typedef int32 ProgramListID; 20 | 21 | class FUID; 22 | struct PClassInfo2; 23 | struct PClassInfoW; 24 | 25 | #define PLUGIN_API 26 | 27 | #define INT_MAX 2147483647 28 | #define INT_MIN (-2147483647 - 1) 29 | 30 | } 31 | -------------------------------------------------------------------------------- /generate_header/scripts/test/headers/variables.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "vsttypes.h" 4 | 5 | namespace Steinberg { 6 | 7 | struct PFactoryInfo 8 | { 9 | enum FactoryFlags 10 | { 11 | kUnicode = 1 << 4 12 | }; 13 | }; 14 | 15 | namespace Vst { 16 | 17 | #define ATTR_STYLE "style" 18 | 19 | namespace Attributes 20 | { 21 | const CString kStyle = ATTR_STYLE; 22 | static const int32 kMaxInt = INT_MAX; 23 | static const int32 kMinInt = INT_MIN; 24 | }; 25 | 26 | static const UnitID kNoParentUnitId = -1; 27 | const Speaker kSpeakerL = 1 << 0; 28 | const Speaker kSpeakerR = 1 << 1; 29 | const Speaker kSpeakerC = 1 << 2; 30 | const Speaker kSpeakerLfe = 1 << 3; 31 | const Speaker kSpeakerLs = 1 << 4; 32 | const Speaker kSpeakerRs = 1 << 5; 33 | const Speaker kSpeakerPl = (Speaker)1 << 31; 34 | const Speaker kSpeakerPr = (Speaker)1 << 32; 35 | const SpeakerArrangement k71Proximity = kSpeakerL | kSpeakerR | kSpeakerC | kSpeakerLfe | kSpeakerLs | kSpeakerRs | kSpeakerPl | kSpeakerPr; 36 | const CString kStringEmpty = ""; 37 | const CString kStringStereoR = "Stereo (Ls Rs)"; 38 | 39 | } 40 | 41 | static const int32 kMinLong = (-0x42-1); 42 | static const int32 kMinInt32 = kMinLong; 43 | 44 | static const uint32 kMaxInt32u = int32 (kMinInt32) | (int32 (0x42) << 23); 45 | static const UCoord kMinCoord = ((UCoord)-0x42); 46 | 47 | const int32 kDefaultFactoryFlags = PFactoryInfo::kUnicode; 48 | 49 | } 50 | -------------------------------------------------------------------------------- /generate_header/scripts/test/headers/variables_expected.h: -------------------------------------------------------------------------------- 1 | static const Steinberg_CString Steinberg_Vst_Attributes_kStyle = "style"; 2 | static const Steinberg_int32 Steinberg_Vst_Attributes_kMaxInt = INT_MAX; 3 | static const Steinberg_int32 Steinberg_Vst_Attributes_kMinInt = INT_MIN; 4 | static const Steinberg_UnitID Steinberg_Vst_kNoParentUnitId = -1; 5 | static const Steinberg_Vst_Speaker Steinberg_Vst_kSpeakerL = 1 << 0; 6 | static const Steinberg_Vst_Speaker Steinberg_Vst_kSpeakerR = 1 << 1; 7 | static const Steinberg_Vst_Speaker Steinberg_Vst_kSpeakerC = 1 << 2; 8 | static const Steinberg_Vst_Speaker Steinberg_Vst_kSpeakerLfe = 1 << 3; 9 | static const Steinberg_Vst_Speaker Steinberg_Vst_kSpeakerLs = 1 << 4; 10 | static const Steinberg_Vst_Speaker Steinberg_Vst_kSpeakerRs = 1 << 5; 11 | static const Steinberg_Vst_Speaker Steinberg_Vst_kSpeakerPl = (Steinberg_Vst_Speaker) 1 << 31; 12 | static const Steinberg_Vst_Speaker Steinberg_Vst_kSpeakerPr = (Steinberg_Vst_Speaker) 1 << 32; 13 | static const Steinberg_Vst_SpeakerArrangement Steinberg_Vst_k71Proximity = 1 << 0 | 1 << 1 | 1 << 2 | 1 << 3 | 1 << 4 | 1 << 5 | (Steinberg_Vst_Speaker) 1 << 31 | (Steinberg_Vst_Speaker) 1 << 32; 14 | static const Steinberg_CString Steinberg_Vst_kStringEmpty = ""; 15 | static const Steinberg_CString Steinberg_Vst_kStringStereoR = "Stereo (Ls Rs)"; 16 | static const Steinberg_int32 Steinberg_kMinLong = (-0x42 - 1); 17 | static const Steinberg_int32 Steinberg_kMinInt32 = (-0x42 - 1); 18 | static const Steinberg_uint32 Steinberg_kMaxInt32u = (Steinberg_int32) (-0x42 - 1) | ((Steinberg_int32) 0x42 << 23); 19 | static const Steinberg_UCoord Steinberg_kMinCoord = ((Steinberg_UCoord) -0x42); 20 | static const Steinberg_int32 Steinberg_kDefaultFactoryFlags = 1 << 4; -------------------------------------------------------------------------------- /generate_header/scripts/test/headers/vst_interfaces.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "funknown.h" 4 | #include "structs.h" 5 | 6 | namespace Steinberg { 7 | namespace Vst { 8 | 9 | enum MediaTypes 10 | { 11 | kAudio = 0, 12 | kEvent, 13 | kNumMediaTypes 14 | }; 15 | 16 | struct UnitInfo 17 | { 18 | UnitID id; 19 | UnitID parentUnitId; 20 | CString name; 21 | ProgramListID programListId; 22 | }; 23 | 24 | class IUnitHandler : public FUnknown 25 | { 26 | virtual tresult PLUGIN_API notifyUnitSelection (MediaTypes mediaType) = 0; 27 | virtual tresult PLUGIN_API notifyProgramListChange (ProgramListID listId, int32 programIndex) = 0; 28 | 29 | static const FUID iid; 30 | }; 31 | 32 | DECLARE_CLASS_IID (IUnitHandler, 0x4B5147F8, 0x4654486B, 0x8DAB30BA, 0x163A3C56) 33 | 34 | class IUnitHandler2 : public FUnknown 35 | { 36 | virtual tresult PLUGIN_API notifyUnitByBusChange () = 0; 37 | 38 | static const FUID iid; 39 | }; 40 | 41 | DECLARE_CLASS_IID (IUnitHandler2, 0xF89F8CDF, 0x699E4BA5, 0x96AAC9A4, 0x81452B01) 42 | 43 | class IUnitInfo : public IUnitHandler2, public IUnitHandler 44 | { 45 | virtual int32 PLUGIN_API getUnitCount () = 0; 46 | virtual tresult PLUGIN_API getUnitInfo (int32 unitIndex, UnitInfo& info /*out*/) = 0; 47 | 48 | static const FUID iid; 49 | }; 50 | 51 | DECLARE_CLASS_IID (IUnitInfo, 0x3D4BD6B5, 0x913A4FD2, 0xA886E768, 0xA5EB92C1) 52 | 53 | }} 54 | -------------------------------------------------------------------------------- /generate_header/scripts/test/headers/vst_interfaces_expected.h: -------------------------------------------------------------------------------- 1 | typedef struct Steinberg_FUnknownVtbl 2 | { 3 | /* methods defined in "Steinberg_FUnknown": */ 4 | Steinberg_tresult (SMTG_STDMETHODCALLTYPE* queryInterface) (void* thisInterface, const Steinberg_TUID iid, void** obj); 5 | Steinberg_uint32 (SMTG_STDMETHODCALLTYPE* addRef) (void* thisInterface); 6 | 7 | } Steinberg_FUnknownVtbl; 8 | 9 | typedef struct Steinberg_FUnknown 10 | { 11 | struct Steinberg_FUnknownVtbl* lpVtbl; 12 | } Steinberg_FUnknown; 13 | 14 | static const Steinberg_TUID Steinberg_FUnknown_iid = SMTG_INLINE_UID (0x00000000, 0x00000000, 0xC0000000, 0x00000046); 15 | 16 | typedef struct Steinberg_Vst_IUnitHandlerVtbl 17 | { 18 | /* methods derived from "Steinberg_FUnknown": */ 19 | Steinberg_tresult (SMTG_STDMETHODCALLTYPE* queryInterface) (void* thisInterface, const Steinberg_TUID iid, void** obj); 20 | Steinberg_uint32 (SMTG_STDMETHODCALLTYPE* addRef) (void* thisInterface); 21 | 22 | /* methods defined in "Steinberg_Vst_IUnitHandler": */ 23 | Steinberg_tresult (SMTG_STDMETHODCALLTYPE* notifyUnitSelection) (void* thisInterface, Steinberg_Vst_MediaTypes mediaType); 24 | Steinberg_tresult (SMTG_STDMETHODCALLTYPE* notifyProgramListChange) (void* thisInterface, Steinberg_ProgramListID listId, Steinberg_int32 programIndex); 25 | 26 | } Steinberg_Vst_IUnitHandlerVtbl; 27 | 28 | typedef struct Steinberg_Vst_IUnitHandler 29 | { 30 | struct Steinberg_Vst_IUnitHandlerVtbl* lpVtbl; 31 | } Steinberg_Vst_IUnitHandler; 32 | 33 | static const Steinberg_TUID Steinberg_Vst_IUnitHandler_iid = SMTG_INLINE_UID (0x4B5147F8, 0x4654486B, 0x8DAB30BA, 0x163A3C56); 34 | 35 | typedef struct Steinberg_Vst_IUnitHandler2Vtbl 36 | { 37 | /* methods derived from "Steinberg_FUnknown": */ 38 | Steinberg_tresult (SMTG_STDMETHODCALLTYPE* queryInterface) (void* thisInterface, const Steinberg_TUID iid, void** obj); 39 | Steinberg_uint32 (SMTG_STDMETHODCALLTYPE* addRef) (void* thisInterface); 40 | 41 | /* methods defined in "Steinberg_Vst_IUnitHandler2": */ 42 | Steinberg_tresult (SMTG_STDMETHODCALLTYPE* notifyUnitByBusChange) (void* thisInterface); 43 | 44 | } Steinberg_Vst_IUnitHandler2Vtbl; 45 | 46 | typedef struct Steinberg_Vst_IUnitHandler2 47 | { 48 | struct Steinberg_Vst_IUnitHandler2Vtbl* lpVtbl; 49 | } Steinberg_Vst_IUnitHandler2; 50 | 51 | static const Steinberg_TUID Steinberg_Vst_IUnitHandler2_iid = SMTG_INLINE_UID (0xF89F8CDF, 0x699E4BA5, 0x96AAC9A4, 0x81452B01); 52 | 53 | typedef struct Steinberg_Vst_IUnitInfoVtbl 54 | { 55 | /* methods derived from "Steinberg_FUnknown": */ 56 | Steinberg_tresult (SMTG_STDMETHODCALLTYPE* queryInterface) (void* thisInterface, const Steinberg_TUID iid, void** obj); 57 | Steinberg_uint32 (SMTG_STDMETHODCALLTYPE* addRef) (void* thisInterface); 58 | 59 | /* methods derived from "Steinberg_Vst_IUnitHandler2": */ 60 | Steinberg_tresult (SMTG_STDMETHODCALLTYPE* notifyUnitByBusChange) (void* thisInterface); 61 | 62 | /* methods derived from "Steinberg_Vst_IUnitHandler": */ 63 | Steinberg_tresult (SMTG_STDMETHODCALLTYPE* notifyUnitSelection) (void* thisInterface, Steinberg_Vst_MediaTypes mediaType); 64 | Steinberg_tresult (SMTG_STDMETHODCALLTYPE* notifyProgramListChange) (void* thisInterface, Steinberg_ProgramListID listId, Steinberg_int32 programIndex); 65 | 66 | /* methods defined in "Steinberg_Vst_IUnitInfo": */ 67 | Steinberg_int32 (SMTG_STDMETHODCALLTYPE* getUnitCount) (void* thisInterface); 68 | Steinberg_tresult (SMTG_STDMETHODCALLTYPE* getUnitInfo) (void* thisInterface, Steinberg_int32 unitIndex, struct Steinberg_Vst_UnitInfo* info); 69 | 70 | } Steinberg_Vst_IUnitInfoVtbl; 71 | 72 | typedef struct Steinberg_Vst_IUnitInfo 73 | { 74 | struct Steinberg_Vst_IUnitInfoVtbl* lpVtbl; 75 | } Steinberg_Vst_IUnitInfo; 76 | 77 | static const Steinberg_TUID Steinberg_Vst_IUnitInfo_iid = SMTG_INLINE_UID (0x3D4BD6B5, 0x913A4FD2, 0xA886E768, 0xA5EB92C1); -------------------------------------------------------------------------------- /generate_header/scripts/test/headers/vsttypes.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "types.h" 4 | 5 | namespace Steinberg { 6 | namespace Vst { 7 | 8 | typedef uint64 Speaker; 9 | typedef uint64 SpeakerArrangement; 10 | 11 | }} 12 | -------------------------------------------------------------------------------- /generate_header/scripts/test/test_conversion.py: -------------------------------------------------------------------------------- 1 | #----------------------------------------------------------------------------- 2 | # This file is part of a Steinberg SDK. It is subject to the license terms 3 | # in the LICENSE file found in the top-level directory of this distribution 4 | # and at www.steinberg.net/sdklicenses. 5 | # No part of the SDK, including this file, may be copied, modified, propagated, 6 | # or distributed except according to the terms contained in the LICENSE file. 7 | #----------------------------------------------------------------------------- 8 | 9 | import re 10 | import unittest 11 | from pathlib import Path 12 | 13 | from interface_convert import create_translation_unit, parse_header, generate_conversion, clear_arrays 14 | 15 | 16 | class TestConversion(unittest.TestCase): 17 | def setUp(self): 18 | clear_arrays() 19 | 20 | @classmethod 21 | def _convert_header(cls, header_name: str) -> str: 22 | header_path = (cls._get_headers_directory() / f'{header_name}.h').absolute() 23 | translation_unit = create_translation_unit(header_path, str(header_path.parents[2])) 24 | parse_header(translation_unit.cursor) 25 | result = generate_conversion() 26 | translation_unit.reparse(unsaved_files=[(header_path, '')]) 27 | return result 28 | 29 | @classmethod 30 | def _load_expectation(cls, header_name: str) -> str: 31 | expectation_path = cls._get_headers_directory() / f'{header_name}_expected.h' 32 | with expectation_path.open() as f: 33 | return f.read() 34 | 35 | @staticmethod 36 | def _get_section(start_comment: str, end_comment: str, header_content: str) -> str: 37 | if end_comment: 38 | match = re.search(r'{}.*?\*/\s*(.*?)\s*/\*-+\s-+.-+.{}'.format(start_comment, end_comment), header_content, 39 | flags=re.DOTALL) 40 | else: 41 | match = re.search(r'{}.*?\*/\s*(.*?)$'.format(start_comment), header_content, flags=re.DOTALL) 42 | if match: 43 | return re.sub(r'.?/\*-----.*?\*/.', '', match.group(1), flags=re.DOTALL).strip() 44 | return '' 45 | 46 | @staticmethod 47 | def _get_headers_directory(): 48 | return Path(__file__).parent / 'headers' 49 | 50 | def test_variables(self): 51 | header_name = 'variables' 52 | content_section = self._get_section('Variable declarations', 'Structs', self._convert_header(header_name)) 53 | self.assertEqual(self._load_expectation(header_name), content_section) 54 | 55 | def test_enums(self): 56 | header_name = 'enums' 57 | content_section = self._get_section('Enums', 'Variable declarations', self._convert_header(header_name)) 58 | self.assertEqual(self._load_expectation(header_name), content_section) 59 | 60 | def test_struct(self): 61 | header_name = 'structs' 62 | content_section = self._get_section('Structs', 'Interfaces', self._convert_header(header_name)) 63 | self.assertEqual(self._load_expectation(header_name), content_section) 64 | 65 | def test_interfaces(self): 66 | header_name = 'interfaces' 67 | content_section = self._get_section('Interfaces', '', self._convert_header(header_name)) 68 | self.assertEqual(self._load_expectation(header_name), content_section) 69 | 70 | def test_typedefs(self): 71 | header_name = 'typedefs' 72 | generated_source = self._convert_header(header_name) 73 | content_section = self._get_section('Typedefs', 'Interface forward declarations', generated_source) 74 | content_section += '\n\n' 75 | content_section += self._get_section('Interface typedefs', 'Enums', generated_source) 76 | self.assertEqual(self._load_expectation(header_name), content_section) 77 | 78 | def test_vst_interfaces(self): 79 | header_name = 'vst_interfaces' 80 | content_section = self._get_section('Interfaces', '', self._convert_header(header_name)) 81 | self.assertEqual(self._load_expectation(header_name), content_section) 82 | -------------------------------------------------------------------------------- /generate_header/scripts/uv.lock: -------------------------------------------------------------------------------- 1 | version = 1 2 | revision = 1 3 | requires-python = "==3.9.*" 4 | 5 | [[package]] 6 | name = "c-api-generator" 7 | version = "0.0.0" 8 | source = { virtual = "." } 9 | dependencies = [ 10 | { name = "clang" }, 11 | { name = "jinja2" }, 12 | { name = "libclang" }, 13 | ] 14 | 15 | [package.metadata] 16 | requires-dist = [ 17 | { name = "clang", specifier = "==18.1.*" }, 18 | { name = "jinja2" }, 19 | { name = "libclang" }, 20 | ] 21 | 22 | [[package]] 23 | name = "clang" 24 | version = "18.1.8" 25 | source = { registry = "https://pypi.org/simple" } 26 | sdist = { url = "https://files.pythonhosted.org/packages/2c/6d/202fe248475f92ab9057a4066d50fe8aaa2def62493894dc9a9814ce8d3b/clang-18.1.8.tar.gz", hash = "sha256:26d11859bab6da8d1fcdb85a244957f6c129a0cd15da2abca3059b054b87635f", size = 3101 } 27 | wheels = [ 28 | { url = "https://files.pythonhosted.org/packages/a5/3c/1bebce0b2588b913b48baea6eac5091c023f03cc0c8ab4b015a8315d0d09/clang-18.1.8-py3-none-any.whl", hash = "sha256:2f6a00126743ee23d8fcd2a2338b42ef4d29897f293ee3a1bc4d5925d8ee875c", size = 31627 }, 29 | ] 30 | 31 | [[package]] 32 | name = "jinja2" 33 | version = "3.1.6" 34 | source = { registry = "https://pypi.org/simple" } 35 | dependencies = [ 36 | { name = "markupsafe" }, 37 | ] 38 | sdist = { url = "https://files.pythonhosted.org/packages/df/bf/f7da0350254c0ed7c72f3e33cef02e048281fec7ecec5f032d4aac52226b/jinja2-3.1.6.tar.gz", hash = "sha256:0137fb05990d35f1275a587e9aee6d56da821fc83491a0fb838183be43f66d6d", size = 245115 } 39 | wheels = [ 40 | { url = "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl", hash = "sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67", size = 134899 }, 41 | ] 42 | 43 | [[package]] 44 | name = "libclang" 45 | version = "18.1.1" 46 | source = { registry = "https://pypi.org/simple" } 47 | sdist = { url = "https://files.pythonhosted.org/packages/6e/5c/ca35e19a4f142adffa27e3d652196b7362fa612243e2b916845d801454fc/libclang-18.1.1.tar.gz", hash = "sha256:a1214966d08d73d971287fc3ead8dfaf82eb07fb197680d8b3859dbbbbf78250", size = 39612 } 48 | wheels = [ 49 | { url = "https://files.pythonhosted.org/packages/4b/49/f5e3e7e1419872b69f6f5e82ba56e33955a74bd537d8a1f5f1eff2f3668a/libclang-18.1.1-1-py2.py3-none-macosx_11_0_arm64.whl", hash = "sha256:0b2e143f0fac830156feb56f9231ff8338c20aecfe72b4ffe96f19e5a1dbb69a", size = 25836045 }, 50 | { url = "https://files.pythonhosted.org/packages/e2/e5/fc61bbded91a8830ccce94c5294ecd6e88e496cc85f6704bf350c0634b70/libclang-18.1.1-py2.py3-none-macosx_10_9_x86_64.whl", hash = "sha256:6f14c3f194704e5d09769108f03185fce7acaf1d1ae4bbb2f30a72c2400cb7c5", size = 26502641 }, 51 | { url = "https://files.pythonhosted.org/packages/db/ed/1df62b44db2583375f6a8a5e2ca5432bbdc3edb477942b9b7c848c720055/libclang-18.1.1-py2.py3-none-macosx_11_0_arm64.whl", hash = "sha256:83ce5045d101b669ac38e6da8e58765f12da2d3aafb3b9b98d88b286a60964d8", size = 26420207 }, 52 | { url = "https://files.pythonhosted.org/packages/1d/fc/716c1e62e512ef1c160e7984a73a5fc7df45166f2ff3f254e71c58076f7c/libclang-18.1.1-py2.py3-none-manylinux2010_x86_64.whl", hash = "sha256:c533091d8a3bbf7460a00cb6c1a71da93bffe148f172c7d03b1c31fbf8aa2a0b", size = 24515943 }, 53 | { url = "https://files.pythonhosted.org/packages/3c/3d/f0ac1150280d8d20d059608cf2d5ff61b7c3b7f7bcf9c0f425ab92df769a/libclang-18.1.1-py2.py3-none-manylinux2014_aarch64.whl", hash = "sha256:54dda940a4a0491a9d1532bf071ea3ef26e6dbaf03b5000ed94dd7174e8f9592", size = 23784972 }, 54 | { url = "https://files.pythonhosted.org/packages/fe/2f/d920822c2b1ce9326a4c78c0c2b4aa3fde610c7ee9f631b600acb5376c26/libclang-18.1.1-py2.py3-none-manylinux2014_armv7l.whl", hash = "sha256:cf4a99b05376513717ab5d82a0db832c56ccea4fd61a69dbb7bccf2dfb207dbe", size = 20259606 }, 55 | { url = "https://files.pythonhosted.org/packages/2d/c2/de1db8c6d413597076a4259cea409b83459b2db997c003578affdd32bf66/libclang-18.1.1-py2.py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:69f8eb8f65c279e765ffd28aaa7e9e364c776c17618af8bff22a8df58677ff4f", size = 24921494 }, 56 | { url = "https://files.pythonhosted.org/packages/0b/2d/3f480b1e1d31eb3d6de5e3ef641954e5c67430d5ac93b7fa7e07589576c7/libclang-18.1.1-py2.py3-none-win_amd64.whl", hash = "sha256:4dd2d3b82fab35e2bf9ca717d7b63ac990a3519c7e312f19fa8e86dcc712f7fb", size = 26415083 }, 57 | { url = "https://files.pythonhosted.org/packages/71/cf/e01dc4cc79779cd82d77888a88ae2fa424d93b445ad4f6c02bfc18335b70/libclang-18.1.1-py2.py3-none-win_arm64.whl", hash = "sha256:3f0e1f49f04d3cd198985fea0511576b0aee16f9ff0e0f0cad7f9c57ec3c20e8", size = 22361112 }, 58 | ] 59 | 60 | [[package]] 61 | name = "markupsafe" 62 | version = "3.0.2" 63 | source = { registry = "https://pypi.org/simple" } 64 | sdist = { url = "https://files.pythonhosted.org/packages/b2/97/5d42485e71dfc078108a86d6de8fa46db44a1a9295e89c5d6d4a06e23a62/markupsafe-3.0.2.tar.gz", hash = "sha256:ee55d3edf80167e48ea11a923c7386f4669df67d7994554387f84e7d8b0a2bf0", size = 20537 } 65 | wheels = [ 66 | { url = "https://files.pythonhosted.org/packages/a7/ea/9b1530c3fdeeca613faeb0fb5cbcf2389d816072fab72a71b45749ef6062/MarkupSafe-3.0.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:eaa0a10b7f72326f1372a713e73c3f739b524b3af41feb43e4921cb529f5929a", size = 14344 }, 67 | { url = "https://files.pythonhosted.org/packages/4b/c2/fbdbfe48848e7112ab05e627e718e854d20192b674952d9042ebd8c9e5de/MarkupSafe-3.0.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:48032821bbdf20f5799ff537c7ac3d1fba0ba032cfc06194faffa8cda8b560ff", size = 12389 }, 68 | { url = "https://files.pythonhosted.org/packages/f0/25/7a7c6e4dbd4f867d95d94ca15449e91e52856f6ed1905d58ef1de5e211d0/MarkupSafe-3.0.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1a9d3f5f0901fdec14d8d2f66ef7d035f2157240a433441719ac9a3fba440b13", size = 21607 }, 69 | { url = "https://files.pythonhosted.org/packages/53/8f/f339c98a178f3c1e545622206b40986a4c3307fe39f70ccd3d9df9a9e425/MarkupSafe-3.0.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:88b49a3b9ff31e19998750c38e030fc7bb937398b1f78cfa599aaef92d693144", size = 20728 }, 70 | { url = "https://files.pythonhosted.org/packages/1a/03/8496a1a78308456dbd50b23a385c69b41f2e9661c67ea1329849a598a8f9/MarkupSafe-3.0.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cfad01eed2c2e0c01fd0ecd2ef42c492f7f93902e39a42fc9ee1692961443a29", size = 20826 }, 71 | { url = "https://files.pythonhosted.org/packages/e6/cf/0a490a4bd363048c3022f2f475c8c05582179bb179defcee4766fb3dcc18/MarkupSafe-3.0.2-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:1225beacc926f536dc82e45f8a4d68502949dc67eea90eab715dea3a21c1b5f0", size = 21843 }, 72 | { url = "https://files.pythonhosted.org/packages/19/a3/34187a78613920dfd3cdf68ef6ce5e99c4f3417f035694074beb8848cd77/MarkupSafe-3.0.2-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:3169b1eefae027567d1ce6ee7cae382c57fe26e82775f460f0b2778beaad66c0", size = 21219 }, 73 | { url = "https://files.pythonhosted.org/packages/17/d8/5811082f85bb88410ad7e452263af048d685669bbbfb7b595e8689152498/MarkupSafe-3.0.2-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:eb7972a85c54febfb25b5c4b4f3af4dcc731994c7da0d8a0b4a6eb0640e1d178", size = 20946 }, 74 | { url = "https://files.pythonhosted.org/packages/7c/31/bd635fb5989440d9365c5e3c47556cfea121c7803f5034ac843e8f37c2f2/MarkupSafe-3.0.2-cp39-cp39-win32.whl", hash = "sha256:8c4e8c3ce11e1f92f6536ff07154f9d49677ebaaafc32db9db4620bc11ed480f", size = 15063 }, 75 | { url = "https://files.pythonhosted.org/packages/b3/73/085399401383ce949f727afec55ec3abd76648d04b9f22e1c0e99cb4bec3/MarkupSafe-3.0.2-cp39-cp39-win_amd64.whl", hash = "sha256:6e296a513ca3d94054c2c881cc913116e90fd030ad1c656b3869762b754f5f8a", size = 15506 }, 76 | ] 77 | -------------------------------------------------------------------------------- /validate_interfaces/cxx.cpp: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------------- 2 | // This file is part of a Steinberg SDK. It is subject to the license terms 3 | // in the LICENSE file found in the top-level directory of this distribution 4 | // and at www.steinberg.net/sdklicenses. 5 | // No part of the SDK, including this file, may be copied, modified, propagated, 6 | // or distributed except according to the terms contained in the LICENSE file. 7 | //----------------------------------------------------------------------------- 8 | 9 | #include "pluginterfaces/vst/vsttypes.h" 10 | #include "pluginterfaces/base/ipluginbase.h" 11 | #include "pluginterfaces/vst/ivstaudioprocessor.h" 12 | #include "pluginterfaces/vst/ivstcomponent.h" 13 | #include "pluginterfaces/vst/ivstcontextmenu.h" 14 | #include "pluginterfaces/vst/ivsteditcontroller.h" 15 | #include "pluginterfaces/vst/ivstevents.h" 16 | #include "pluginterfaces/vst/ivstnoteexpression.h" 17 | #include "pluginterfaces/vst/ivstprocesscontext.h" 18 | #include "pluginterfaces/vst/ivstrepresentation.h" 19 | #include "pluginterfaces/vst/ivstunits.h" 20 | 21 | extern "C" { 22 | #include "vst3_c_api.h" 23 | } 24 | 25 | namespace Steinberg { 26 | 27 | /*ipluginbase.h*/ 28 | static_assert (sizeof (struct Steinberg_PFactoryInfo) == sizeof (PFactoryInfo)); 29 | static_assert (sizeof (struct Steinberg_PClassInfo) == sizeof (PClassInfo)); 30 | static_assert (sizeof (struct Steinberg_PClassInfo2) == sizeof (PClassInfo2)); 31 | static_assert (sizeof (struct Steinberg_PClassInfoW) == sizeof (PClassInfoW)); 32 | 33 | /*ivstaudioprocessor.h*/ 34 | static_assert (sizeof (struct Steinberg_Vst_ProcessSetup) == sizeof (Vst::ProcessSetup)); 35 | static_assert (sizeof (struct Steinberg_Vst_AudioBusBuffers) == sizeof (Vst::AudioBusBuffers)); 36 | static_assert (sizeof (struct Steinberg_Vst_ProcessData) == sizeof (Vst::ProcessData)); 37 | 38 | /*ivstcomponent.h*/ 39 | static_assert (sizeof (struct Steinberg_Vst_BusInfo) == sizeof (Vst::BusInfo)); 40 | static_assert (sizeof (struct Steinberg_Vst_RoutingInfo) == sizeof (Vst::RoutingInfo)); 41 | 42 | /*ivstcontextmenu.h*/ 43 | static_assert (sizeof (struct Steinberg_Vst_IContextMenuItem) == sizeof (Vst::IContextMenuItem)); 44 | 45 | /*ivsteditcontroller.h*/ 46 | static_assert (sizeof (struct Steinberg_Vst_ParameterInfo) == sizeof (Vst::ParameterInfo)); 47 | 48 | /*ivstevents.h*/ 49 | static_assert (sizeof (struct Steinberg_Vst_NoteOnEvent) == sizeof (Vst::NoteOnEvent)); 50 | static_assert (sizeof (struct Steinberg_Vst_NoteOffEvent) == sizeof (Vst::NoteOffEvent)); 51 | static_assert (sizeof (struct Steinberg_Vst_DataEvent) == sizeof (Vst::DataEvent)); 52 | static_assert (sizeof (struct Steinberg_Vst_PolyPressureEvent) == sizeof (Vst::PolyPressureEvent)); 53 | static_assert (sizeof (struct Steinberg_Vst_ChordEvent) == sizeof (Vst::ChordEvent)); 54 | static_assert (sizeof (struct Steinberg_Vst_ScaleEvent) == sizeof (Vst::ScaleEvent)); 55 | static_assert (sizeof (struct Steinberg_Vst_LegacyMIDICCOutEvent) == sizeof (Vst::LegacyMIDICCOutEvent)); 56 | static_assert (sizeof (struct Steinberg_Vst_Event) == sizeof (Vst::Event)); 57 | 58 | /*ivstnoteexpression.h*/ 59 | static_assert (sizeof (struct Steinberg_Vst_NoteExpressionValueDescription) == sizeof (Vst::NoteExpressionValueDescription)); 60 | static_assert (sizeof (struct Steinberg_Vst_NoteExpressionValueEvent) == sizeof (Vst::NoteExpressionValueEvent)); 61 | static_assert (sizeof (struct Steinberg_Vst_NoteExpressionTextEvent) == sizeof (Vst::NoteExpressionTextEvent)); 62 | static_assert (sizeof (struct Steinberg_Vst_NoteExpressionTypeInfo) == sizeof (Vst::NoteExpressionTypeInfo)); 63 | static_assert (sizeof (struct Steinberg_Vst_KeyswitchInfo) == sizeof (Vst::KeyswitchInfo)); 64 | 65 | /*ivstprocesscontext.h*/ 66 | static_assert (sizeof (struct Steinberg_Vst_FrameRate) == sizeof (Vst::FrameRate)); 67 | static_assert (sizeof (struct Steinberg_Vst_Chord) == sizeof (Vst::Chord)); 68 | static_assert (sizeof (struct Steinberg_Vst_ProcessContext) == sizeof (Vst::ProcessContext)); 69 | 70 | /*ivstrepresentation.h*/ 71 | static_assert (sizeof (struct Steinberg_Vst_RepresentationInfo) == sizeof (Vst::RepresentationInfo)); 72 | 73 | /*ivstunits.h*/ 74 | static_assert (sizeof (struct Steinberg_Vst_UnitInfo) == sizeof (Vst::UnitInfo)); 75 | static_assert (sizeof (struct Steinberg_Vst_ProgramListInfo) == sizeof (Vst::ProgramListInfo)); 76 | 77 | } // namespace 78 | 79 | -------------------------------------------------------------------------------- /validate_interfaces/main.c: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------------- 2 | // This file is part of a Steinberg SDK. It is subject to the license terms 3 | // in the LICENSE file found in the top-level directory of this distribution 4 | // and at www.steinberg.net/sdklicenses. 5 | // No part of the SDK, including this file, may be copied, modified, propagated, 6 | // or distributed except according to the terms contained in the LICENSE file. 7 | //----------------------------------------------------------------------------- 8 | 9 | #include 10 | 11 | #include "vst3_c_api.h" 12 | 13 | 14 | int main () 15 | { 16 | /*ipluginbase.h*/ 17 | assert (sizeof(struct Steinberg_PFactoryInfo) == 452); 18 | assert (sizeof(struct Steinberg_PClassInfo) == 116); 19 | assert (sizeof(struct Steinberg_PClassInfo2) == 440); 20 | assert (sizeof(struct Steinberg_PClassInfoW) == 696); 21 | 22 | /*ivstaudioprocessor.h*/ 23 | assert (sizeof(struct Steinberg_Vst_ProcessSetup) == 24); 24 | assert (sizeof(struct Steinberg_Vst_AudioBusBuffers) == 24); 25 | assert (sizeof(struct Steinberg_Vst_ProcessData) == 80); 26 | 27 | /*ivstcomponent.h*/ 28 | assert (sizeof(struct Steinberg_Vst_BusInfo) == 276); 29 | assert (sizeof(struct Steinberg_Vst_RoutingInfo) == 12); 30 | 31 | /*ivstcontextmenu.h*/ 32 | assert (sizeof(struct Steinberg_Vst_IContextMenuItem) == 264); 33 | 34 | /*ivsteditcontroller.h*/ 35 | assert (sizeof(struct Steinberg_Vst_ParameterInfo) == 792); 36 | 37 | /*ivstevents.h*/ 38 | assert (sizeof(struct Steinberg_Vst_NoteOnEvent) == 20); 39 | assert (sizeof(struct Steinberg_Vst_NoteOffEvent) == 16); 40 | assert (sizeof(struct Steinberg_Vst_DataEvent) == 16); 41 | assert (sizeof(struct Steinberg_Vst_PolyPressureEvent) == 12); 42 | assert (sizeof(struct Steinberg_Vst_ChordEvent) == 16); 43 | assert (sizeof(struct Steinberg_Vst_ScaleEvent) == 16); 44 | assert (sizeof(struct Steinberg_Vst_LegacyMIDICCOutEvent) == 4); 45 | assert (sizeof(struct Steinberg_Vst_Event) == 48); 46 | 47 | /*ivstnoteexpression.h*/ 48 | assert (sizeof(struct Steinberg_Vst_NoteExpressionValueDescription) == 32); 49 | assert (sizeof(struct Steinberg_Vst_NoteExpressionValueEvent) == 16); 50 | assert (sizeof(struct Steinberg_Vst_NoteExpressionTextEvent) == 24); 51 | assert (sizeof(struct Steinberg_Vst_NoteExpressionTypeInfo) == 816); 52 | assert (sizeof(struct Steinberg_Vst_KeyswitchInfo) == 536); 53 | 54 | /*ivstprocesscontext.h*/ 55 | assert (sizeof(struct Steinberg_Vst_FrameRate) == 8); 56 | assert (sizeof(struct Steinberg_Vst_Chord) == 4); 57 | assert (sizeof(struct Steinberg_Vst_ProcessContext) == 112); 58 | 59 | /*ivstrepresentation.h*/ 60 | assert (sizeof(struct Steinberg_Vst_RepresentationInfo) == 256); 61 | 62 | /*ivstunits.h*/ 63 | assert (sizeof(struct Steinberg_Vst_UnitInfo) == 268); 64 | assert (sizeof(struct Steinberg_Vst_ProgramListInfo) == 264); 65 | 66 | return 0; 67 | } 68 | -------------------------------------------------------------------------------- /validate_interfaces/test2.c: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------------- 2 | // This file is part of a Steinberg SDK. It is subject to the license terms 3 | // in the LICENSE file found in the top-level directory of this distribution 4 | // and at www.steinberg.net/sdklicenses. 5 | // No part of the SDK, including this file, may be copied, modified, propagated, 6 | // or distributed except according to the terms contained in the LICENSE file. 7 | //----------------------------------------------------------------------------- 8 | 9 | #include "vst3_c_api.h" 10 | 11 | void func () 12 | { 13 | 14 | } 15 | --------------------------------------------------------------------------------