This page describes a template header file for constructing Max/MSP externals from C++ classes, in a friendly and readable manner. The core notion is that an instance of the external is encapsulated by an instance of the C++ class.
maxcpp.zip (includes headers, examples and Xcode project)
Max externals built using this template automatically gain the @enable attribute (accessible in a C++ instance as the member variable maxEnable). The class variable maxClassName identifies (as a char *) the name of the external.
For example:
#include "max.cpp.h"
/*
The external's class
*/
class Example : public MaxCpp<Example>
{
public:
Example(t_symbol * s = 0, long ac = 0, t_atom * av = 0);
~Example() {};
// methods:
void bang();
void test(t_symbol * s, long ac, t_atom * av);
};
Example::Example(t_symbol *s, long ac, t_atom *av)
: MaxCpp<Example>()
{
// remember to set any defaults before attribute args are processed!
attr_args_process(this, ac, av);
}
void Example :: bang()
{
post("%s bang", maxClassName);
}
void Example :: test(t_symbol * s, long argc, t_atom * argv)
{
post("%s %p call %s %i args", maxClassName, this, s->s_name, argc);
}
// called when library is loaded
extern "C" int main(void)
{
t_class * c = Example::maxMakeClass("example");
// add some methods:
REGISTER_METHOD(Example, bang);
REGISTER_METHOD_GIMME(Example, test);
// register this as a class for Max UI & store static reference
class_register(CLASS_BOX, c);
}
MSP externals gain all the benefits of the Max external template, plus a helper wrapper for the DSP function. Input and output buffers are passed in as signalArray references, which are simply typedefs of std::vector<t_sample *>. Thus individual inlet and outlet channels are accessible as ins[n] and outs[n], and individual samples as ins[chan][samp], and the number of signal inlets is ins.size() etc.
For example:
#include "max.cpp.h"
/*
The external's class
*/
class ExampleMSP : public MaxCpp<ExampleMSP>
{
public:
ExampleMSP(t_symbol * s = 0, long ac = 0, t_atom * av = 0);
~ExampleMSP();
// callback for an MSP external:
void doDsp(unsigned long vs, signalArray & ins, signalArray & outs);
};
ExampleMSP::ExampleMSP(t_symbol *s, long ac, t_atom *av)
: MaxCpp<ExampleMSP>()
{
// create signal inlets & outlets:
maxMSPCreate(2, 2);
// remember to set any defaults before attribute args are processed!
attr_args_process(this, ac, av);
}
ExampleMSP :: ~ExampleMSP()
{
// For all MSP objects: call this *before* freeing any memory etc:
maxMSPEnd();
}
void ExampleMSP :: doDsp(unsigned long vs, signalArray & ins, signalArray & outs)
{
// demo: copy inputs to outputs:
for (unsigned int c=0;c < ins.size();c++)
{
float * in = ins[c];
float * out = outs[c];
for (unsigned int i=0; i< vs; i++) { out[i] = in[i]; }
}
}
// called when library is loaded
extern "C" int main(void)
{
// create class and register DSP callback:
t_class * c = ExampleMSP::maxMSPMakeClass("example~", &ExampleMSP::doDsp);
// register this as a class for Max UI & store static reference
class_register(CLASS_BOX, c);
}
This class provides a set of helper functions & attributes for editing associated text files. The associated file is set with the @file attribute. When this file changes (if @autowatch is set to 1) or is loaded, the instance method doScript is called. The @autosave attribute, when set to 1, will save the file automatically each time the editor window is closed (rather than prompting the user). The @fontsize attribute sets the size of the text editor font. Double click on the external, or send the message open, to open a text editor for the associated file. Send the message settext to change the text contents (and save them to file).
For example:
#include "max.cpp.h"
#include "max.cpp.file.h"
/*
The external's class
*/
class ExampleText : public MaxCpp<ExampleText>, public MaxFile<ExampleText>
{
public:
ExampleText(t_symbol * s = 0, long ac = 0, t_atom * av = 0);
~ExampleText() {};
// callback for a text editor external:
void doScript(char * script);
};
ExampleText::ExampleText(t_symbol *s, long ac, t_atom *av)
: MaxCpp<ExampleText>(), MaxFile<ExampleText>()
{
// remember to set any defaults before attribute args are processed!
attr_args_process(this, ac, av);
}
void ExampleText :: doScript(char * s)
{
// demo: print text to Max window:
post("%s loaded text %s", maxClassName, s);
}
// called when library is loaded
extern "C" int main(void)
{
t_class * c = ExampleText::maxMakeClass("exampletext");
// initialize text editor and register script callback:
ExampleText::initMaxFileClass(c, &ExampleText::doScript);
// register this as a class for Max UI & store static reference
class_register(CLASS_BOX, c);
}