iffyloop / EasyVst

Easy-to-use VST3 wrapper for hosting VST3 plugins without JUCE or other frameworks
Other
57 stars 6 forks source link

Build instructions and example usage #1

Closed aidanswank closed 2 years ago

aidanswank commented 2 years ago

Hello! Very cool project, exactly what I was looking for! :) I have built SDL2 dependent projects before but I am confused on how to integrate the vst3sdk with your wrapper.

I downloaded the sdk from github, including submodules "pluginterfaces" and "public.sdk". I attempted to write a Makefile, including the headers required by EasyVst.h, but then I kept facing "Undefined symbols", presumably from missing .cpp files? I'm probably going about this all wrong, any insight to your build processes and usage would be greatly appreciated 🙏

Thanks

iffyloop commented 2 years ago

Hi! So sorry for such a late response. Here are the VST SDK files I include as part of my project, along with (of course) the EasyVst.cpp file from this repository:

public.sdk\source\vst\hosting\connectionproxy.cpp
public.sdk\source\vst\hosting\eventlist.cpp
public.sdk\source\vst\hosting\hostclasses.cpp
public.sdk\source\vst\hosting\module.cpp
public.sdk\source\vst\hosting\module_win32.cpp
public.sdk\source\vst\hosting\parameterchanges.cpp
public.sdk\source\vst\hosting\pluginterfacesupport.cpp
public.sdk\source\vst\hosting\plugprovider.cpp
public.sdk\source\vst\hosting\processdata.cpp
public.sdk\source\vst\utility\stringconvert.cpp
public.sdk\source\vst\vstinitiids.cpp

Try including those in your project and let me know if that fixes it. I've only tested with Visual Studio currently; haven't done anything with a Makefile or other operating systems yet but the plan is to add full cross-platform support eventually. Keep in mind that you'll need to modify the EasyVst::createView function here to add support for other platforms.

Not sure if you're still interested since it's been so long since you opened the issue, but if this is still something you're working on then let me know and I'd be happy to help you out! I can add a sample main.cpp file too showing how to properly initialize and use the EasyVst class.

aidanswank commented 2 years ago

Sorry for closing and reopening I did it by accident! I'm still new to github, feel free to mark it whatever you want No worries, thank you for your response!

I forgot to state that I was trying to compile for Mac OS I added the cpp files you listed to my project and it stopped compiling at the module_win32.cpp, which is understandable, so I naively changed it to module_mac.mm, then it told me #error this file needs to be compiled with automatic reference counting enabled so I added this flag fobjc-arc that I found online which seemed to fix it

It also told me error: DEVELOPMENT, RELEASE, _DEBUG, or NDEBUG must be defined! so I added -DDEVELOPMENT=1 flag as a preprocessor definition, which seemed to silence the error.

after that I got the error Undefined symbols for architecture x86_64: "Steinberg::FUnknownPrivate::atomicAdd(int&, int)"

Keep in mind that you'll need to modify the EasyVst::createView function here to add support for other platforms.

I looked up JUCEs vst3 wrapper to try to get some insight, it seems to do a similar kPlatformTypeHWND check here and below that line im guessing that kPlatformTypeNSView is the equivalent check on mac.

I can add a sample main.cpp file too showing how to properly initialize and use the EasyVst class.

Yes that would be helpful! Sorry for spewing a bunch of Mac and Makefile specific things at you. I currently have access to a computer running Windows 10 with Visual Studio 2019. I was thinking maybe you could share your visual studio project so I could first get it compiling on there as a point of reference and then slowing start porting it to Mac.

Thank you for time!

iffyloop commented 2 years ago

Nice job troubleshooting those Mac-related issues - I should've mentioned that module_win32.cpp needed to be modified depending on your platform but I forgot - sorry.

I looked up JUCEs vst3 wrapper to try to get some insight, it seems to do a similar kPlatformTypeHWND check here and below that line im guessing that kPlatformTypeNSView is the equivalent check on mac.

Yes, you are correct. You need to change this line to use kPlatformTypeNSView and this line to use cocoa.window instead of win.window I think but you might need to do something additional to convert the NSWindow to an NSView - let me know what works for you.

Yes that would be helpful! Sorry for spewing a bunch of Mac and Makefile specific things at you. I currently have access to a computer running Windows 10 with Visual Studio 2019. I was thinking maybe you could share your visual studio project so I could first get it compiling on there as a point of reference and then slowing start porting it to Mac.

No problem, and yes, I can make a Visual Studio project and share it with you. I have a lot going on this week but I'll try to get back to you by the weekend if possible. Ping me again here if I haven't uploaded a project and replied to you in a week. Sorry about the delay and thanks for your patience!

after that I got the error Undefined symbols for architecture x86_64: "Steinberg::FUnknownPrivate::atomicAdd(int&, int)"

