Using Max SDK in MIN Devkit Projects: A How To Guide
Hi all,
If you've worked with Min Devkit enough to recognize how awesome it is, you might also have run into a few of its limitations when working with Max's more advanced features such as dictionaries, notifications, UI objects, etc.
Min Devkit is a wrapper around Max SDK, and in fact, the entire Max SDK Base is included in the min-api folder. Mixing and matching Min Devkit and Max SDK takes some care. There are also a few essential, undocumented, setup components that need to be addressed before you're able to do anything substantial here. The notes below are assembled from my learnings across several threads in this forum. Thanks especially to 11OLSEN and Rob Ramirez for all the support.
Two Methods for Using Max SDK in Min Devkit Projects
1) Call Max SDK Functions in Min Devkit Source Code
If you want to use a feature of the Max SDK that isn't fully implement in Min, you can call any Max SDK function by prefixing it with c74::max. For example: c74::max::object_notify().
A couple of caveats here:
Be sure to call Max SDK functions in the equivalent section of the Min Object. For example, if the function needs to be called in the constructor, or message function of a Max SDK object, be sure to call it in the constructor or message function of your Min Object.
maxobj() will return a t_object pointer to the present min object. You can use it where a Max SDK function requires a t_object* for the present object.
max-sdk uses common-symbols (e.g. _sym_dictionary, etc) all over the place, but this is not something min exposes or wraps. One solution is to use c74::max::gensym() wherever these symbols are present. But it is also possible to give Min access to these symbols. I prefer this solution because then max-sdk functions will work in Min out of the box without additional tweaking. Two things are required to do this:
firstm include common_syms.c into your project. This can be achieved by modifying your project's cmakelists to include the file as shown below. Make the change to the cmakelists in the same folder as your source code file, not the cmakelists in the package root. Don't forget to regenerate your solution after modifying any cmakelists file.
set( SOURCE_FILES
${PROJECT_NAME}.cpp
${MAX_SDK_INCLUDES}/common/common_syms.c
)second, you must call c74::max::common_symbols_init(); in your object constructor (or at some other initialization point, prior to when the symbols are referenced).
Follow these suggestions and you should be able to leverage most of the Max features supported by MaxSDK inside MinDevkit.
2) Create a Max SDK Object in a Min Devkit Solution
Sometimes calling a few Max SDK functions inside a Min object is not sufficient. Min's support for UI Objects is either incomplete, incompletely documented, or both. You might run into something that can be done in Max SDK that is very difficult to achieve in Min (textfields are a good example). In this case it can be easier just to build a Min SDK object and include it in your MinDevkit package.
There are probably a few ways to do this. Below is my preferred solution:
1) Create a new Min Object the way you normally would.
2) Delete the contents of the source file.
3) Replace the contents of the source file with well-formed Max SDK source code. Ideally, paste in an entire example from the Max-SDK.
4) Somewhere early in the ext_main function you will find the line where class_new() creates the class.
In the simplemax example from Max SDK it looks like this:
c = class_new("simplemax", (method)simplemax_new, (method)simplemax_free, ....
The first argument, the string in quotes, needs to match the name of your file. So if your source file is "MyNewObject.cpp" then the first argument of class_new() should be "MyNewObject". eg:
c = class_new("MyNewObject", (method)simplemax_new, (method)simplemax_free, ...
You can replace the name of your template (in this case, simplemax) throughout the code, but the only one that matter is the first argument of class_new(). If you don't do this, your object will appear red in Max and there will be no indicator as to why.
5) You could stop here, but it's possible to go a step further. Delete all the includes from the top of the file. Replace them with:
#include "c74_min.h"
using namespace c74::max;
Now we are literally running Max SDK inside of Min. We could even call Min functions inside it using the c74::min:: prefix. (Very cool in theory, use in practice at your own risk)
Most importantly, the new Max SDK object is running entirely on modern C++ which means you get access to the C++ standard libraries and any third party C++ libs you want to use.
IMPORTANT:
The same concern about common symbols applies. Be sure to include common_syms.c in your cmakelists.txt as described above.
IMPORTANT FOR UI OBJECTS:
UI Objects in Max SDK also require jpatcher_syms.c. Include this as well using the same method.
Your cmakelists.txt for a Min object that uses Max SDK to create a UI Object should have the following:set( SOURCE_FILES
${PROJECT_NAME}.cpp
${MAX_SDK_INCLUDES}/common/commonsyms.c
${MAX_SDK_INCLUDES}/common/jpatcher_syms.c
)
Armed with this, you should be able achieve anything Max SDK is capable of inside a Min Devkit Package.
I hope this is helpful to someone. I offer it as gratitude to the folks who helped me figure this stuff out.
@Joe Kaplan Thank you for this guide!
In your experience, how would you recommend using the MaxSDK in Min fft objects (i.e. objects inside a pfft~
)?
`t_pfftpub` is not a structure of the Min API and it is declared in `r_pfft.h` (inside the MaxSDK). I have seen example of its use to get access to the fft size
t_pfftpub *pfft = (t_pfftpub*)gensym("__pfft~__")->s_thing;
if (pfft)
x->fftsize = pfft->x_fftsize;
else
x->fftsize = 512;
____________
p.s. I guess there is a typo here:
if your source file is "MyNewObject.cpp" then the first argument of class_new() should be "MyPatch"
"the first argument of a class_new() should be MyNewObject"
as you corretly write in the code example
HI DDGG,
Thanks for your note. I'm glad this was helpful to someone. Appreciate you pointing out the typos. I made an edit and corrected the one you noted and a few other things.
As for your question:
I have not done any work with fft in min devkit or Max SDK. The discoveries in this guide were prompted by a need to get some very specific behaviors from a UI object. (which I'm excited to report is now fully functioning as desired)
For my work, I wound up going with option 1 above. Which would probably be my first preference in all cases, whenever possible. If find Min is just so much easier to work with than MaxSDK. Once you get a build environment set up, it's really quite amazing how easy Min is, imho.
As for your particular code, I dropped it into my Max-SDK enabled Min Devkit object. (i.e. with common_sym.c included and initialized). Remember that to use MaxSDK elements you have to prefix them with the MaxSDK namespace: c74::max. You could also just use the c74::max namespace inside a block.
{
using namespace c74::max;
t_pfftpub* pfft = (t_pfftpub*)gensym("__pfft~__")->s_thing;
if (pfft)
x->fftsize = pfft->x_fftsize;
else
x->fftsize = 512;
}
The only things the linter was upset about was t_pfftpub and x. t_pfftpub is a type that doesn't seem to be defined in MaxSDK by default. When I looked at the fftinfo~.c example in Max SDK, I noticed it includes a special header, "r_pfft.h," which contains a definition of t_pfftpub.
I tossed #include r_pfft.h at the top of my Min file, and then the linter found the definition for t_pfftpub and all was good except for the pointer assigned to x.
Looking more closely at fftinfo~.c, the definition of x is a bit complicated. I don't know Max SDK very well, and I really don't know fft. It may be that that x corresponds to some other element that is already defined by the MinDevikit boilerplate. In which case you could use that instead. I think the exact solution requires a deeper understanding of fftinfo~.c, which I lack.
But I suspect that if you follow the example and figure out what that x is referring to and make sure it is initialized properly in your Min file then you might be good to go.
I hope that helps. Please share how it goes for you!
This would be very good to have as an "article" on here so it doesn't just get lost in the forum posts!