diff options
-rw-r--r-- | doc/tutorials/externals-howto/LICENSE.txt | 48 | ||||
-rw-r--r-- | doc/tutorials/externals-howto/example1/helloworld.c | 2 | ||||
-rw-r--r-- | doc/tutorials/externals-howto/example2/counter.c | 2 | ||||
-rw-r--r-- | doc/tutorials/externals-howto/example3/counter.c | 202 | ||||
-rw-r--r-- | doc/tutorials/externals-howto/example4/pan~.c | 146 |
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); +} |