Max/MSP externals in C++

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.

Download

maxcpp.zip (includes headers, examples and Xcode project)

Max externals

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

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);
}

Externals with text editors

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);
}