I'll take a look at this when I am building the VS project and see if I can find where atomicAdd is defined.

aidanswank commented 2 years ago

Tried setting up a visual studio project and noticed similar atomicAdd errors telling me link libraries LNK2019 so it seemed I was doing the same mistake on both machines. I previously had built the vstsdk so I linked it like -L[MYPATH]/vst3sdk/public.sdk/build/lib/Debug and then I added all the lib files in that folder Im not sure if they are all needed

-lauv3wrappermacos \
-lbase \
-lpluginterfaces \
-lsdk_hosting \
-lsdk_common \
-lsdk \
-lvstgui_standalone \
-lvstgui_support \
-lvstgui_uidescription \
-lvstgui \

added a main file and it compiled!

Changed if (_view->isPlatformTypeSupported(Steinberg::kPlatformTypeNSView) != Steinberg::kResultTrue) { and when I passed wmInfo.info.cocoa.window into _view->attached it gave me

2022-07-12 00:59:48.274 app[47781:5940397] -[SDLWindow addSubview:]: unrecognized selector sent to instance 0x7fbf3b443160
2022-07-12 00:59:48.283 app[47781:5940397] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[SDLWindow addSubview:]: unrecognized selector sent to instance 0x7fbf3b443160'
*** First throw call stack:
(
        0   CoreFoundation                      0x00007fff204914bf __exceptionPreprocess + 242
        1   libobjc.A.dylib                     0x00007fff201c9bbb objc_exception_throw + 48
        2   CoreFoundation                      0x00007fff20513fc8 -[NSObject(NSObject) __retain_OA] + 0
        3   CoreFoundation                      0x00007fff203f964d ___forwarding___ + 1448
        4   CoreFoundation                      0x00007fff203f9018 _CF_forwarding_prep_0 + 120
        5   ExaktLite                           0x0000000114ded35f _ZN5iplug9igraphics12IGraphicsMac10OpenWindowEPv + 271
        6   ExaktLite                           0x0000000114e784be _ZThn16_N13IPlugVST3ViewIN5iplug9IPlugVST3EE8attachedEPvPKc + 62
        7   app                                 0x0000000104d3e37d _ZN7EasyVst10createViewEv + 1149
        8   app                                 0x0000000104d4614f main + 175
        9   libdyld.dylib                       0x00007fff20339f5d start + 1
)
libc++abi: terminating with uncaught exception of type NSException
zsh: abort      ./app

As you suspected it seemed to give me trouble with NSWindow and had to convert to an NSView I found a SDL_MetalView function and attached it like this

SDL_MetalView metalview = SDL_Metal_CreateView(_window);
if (_view->attached(metalview, Steinberg::kPlatformTypeNSView) != Steinberg::kResultOk) {

I tested on Exakt Lite, a free vst3. Not sure if im setting up input correctly, my mouse remains unresponsive in the plugin. Had to make _window member public to pass into SDL_CreateRenderer, Im probably doing something wrong What does symbolicSampleSize and maxBlockSize mean? I put in random values

#include "EasyVst.h"

int main()
{
    SDL_Init(SDL_INIT_EVERYTHING);

    EasyVst easyvst;
    easyvst.init("/Library/Audio/Plug-Ins/VST3/ExaktLite.vst3",44100,512,512,true);
    easyvst.createView();

    SDL_Renderer *renderer = SDL_CreateRenderer(easyvst._window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);

    bool isRunning = true;

    SDL_Event e;

    while(isRunning)
    {
        while (SDL_PollEvent(&e))
        {
            if (e.type == SDL_QUIT)
            {
                isRunning = false;
            }
            easyvst.processSdlEvent(e);
        }
        SDL_RenderPresent(renderer);
    }

    return 0;
}
Screen Shot 2022-07-12 at 12 40 51 AM

debug output:

Debug info for VST3 plugin "/Library/Audio/Plug-Ins/VST3/ExaktLite.vst3": Buses: 0 audio and 1 event inputs; 1 audio and 1 event outputs
Error loading VST3 plugin "/Library/Audio/Plug-Ins/VST3/ExaktLite.vst3": Failed to setup VST processing

Thank you so much for your help and for making this wrapper!! Im going to try to add microphone and rtmidi input likely soon

iffyloop commented 2 years ago

and then I added all the lib files in that folder Im not sure if they are all needed

I am so sorry, I forgot to tell you about this as well. In VS you add them in a separate directory rather than appending them with -l flags as you do on macOS.

Great, great work getting everything compiled and running!

Had to make _window member public to pass into SDL_CreateRenderer, Im probably doing something wrong

I'm not sure why that would be; simply calling createView should be enough to make the window appear without needing to create a renderer yourself. Maybe a macOS issue? I can look into it more later.

What does symbolicSampleSize and maxBlockSize mean? I put in random values

symbolicSampleSize indicates the number of bits the plugin should use for the input and output streams (this is not the same as the bitness of your OS which is almost guaranteed to be 64). The easy way to decide is that if you're using float* arrays for your input then symbolicSampleSize should be kSample32 whereas if you're using double* arrays then it should be kSample64.

maxBlockSize indicates the maximum number of samples your app will try to pull from the plugin during any process call. For example, if you're processing 512 samples during every audio callback, then you set maxBlockSize to 512. You are allowed to pull less than maxBlockSize, although IIRC some plugins will crackle or glitch if you don't consistently pull the same block size on every process call.

Failed to setup VST processing

I'm really not sure why this is failing though, that's worrisome (probably means you'll get no audio output). Looks like Exakt Lite is a free plugin though so hopefully I can download it and test it on Windows at least this weekend.

P.S. Before you call setProcessing you probably need to call setBusActive and activate the appropriate I/O buses. (Event buses are for MIDI, and audio buses are for audio). To append events you have to call eventList and then modify its structure, and to pull audio out, you access channelBuffers32/channelBuffers64 (depending on your symbolicSampleSize). I will send you examples for all this once the VS project is online this weekend.

aidanswank commented 2 years ago

I'm not sure why that would be; simply calling createView should be enough to make the window appear

That was my mistake sorry! I was testing incorrectly, it works as intended.

Thank you for the explanations, passing kSample32 as the symbolicSampleSize fixed the Failed to setup VST processing error.

Excited to start studying the example project whenever its ready :)

iffyloop commented 2 years ago

Great! Glad things are working better now. I uploaded a sample with RtMidi for you: https://github.com/blitcrush/EasyVst/blob/main/examples/SimpleMidiExample.cpp

Unfortunately, including an entire ready-to-compile project would be quite inconvenient, given the size of the VST3 SDK. Nevertheless, given that you were able to compile everything and display a window earlier, I don't think you'll have much more difficulty. Thank you again for providing such detailed information in your comments above, that will make things much easier for other macOS users!

At the top of SimpleMidiExample.cpp are a few links to additional dependencies (specifically needed for the example) you'll need to add to your project to compile it - notably, cameron314/concurrentqueue, portaudio, and RtMidi - if you need more directions then let me know but these should be easier to integrate than the main VST3 SDK.

I don't have time to write much more now, but let me know if you run into issues getting that example compiled and I'm happy to help tomorrow. Hope this helps!

aidanswank commented 2 years ago

Thank you so much for the example!! super helpful. Got everything compiled and running, works great I also got just the basic vst window working on windows 10 and noticed that mouse click events work there but not on my mac. It was super strange, all the plugins I tried reacted to hovering over gui elements and keyboard shortcuts but when clicked on did nothing. So I reassessed the SDL_Metal_CreateView function I added and looked over the "editorhost" example in the vst3sdk.

On line 328 in editorhost.cpp it had a similar line if (plugView->attached (platformWindow.ptr, platformWindow.type) != kResultTrue) which used this function from this window.mm Objective-C++ file, I guess its like apple flavored c++

NativePlatformWindow Window::getNativePlatformWindow () const
{
    auto nsWindow = impl->nsWindowDelegate.nsWindow;
    return {kPlatformTypeNSView, (__bridge void*) ([nsWindow contentView])};
}

What I did in order to get mouse click events working on my mac was copy the casting in function above (? i think thats they are doing but I have no idea how apples language works) and changed it to take in the NSWindow pointer from SDL and return a void pointer. I put it in a small separate objective-c++ file. Also did a forward declaration of the function below in EasyVst.h in order to access it from within c++

#import <Cocoa/Cocoa.h>

void* getNSView(NSWindow* nsWindow)
{
    return (__bridge void*)([nsWindow contentView]);
}

and in EasyVst.cpp removed SDL_Metal_CreateView(_window) stuff and passed in the original cocoa.window into getNSView.

if (_view->attached( getNSView(wmInfo.info.cocoa.window), Steinberg::kPlatformTypeNSView ) != Steinberg::kResultOk)

Is this what you meant by

something additional to convert the NSWindow to an NSView

? I should've listened to you more attentively 😭 . I read on the apple docs Mouse events are dispatched by an NSWindow object to the NSView object over which the event occurred. My guess is that something was lost when just calling SDL_Metal_CreateView directly?

Heres a pastebin of my makefile for SimpleMidiExample.cpp, might be helpful for any mac users

iffyloop commented 2 years ago

Glad it's working for you! Thanks for posting that info above and for the Makefile. Hopefully at some point I'll be able to get these changes integrated into the main codebase, but for now this will be a good help to anyone else trying to set up the library on macOS. I'll go ahead and close the issue now since it sounds like everything's working - feel free to reopen it, or file a new issue if you need help with something else.