aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/tutorials/externals-howto/LICENSE.txt48
-rw-r--r--doc/tutorials/externals-howto/example1/helloworld.c2
-rw-r--r--doc/tutorials/externals-howto/example2/counter.c2
-rw-r--r--doc/tutorials/externals-howto/example3/counter.c202
-rw-r--r--doc/tutorials/externals-howto/example4/pan~.c146
5 files changed, 398 insertions, 2 deletions
diff --git a/doc/tutorials/externals-howto/LICENSE.txt b/doc/tutorials/externals-howto/LICENSE.txt
new file mode 100644
index 00000000..4f5d55aa
--- /dev/null
+++ b/doc/tutorials/externals-howto/LICENSE.txt
@@ -0,0 +1,48 @@
+"HOWTO write Externals for Pure data" by IOhannes m zmölnig
+
+This work consists of a HOWTO-text (possibly in various translations) and
+accompanying material (example source code files, Makefiles,...)
+
+
+1. License for the HOWTO-text:
+==============================
+
+The text is licensed under the Creative Commons Attribution-ShareAlike 2.5 License.
+To view a copy of this license, visit http://creativecommons.org/licenses/by-sa/2.5/
+or send a letter to
+ Creative Commons, 543 Howard Street, 5th Floor, San Francisco, California, 94105, USA.
+
+
+2. License for the accompanying material (examples,...)
+=======================================================
+
+This software is copyrighted by IOhannes m zmölnig. The following
+terms (the "Standard Improved BSD License") apply to all files associated with
+the software unless explicitly disclaimed in individual files:
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+3. The name of the author may not be used to endorse or promote
+ products derived from this software without specific prior
+ written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY
+EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/doc/tutorials/externals-howto/example1/helloworld.c b/doc/tutorials/externals-howto/example1/helloworld.c
index 43682997..e93a6e0f 100644
--- a/doc/tutorials/externals-howto/example1/helloworld.c
+++ b/doc/tutorials/externals-howto/example1/helloworld.c
@@ -6,7 +6,7 @@
* it creates an object that prints "Hello world!" whenever it
* gets banged.
*
- * this file is released under Pd's license (BSD-like)
+ * for legal issues please see the file LICENSE.txt
*/
diff --git a/doc/tutorials/externals-howto/example2/counter.c b/doc/tutorials/externals-howto/example2/counter.c
index afc72335..6c4787c2 100644
--- a/doc/tutorials/externals-howto/example2/counter.c
+++ b/doc/tutorials/externals-howto/example2/counter.c
@@ -6,7 +6,7 @@
* it creates an object that increments and outputs a counter
* whenever it gets banged.
*
- * this file is released under Pd's license (BSD-like)
+ * for legal issues please see the file LICENSE.txt
*/
diff --git a/doc/tutorials/externals-howto/example3/counter.c b/doc/tutorials/externals-howto/example3/counter.c
new file mode 100644
index 00000000..4eee6a5e
--- /dev/null
+++ b/doc/tutorials/externals-howto/example3/counter.c
@@ -0,0 +1,202 @@
+/*
+ * HOWTO write an External for Pure data
+ * (c) 2001-2006 IOhannes m zmölnig zmoelnig[AT]iem.at
+ *
+ * this is the source-code for the third example in the HOWTO
+ * it creates an object that increments and outputs a counter
+ * whenever it gets banged.
+ * the counter value can be "set" to a special value, or "reset" to a default
+ * an upper and lower boundary can be specified: whenever the counter crosses
+ * such boundary a "bang" is emitted at the 2nd outlet and the counter value wraps
+ *
+ * for legal issues please see the file LICENSE.txt
+ */
+
+
+/**
+ * include the interface to Pd
+ */
+#include "m_pd.h"
+
+
+/**
+ * define a new "class"
+ */
+static t_class *counter_class;
+
+
+/**
+ * this is the dataspace of our new object
+ * the first element is the mandatory "t_object"
+ * then we have all sort of variables for the
+ * actual counter value, the step-size and the counting boundaries
+ * finally we have 2 "t_outlet" elements so we can send data
+ * to a "named" outlet.
+ */
+typedef struct _counter {
+ t_object x_obj; /* mandatory t_object */
+ t_int i_count; /* the current counter value */
+ t_float step; /* step size;
+ * this is "float" because of the passive inlet we are using */
+ t_int i_down, i_up; /* lower and upper boundary */
+ t_outlet *f_out, *b_out; /* outlets */
+} t_counter;
+
+
+/**
+ * this method is called whenever a "bang" is sent to the object
+ */
+void counter_bang(t_counter *x)
+{
+ t_float f=x->i_count;
+ t_int step = x->step;
+ x->i_count+=step;
+
+ if (x->i_down-x->i_up) {
+ if ((step>0) && (x->i_count > x->i_up)) {
+ x->i_count = x->i_down;
+ /* we crossed the upper boundary, so we send a bang out of
+ * the 2nd outlet (which is x->b_out)
+ */
+ outlet_bang(x->b_out);
+ } else if (x->i_count < x->i_down) {
+ x->i_count = x->i_up;
+ outlet_bang(x->b_out);
+ }
+ }
+ /* output the current counter value at the 1st outlet (which is x->f_out) */
+ outlet_float(x->f_out, f);
+}
+
+
+/**
+ * this is called whenever a "reset" message is sent to the inlet of the object
+ * since the "reset" message has no arguments (as declared in counter_setup())
+ * we only get a reference to the class-dataspace
+ */
+void counter_reset(t_counter *x)
+{
+ x->i_count = x->i_down;
+}
+
+
+/**
+ * this is called whenever a "set" message is sent to the inlet of the object
+ * since the "set" message has one floating-point argument (as declared in counter_setup())
+ * we get a reference to the class-dataspace and the value
+ */
+void counter_set(t_counter *x, t_floatarg f)
+{
+ x->i_count = f;
+}
+
+
+/**
+ * this is called whenever a "bound" message is sent to the inlet of the object
+ * note that in counter_new(), we rewrite a list to the 2nd inlet
+ * to a "bound" message to the 1st inlet
+ */
+void counter_bound(t_counter *x, t_floatarg f1, t_floatarg f2)
+{
+ x->i_down = (f1<f2)?f1:f2;
+ x->i_up = (f1>f2)?f1:f2;
+}
+
+
+/**
+ * this is the "constructor" of the class
+ * we expect a variable number of arguments to this object
+ * symbol "s" is the name of the object itself
+ * the arguments are given as a t_atom array of argc elements.
+ */
+void *counter_new(t_symbol *s, int argc, t_atom *argv)
+{
+ t_counter *x = (t_counter *)pd_new(counter_class);
+ t_float f1=0, f2=0;
+
+ /* depending on the number of arguments we interprete them differently */
+ x->step=1;
+ switch(argc){
+ default:
+ case 3:
+ x->step=atom_getfloat(argv+2);
+ case 2:
+ f2=atom_getfloat(argv+1);
+ case 1:
+ f1=atom_getfloat(argv);
+ break;
+ case 0:
+ }
+ if (argc<2)f2=f1;
+
+ x->i_down = (f1<f2)?f1:f2;
+ x->i_up = (f1>f2)?f1:f2;
+
+ x->i_count=x->i_down;
+
+ /* create a new active inlet for this object
+ * a message with the selector "list" that is sent
+ * to this inlet (it is the 2nd inlet from left),
+ * will be appear to be the same message but with the selector "bound"
+ * at the 1st inlet.
+ * the method for "bound" messages is given in counter_setup()
+ */
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd,
+ gensym("list"), gensym("bound"));
+
+ /* create a passive inlet inlet (it will be the 2rd inlet from left)
+ * whenever a floating point number is sent to this inlet,
+ * its value will be immediately stored in "x->step"
+ * no function will be called
+ */
+ floatinlet_new(&x->x_obj, &x->step);
+
+ /* create a new outlet which will output floats
+ * we store a reference to this outlet in x->f_out
+ * so we are able to send data to this very outlet
+ */
+ x->f_out = outlet_new(&x->x_obj, &s_float);
+ /* create a new outlet which will output bangs */
+ x->b_out = outlet_new(&x->x_obj, &s_bang);
+
+ return (void *)x;
+}
+
+
+/**
+ * define the function-space of the class
+ */
+void counter_setup(void) {
+ counter_class = class_new(gensym("counter"),
+ (t_newmethod)counter_new,
+ 0, sizeof(t_counter),
+ CLASS_DEFAULT,
+ A_GIMME, /* an arbitrary number of arguments
+ * which are of arbitrary type */
+ 0);
+
+ /* call a function when a "bang" message appears on the first inlet */
+ class_addbang (counter_class, counter_bang);
+
+ /* call a function when a "reset" message (without arguments) appears on the first inlet */
+ class_addmethod(counter_class,
+ (t_method)counter_reset, gensym("reset"), 0);
+
+ /* call a function when a "set" message with one float-argument (defaults to 0)
+ * appears on the first inlet */
+ class_addmethod(counter_class,
+ (t_method)counter_set, gensym("set"),
+ A_DEFFLOAT, 0);
+
+ /* call a function when a "bound" message with 2 float-argument (both default to 0)
+ * appears on the first inlet
+ * this is used for "list" messages which appear on the 2nd inlet
+ * the magic is done in counter_new()
+ */
+ class_addmethod(counter_class,
+ (t_method)counter_bound, gensym("bound"),
+ A_DEFFLOAT, A_DEFFLOAT, 0);
+
+ /* set the name of the help-patch to "help-counter"(.pd) */
+ class_sethelpsymbol(counter_class, gensym("help-counter"));
+}
diff --git a/doc/tutorials/externals-howto/example4/pan~.c b/doc/tutorials/externals-howto/example4/pan~.c
new file mode 100644
index 00000000..06dccd69
--- /dev/null
+++ b/doc/tutorials/externals-howto/example4/pan~.c
@@ -0,0 +1,146 @@
+/*
+ * HOWTO write an External for Pure data
+ * (c) 2001-2006 IOhannes m zmölnig zmoelnig[AT]iem.at
+ *
+ * this is the source-code for the fourth example in the HOWTO
+ * it creates a simple dsp-object:
+ * 2 input signals are mixed into 1 output signal
+ * the mixing-factor can be set via the 3rd inlet
+ *
+ * for legal issues please see the file LICENSE.txt
+ */
+
+
+/**
+ * include the interface to Pd
+ */
+#include "m_pd.h"
+
+
+/**
+ * define a new "class"
+ */
+static t_class *pan_tilde_class;
+
+
+/**
+ * this is the dataspace of our new object
+ * the first element is the mandatory "t_object"
+ * f_pan denotes the mixing-factor
+ * "f" is a dummy and is used to be able to send floats AS signals.
+ */
+typedef struct _pan_tilde {
+ t_object x_obj;
+ t_sample f_pan;
+ t_sample f;
+} t_pan_tilde;
+
+
+/**
+ * this is the core of the object
+ * this perform-routine is called for each signal block
+ * the name of this function is arbitrary and is registered to Pd in the
+ * pan_tilde_dsp() function, each time the DSP is turned on
+ *
+ * the argument to this function is just a pointer within an array
+ * we have to know for ourselves how many elements inthis array are
+ * reserved for us (hint: we declare the number of used elements in the
+ * pan_tilde_dsp() at registration
+ *
+ * since all elements are of type "t_int" we have to cast them to whatever
+ * we think is apropriate; "apropriate" is how we registered this function
+ * in pan_tilde_dsp()
+ */
+t_int *pan_tilde_perform(t_int *w)
+{
+ /* the first element is a pointer to the dataspace of this object */
+ t_pan_tilde *x = (t_pan_tilde *)(w[1]);
+ /* here is a pointer to the t_sample arrays that hold the 2 input signals */
+ t_sample *in1 = (t_sample *)(w[2]);
+ t_sample *in2 = (t_sample *)(w[3]);
+ /* here comes the signalblock that will hold the output signal */
+ t_sample *out = (t_sample *)(w[4]);
+ /* all signalblocks are of the same length */
+ int n = (int)(w[5]);
+ /* get (and clip) the mixing-factor */
+ t_sample f_pan = (x->f_pan<0)?0.0:(x->f_pan>1)?1.0:x->f_pan;
+ /* just a counter */
+ int i;
+
+ /* this is the main routine:
+ * mix the 2 input signals into the output signal
+ */
+ for(i=0; i<n; i++)
+ {
+ out[i]=in1[i]*(1-f_pan)+in2[i]*f_pan;
+ }
+
+ /* return a pointer to the dataspace for the next dsp-object */
+ return (w+6);
+}
+
+
+/**
+ * register a special perform-routine at the dsp-engine
+ * this function gets called whenever the DSP is turned ON
+ * the name of this function is registered in pan_tilde_setup()
+ */
+void pan_tilde_dsp(t_pan_tilde *x, t_signal **sp)
+{
+ /* add pan_tilde_perform() to the DSP-tree;
+ * the pan_tilde_perform() will expect "5" arguments (packed into an
+ * t_int-array), which are:
+ * the objects data-space, 3 signal vectors (which happen to be
+ * 2 input signals and 1 output signal) and the length of the
+ * signal vectors (all vectors are of the same length)
+ */
+ dsp_add(pan_tilde_perform, 5, x,
+ sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec, sp[0]->s_n);
+}
+
+
+/**
+ * this is the "constructor" of the class
+ * the argument is the initial mixing-factir
+ */
+void *pan_tilde_new(t_floatarg f)
+{
+ t_pan_tilde *x = (t_pan_tilde *)pd_new(pan_tilde_class);
+
+ /* save the mixing factor in our dataspace */
+ x->f_pan = f;
+
+ /* create a new signal-inlet */
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_signal, &s_signal);
+
+ /* create a new passive inlet for the mixing-factor */
+ floatinlet_new (&x->x_obj, &x->f_pan);
+
+ /* create a new signal-outlet */
+ outlet_new(&x->x_obj, &s_signal);
+
+ return (void *)x;
+}
+
+
+/**
+ * define the function-space of the class
+ * within a single-object external the name of this function is very special
+ */
+void pan_tilde_setup(void) {
+ pan_tilde_class = class_new(gensym("pan~"),
+ (t_newmethod)pan_tilde_new,
+ 0, sizeof(t_pan_tilde),
+ CLASS_DEFAULT,
+ A_DEFFLOAT, 0);
+
+ /* whenever the audio-engine is turned on, the "pan_tilde_dsp()"
+ * function will get called
+ */
+ class_addmethod(pan_tilde_class,
+ (t_method)pan_tilde_dsp, gensym("dsp"), 0);
+ /* if no signal is connected to the first inlet, we can as well
+ * connect a number box to it and use it as "signal"
+ */
+ CLASS_MAINSIGNALIN(pan_tilde_class, t_pan_tilde, f);
+}