mc support with min-api for
domkirke
Apr 11 2022 | 4:01 pm
Hello everyone!
We are currently developing the nn~ library with the min-api, that allows to embed any TorchScript model on Max/MSP in a light manner:
https://github.com/acids-ircam/nn_tilde
A multi-channel support would be a great add-on for the usability of our package ; unfortunately, we do not find any information/resource on how to do that with the min-api. Is this even possible and, if it is, where could we find the documentation?
Thanks a lot!
The ACIDS-IRCAM team
- SmokeDoepferEverydayApr 12 2022 | 8:18 am
- SmokeDoepferEverydayApr 12 2022 | 8:21 amand the examples: https://github.com/Cycling74/max-sdk/tree/main/source/mc
- 👽R∆J∆ The Resident ∆lien👽Apr 12 2022 | 5:19 pmfor the min-api (C++ based), i've not found much either beyond this: https://github.com/Cycling74/min-devkit/blob/main/source/projects/mc.min.info_tilde/mc.min.info_tilde.cppbut this project sounds amazing, (i've only learned a bit of 'PyTorch', facebook developer's python extension of the proper C++ based 'Torch'... very impressive as is), wishing you the best of luck!
- domkirkeApr 14 2022 | 3:52 pmThank you for your answers! Unfortunately, max-sdk is not compatible with the min-api, and the given example code analyzes MC inputs but does not show how to produce ones. But thank you anyway! :)
- testcaseApr 18 2022 | 12:40 amfirst I am just curious - have you wrapped the object using the mc wrapper and that is not the capability you need?
- domkirkeApr 18 2022 | 10:58 amWe have not tried, because indeed it is not the specific purpose of what we need ; indeed (tell me if I am wrong), wrapping the external for xN channels would require to duplicate the ML model xN times right? However, if you got any documentation on how to perform mc wrapping, it is always welcome :-)
- Isabel KaspriskieApr 18 2022 | 1:58 pmHi @domkirke,You can access max-sdk methods by using the `max::` namespace provided by the max-sdk-base. While it may not be as "clean" as the min API, it opens up to all of the possibilities that the Max SDK offers.
- testcaseApr 18 2022 | 5:43 pm(edited to fix some typos) @domkirke, the information on the wrapper is here.https://cycling74.com/sdk/max-sdk-8.2.0/chapter_mc.htmlif that isn't what you need (which is sounds like you don't) I don't think there is any class in the min-api that will work as is *without* mixing the min-api and max-sdk (the non wrapper mc stuff is also explained in link above). while you certainly don't want to arbitrarily mix these two I have found that there are ways you can safely do so. Unfortunately the min-api seems to be missing some essential things and the documentation is sparse so it takes some digging through the code and asking for help.I was curious after seeing your question about how one could do this and I came up with a simple bit of code that seems to work to show the concept of what I think you need to do. you will note the use of the maxclass_setup message to call things needed from the max-sdk, also the use of the C function which is getting the number of channels by accessing the chans attribute and how the minwrap casting works. there is no error checking in this and I have not tested it extensively but see if it makes sense. also note multichannelsignal on the outlet definition
#include "c74_min.h" using namespace c74::min; long simplemc_multichanneloutputs(c74::max::t_object* x, long index, long count); class simplemc_tilde : public object<simplemc_tilde>, public vector_operator<> { public: MIN_DESCRIPTION { "simple out" }; MIN_TAGS { "misc" }; MIN_AUTHOR { "anonymous" }; MIN_RELATED { "cycle~" }; inlet<> m_inlet { this, "messages" }; outlet<> m_outlet { this, "(multichannelsignal) output", "multichannelsignal" }; attribute<int> chans {this, "chans", 1, range { 1, 1024 } }; void operator()(audio_bundle input, audio_bundle output) { for (auto i = 0; i < output.frame_count(); ++i) { for (auto channel = 0; channel < output.channel_count(); ++channel) { auto out = output.samples(); out[channel][i] = channel; // will just outputs channel number } } } message<> maxclass_setup {this, "maxclass_setup", MIN_FUNCTION { c74::max::t_class* c = args[0]; c74::max::class_addmethod(c, (c74::max::method)simplemc_multichanneloutputs, "multichanneloutputs", c74::max::A_CANT, 0); return {}; } }; }; MIN_EXTERNAL(simplemc_tilde); long simplemc_multichanneloutputs(c74::max::t_object* x, long index, long count) { minwrap<simplemc_tilde>* ob = (minwrap<simplemc_tilde>*)(x); return ob->m_min_object.chans; }
- domkirkeApr 22 2022 | 4:03 pmHello Testcase! Thank you so much for you answer. Indeed, this seems to be an interesting solution, we'll investigate that next week and we'll post here how it came :-)
- benedikt.sailerMay 24 2022 | 5:34 amJust used this approach to automatically sync the number of output channels to the number of input channels my external receives. Works like a charm. It's important to note, that the chans variable from the example above NEEDS to be of type min::attribute<int> and can't just be a long, even though that's the return type of thelong simplemc_multichanneloutputs () function. When I tried just using a long class member max crashed...
- domkirkeMay 24 2022 | 10:16 amHello folks! We managed to develop a mc~ support thanks to your advices, everything is here : https://github.com/acids-ircam/nn_tildeHope that could help people wanting to develop mc support with the min-api. Thank you so much !
- Christopher PooveyJul 03 2022 | 2:59 pmHello everyone,This forum post has been very useful in getting me started, but I am having an issue just passing a multichannel signal through an external. I am quite new to authoring externals and it is likely I am doing something silly. The external adapts to an incoming mc signal fine, but it has issues reading the input channel and outputting it. I was indexing via the output channel before and it was crashing max and when I index from the input channel it does not pass the values correctly. I attached my cpp file and here is the code for the operator function. void operator()(audio_bundle input, audio_bundle output) {
void operator()(audio_bundle input, audio_bundle output) { for (auto i = 0; i < input.frame_count(); ++i) { for (auto channel = 0; channel < input.channel_count(); ++channel) { output.samples(channel)[i] = input.samples(channel)[i]; } } }
- S ShetaApr 11 2023 | 5:18 pm@BENEDIKT.SAILER Hi, it's been a while since this thread was posted but I was wondering if you could clarify how you adapted Testcase's code to sync the number of output channels to the number of input channels?