Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for REAPER's cockos.reaper_extension? #110

Open
nofishonfriday opened this issue Nov 14, 2022 · 12 comments
Open

Support for REAPER's cockos.reaper_extension? #110

nofishonfriday opened this issue Nov 14, 2022 · 12 comments

Comments

@nofishonfriday
Copy link

Hi,

Cockos has just added support for CLAP plugins being able to access the REAPER API in their pre-release versions ( link to changelog) .
Curious (as I'm still a beginner with the clap-juce-extensions), can we use/access this out of the box with the current version or would it need a code modification?
And if the latter, would it be something considerable for the future?

Thanks.

@baconpaul
Copy link
Collaborator

So I was looking at this for surge also. I haven't written the code yet but let me jot notes here (especially if you are interested in taking a shot at it).

the answer is "yes" but we just need to plumb it through.

The extension is something you can just get with HostProxy::getExtension (https://github.com/free-audio/clap-helpers/blob/4d4e297947382d2a9d00a469af61e43332463ebf/include/clap/helpers/host-proxy.hh#L24) so the question is how do you get from your AudioProcessor to a HostProxy instance. Basically we want your AudioProcessor to be able to do something like (clap-juce-extensions-somewhere)->getHost()->getExtension(&reaper_info, "cokocs.reaper-info") or what not.

The way to do this, I think (and how I would do it) is

in include/clap-juce-extensions/clap-juce-extensions.h

  1. At the end of the capabilities class in the private section add a new function which is probably something like
    std::function<bool(void *, const char*)> extensionGet{nullptr}
  2. In the public section add
      { auto res = extensionGet((void *)&t, id);  
      }
      else return false; }```
    
    

so this will give you, if you implement the extensions, the ability to do reaper_info_t info; if (getExtension(info, "cokocs.reaper-thingy")) ... in your juce class

So the only thing left then is to set that lambda to something in the startup path. In src/wrapper/clap-juce-wrapper.cpp you can see this code

        if (processorAsClapExtensions != nullptr)
        {
            processorAsClapExtensions->parameterChangeHandler =
                [this](const clap_event_param_value *paramEvent) {
                    handleParameterChangeEvent(paramEvent);
                };
            processorAsClapExtensions->lookupParamByID = [this](clap_id param_id) {
                return findVariantByParamId(param_id);
            };
        };

soo to that you should be able to do something like set the extensionGet to [this](a, b) {host->extensioNGet(a,b);}

anyway that's shorthand. If you think you want to take a swing at it would be happy to review, and if not, can def get to it after thanksgiving or earlier if its pressing.

@nofishonfriday
Copy link
Author

Thanks for the quick and thorough reply.
It's definitely not pressing (hadn't planned to do anything specific with it currently).
I may give it a shot (aka PR), but if you get round to it earlier that's also fine (and much appreciated).
Thanks again.

@baconpaul
Copy link
Collaborator

Yeah we’ve kinda used surge to highlight the things which are possible so I kinda want to do something. The only thing is I don’t know reaper well enough to know what a cool feature would be with this api!! All ears for ideas

@nofishonfriday
Copy link
Author

nofishonfriday commented Nov 14, 2022

Admittedly I don't come up spontaneously with something too.
But in general all Reaper's API functions should be accessible with it.
Not sure if the host functions/context available for VST are available for CLAP also.
Anyway I'll post back if I come up with something which I think that could be cool. :)

@jatinchowdhury18
Copy link
Collaborator

Yeah, this seems like a cool thing to have! And it makes sense that the same approach could be used for other DAWs with host-specific APIs. I think Paul's sketch of the implementation seems about right. I think it would also be nice to have an example plugin in this repo that does something simple: I'm thinking a drop-down menu that changes the colour of the track the plugin is on? I should have time for some hacking on this over the Thanksgiving holiday.

@giohappy
Copy link

@jatinchowdhury18 did you have the chance to make any progress on this?

I'm totally new to CLAP but I would certainly digg into it if the interoperability with Reaper API and its host methods was confirmed.

@jatinchowdhury18
Copy link
Collaborator

@giohappy I did not... but I spent 5-10 minutes on it just now. I've pushed my work to a branch in case you (or anyone else) wants to take a look: main...jatinchowdhury18:clap-juce-extensions:reaper-ext

We can query Reaper for the extension, and Reaper gives us back something that is not nullptr, so that seems promising! I haven't yet tried to cast it to a reaper_plugin_info_t and then actually try to do anything useful with it, but that seems like it would be the logical next step.

@jatinchowdhury18
Copy link
Collaborator

Another few minutes of hacking today... muting a track through the Reaper API works!

Screen.Recording.2023-10-11.at.9.41.56.AM.mov

@giohappy
Copy link

@jatinchowdhury18 great! Thanks for sharing it, I will test it ASAP.

@giohappy
Copy link

giohappy commented Oct 11, 2023

@jatinchowdhury18 I was able to run it. Thanks!

I'm not an expert in C++. Is there any difference between this (your code):

MediaTrack *(*getTrackFunc)(ReaProject *, int);
*((void **)&getTrackFunc) = reaperPluginExtension->GetFunc("GetTrack");
auto *track0 = (*getTrackFunc)(nullptr, 0);

and this (what I would have done)?:

void *(*getTrackFunc)(ReaProject *, int);
getTrackFunc = reinterpret_cast<void *(*)(ReaProject *, int)>(reaperPluginExtension->GetFunc("GetTrack"));
auto *track0 = reinterpret_cast<MediaTrack *>((*getTrackFunc)(nullptr, 0));

And are you going to open a PR to have getExtension/extensionGet added to clap-juce-exntesions?

@jatinchowdhury18
Copy link
Collaborator

No problem!

Those code snippets look equivalent to me. I was using this example from the Reaper SDK as a reference.

You might be able to simply your version a little bit if you define the function pointer return type, since then you shouldn't need the second reinterpret_cast.

MediaTrack *(*getTrackFunc)(ReaProject *, int);
getTrackFunc = reinterpret_cast<MediaTrack *(*)(ReaProject *, int)>(reaperPluginExtension->GetFunc("GetTrack"));
auto *track0 = (*getTrackFunc)(nullptr, 0);

There's probably some ways to clean it up further with using declarations as well.


I do plan to open a PR for the extension-related changes, but there's a couple things I'd like to do first:

  1. Currently the plugin can't access use getExtension() in its constructor, since it hasn't been initialized yet. I'd like to see if there's a way to re-order some things which could make that possible.
  2. I want to clean up the example a bit more... maybe even fork those changes into their own example plugin for better clarity, and to avoid adding too much stuff to the current example.

@jatinchowdhury18
Copy link
Collaborator

Having some fun with track colours:

#136 should be ready soon which will make getExtension() available and add this new example plugin.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants