package com.cycling74.max; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.util.HashMap; import com.e1.pdj.*; import java.util.*; import com.cycling74.msp.MSPObject; /** * Main object to extend to use with pd. The name of this class will * reflect the name of the pdj object when it is instanciated. *
Here is a basic guideline for using the MaxObject:
*** * import com.cycling74.max.*; * * public class example extends MaxObject { * * // called when arguments are used in object creation * public example(Atom args[]) { * for(int i=0;i<args.length;i++) { * post("args:" + args[i].toString()); * } * } * * // this method will be called when a float is sended to the object * public inlet(float f) { * post("hello float:" + f); * outlet(0, f); * } * * // this method will be called when symbol callme is sended to the object * public callme(Atom args[]) { * post("hello object:" + args[0]); * outlet(0, args[0]); * } * * // this method will be called when bang is sended to the object * public bang() { * post("hello bang"); * outletBang(0); * } * } *
Compile this class by adding pdj.jar on the classpath and put the * example.class in the classes directory found in your pdj home. * You can also edit directly this class in the classes directory * and pdj will try to compile it for you.
*/ public class MaxObject { /** * Native C pdj object pointer. */ private long _pdobj_ptr; /** * Native C inlet pointers. */ private long _outlets_ptr[]; /** * Native C outlets pointers. */ private long _inlets_ptr[]; /** * The last inlet that received a message. */ private int _activity_inlet; private String name; private HashMap attributes = new HashMap(); private boolean toCreateInfoOutlet = true; private MaxPatcher patch = new MaxPatcher(); // useless statics.... /** * Use this to declare that your object has no inlets. */ public static final int[] NO_INLETS = {}; /** * Use this to declare that your object has no outlets. */ public static final int[] NO_OUTLETS = {}; /** * Defined in the original MXJ API; don't know what it is used for... */ public static final String[] EMPTY_STRING_ARRAY = {}; /** * Default constructor for MaxObject. You can add an constructor that * supports Atom[] to read object creation arguments. It is not defined * in this API since it does not to force a 'super()' call in all the * extended class. */ protected MaxObject() { synchronized (MaxObject.class) { _pdobj_ptr = popPdjPointer(); } name = this.getClass().getName(); patch.patchPath = getPatchPath(); } /** * Will show an error message in the pure-data console. * @param message the string to show */ public static void error(String message) { MaxSystem.error(message); } /** * Will show an info message in the pure-data console. * @param message the string to show */ public static void post(String message) { MaxSystem.post(message); } /** * Will show an error message in the pure-data console and crash * pure-data. Do not use if you have no friend left. * @param message the message to show when you make pd crash */ public static void ouch(String message) { MaxSystem.ouch(message); } /** * Show the exeception in the pure-data console. * @param t the exception it self */ public static void showException(Throwable t) { t.printStackTrace(PDJSystem.err); } /** * Show the exception in the pure-data console with a message. * @param message the message that comes with the exception * @param t the exception it self */ public static void showException(String message, Throwable t) { PDJSystem.err.println(message); t.printStackTrace(PDJSystem.err); } /** * Returns the object name. * @return the pdj object name */ public String getName() { return name; } /** * Sets the object name. * @param name pdj object name */ public void setName(String name) { this.name = name; } /** * This method is called when the object is deleted by the user. */ public void notifyDeleted() { } /** * Bail will throw an exception upon object instanciation. This is usefull * if you have a missing requirement and you want to cancel object creation. * @param errormsg the error message to show */ protected static void bail(String errormsg) { throw new PDJError(errormsg); } /** * Declare the inlets used by this object. * @see com.cycling74.max.DataTypes * @param types the type of message that this inlet will use. */ protected void declareInlets(int[] types) { if ( _inlets_ptr != null ) { throw new IllegalStateException(name + ": inlets already defined"); } _inlets_ptr = new long[types.length]; int pos = 0; for(int i=0; ioutlet(int, float)
otherwise outlet(int, String)
* @param outlet the outlet number to use
* @param value the atom value to send
* @return always true, since PD API returns void
*/
public final boolean outlet(int outlet, Atom value) {
if ( value.isFloat() || value.isInt() ) {
doOutletFloat(_outlets_ptr[outlet], value.toFloat());
} else {
doOutletSymbol(_outlets_ptr[outlet], value.toString());
}
return true;
}
/**
* Sends atoms to outlet x. If the array contains only one item,
* outlet(outlet, Atom value)
will be called. If the
* first element of the array is a float/int, list will be
* appended to the message. Otherwise, the first atom will be the
* message and the rest of it the arguments.
* @param outlet the outlet number to use
* @param value the arguments
* @return true or false if atom[] is empty
*/
public final boolean outlet(int outlet, Atom[] value) {
if ( value.length == 0 )
return false;
if ( value.length == 1 ) {
outlet(outlet, value[0]);
} else {
doOutletAnything(_outlets_ptr[outlet], null, value);
}
return true;
}
// user methods
/////////////////////////////////////////////////////////////
/**
* Called by PD when pdj receives a bang from an inlet. Use
* getInlet()
to know which inlet has received the message.
*/
protected void bang() {
}
/**
* This will be called if pd sends a float and the float method is not
* overridden. Use getInlet()
to know which inlet has
* received the message.
* @param i int value
*/
protected void inlet(int i) {
}
/**
* Called by PD when pdj receives a float from an inlet. Use
* getInlet()
to know which inlet has received the message.
* @param f float value received from the inlet
*/
protected void inlet(float f) {
}
/**
* Called by PD when pdj receives a list of atoms. Use
* getInlet()
to know which inlet has received the message.
* @param args the list
*/
protected void list(Atom args[]) {
}
/**
* Called by PD when pdj receives an un-overriden method. If you need
* to catch all messages, override this method. Use getInlet()
* to know which inlet has received the message.
* @param symbol first atom symbol representation
* @param args the arguments of the message
*/
protected void anything(String symbol, Atom[] args) {
post("pdj: object '" + name + "' doesn't understand " + symbol);
}
// compatibility methods
/////////////////////////////////////////////////////////////
public final boolean outletBangHigh(int outlet) {
return outletBang(outlet);
}
public final boolean outletHigh(int outlet, int value) {
return outlet(outlet, value);
}
public final boolean outletHigh(int outlet, float value) {
return outlet(outlet, value);
}
public final boolean outletHigh(int outlet, double value) {
return outlet(outlet, value);
}
public final boolean outletHigh(int outlet, String value) {
return outlet(outlet, value);
}
public final boolean outletHigh(int outlet, String msg, Atom[] args) {
return outlet(outlet, msg, args);
}
public final boolean outletHigh(int outlet, Atom[] value) {
return outlet(outlet, value);
}
/**
* Returns the output stream of PDJ.
* @return the PrintStream output stream of PDJ
*/
public static com.cycling74.io.PostStream getPostStream() {
return new com.cycling74.io.PostStream();
}
/**
* Returns the error stream of PDJ.
* @return the PrintStream error stream of PDJ
*/
public static com.cycling74.io.ErrorStream getErrorStream() {
return new com.cycling74.io.ErrorStream();
}
// unimplementable methods
/////////////////////////////////////////////////////////////
/**
* NOT USED IN PD.
*/
public void viewsource() {
}
/**
* NOT USED IN PD. Throws UnsupportdOperationException
*/
public static Object getContext() {
throw new UnsupportedOperationException();
}
/**
* Returns the object representing the pd patch.
*/
public MaxPatcher getParentPatcher() {
return patch;
}
/**
* NOT USED IN PD.
*/
protected void save() {
}
/**
* NOT USED IN PD.
*/
protected void setInletAssist(String[] messages) {
}
/**
* NOT USED IN PD.
*/
protected void setInletAssist(int index, String message) {
}
/**
* NOT USED IN PD.
*/
protected void setOutletAssist(String[] messages) {
}
/**
* NOT USED IN PD.
*/
protected void setOutletAssist(int index, String message) {
}
/**
* NOT USED IN PD.
*/
protected void embedMessage(String msg, Atom[] args) {
}
/**
* Useless, but in the original API.
*/
public void gc() {
System.gc();
}
/**
* Refresh/reinitialize the PDJ classloader.
*/
public void zap() {
PDJClassLoader.resetClassloader();
}
// not from original class
/////////////////////////////////////////////////////////////
/**
* Tries to get the attribute name[0] and send its value to
* the last outlet.
* @param name the name of the attribute
*/
void get(Atom[] name) throws IllegalAccessException, InvocationTargetException {
String attrName = name[0].toString();
if ( attributes.containsKey(attrName) ) {
Attribute attr = (Attribute) attributes.get(attrName);
outlet(_outlets_ptr.length-1, attr.get());
} else {
error(this.name + ": attribute not defined '" + attrName + "'");
}
}
/**
* Called by pdj to check if it is possible to set value x.
* @param the name of the setter
* @param arg [0] the value to set
* @return true if the setter has been set
*/
private boolean _trySetter(String name, Atom[] arg) {
if ( !attributes.containsKey(name) )
return false;
Attribute attr = (Attribute) attributes.get(name);
attr.set(arg);
return true;
}
/**
* Tries to instantiate a MaxObject.
* @param name fq java name
* @param _pdobj_ptr C pointer to pd object
* @param args objects arguments
*/
static synchronized MaxObject registerObject(String name, long _pdobj_ptr, Atom[] args_complete) {
try {
Class clz = PDJClassLoader.dynamicResolv(name);
MaxObject obj = null;
// map arguments and attributes
List largs = new ArrayList();
List lattr = new ArrayList();
for (int i=1;i