{"id":1412,"date":"2018-10-16T11:37:46","date_gmt":"2018-10-16T18:37:46","guid":{"rendered":"http:\/\/tre.ucsd.edu\/wordpress\/?p=1412"},"modified":"2018-10-16T11:38:38","modified_gmt":"2018-10-16T18:38:38","slug":"mus-177206-two-simple-audio-externals-softclip-and-rms","status":"publish","type":"post","link":"https:\/\/tre.ucsd.edu\/wordpress\/?p=1412","title":{"rendered":"MUS 177\/206 &#8211; two simple audio externals: softclip~ and rms~"},"content":{"rendered":"<p>source for softclip~. this shows how to pass the object structure &#8220;x&#8221; into the audio perform function.<\/p>\n<pre>#include \"m_pd.h\"\r\n#include \r\n#include \r\n#ifdef NT\r\n#pragma warning( disable : 4244 )\r\n#pragma warning( disable : 4305 )\r\n#endif\r\n\r\n\/* ------------------------ softclip~ ----------------------------- *\/\r\n\r\n\/* tilde object to do a simple soft clipping algorithm. *\/\r\n\r\nstatic t_class *softclip_class;\r\n\r\ntypedef struct _softclip\r\n{\r\n    t_object x_obj; \t\/* obligatory header *\/\r\n    t_float gain;    \t\/* floats on the first inlet set the gain *\/\r\n\tt_float sample_rate;\r\n    t_float freq;\r\n} t_softclip;\r\n\r\n    \/* this is the actual performance routine which acts on the samples.\r\n    It's called with a single pointer \"w\" which is our location in the\r\n    DSP call list.  We return a new \"w\" which will point to the next item\r\n    after us.  Meanwhile, w[0] is just a pointer to dsp-perform itself\r\n    (no use to us), w[1] and w[2] are the input and output vector locations,\r\n    and w[3] is the number of points to calculate. *\/\r\nstatic t_int *softclip_perform(t_int *w)\r\n{\r\n\tt_softclip *x = (t_softclip *)(w[1]);\r\n    t_float *in = (t_float *)(w[2]);\r\n    t_float *out = (t_float *)(w[3]);\r\n    int n = (int)(w[4]);\r\n\r\n\t\/\/ i like counting from zero, so i use samplenumber to count the offset from\r\n\t\/\/ the start of the in and out blocks\r\n\tint samplenumber = 0;\r\n\tfloat a = -0.5f;\r\n\tfloat b = 0.0;\r\n\tfloat c = 1.5f;\r\n\tfloat d = 0.0;\r\n\tfloat ingain;\r\n\r\n    while (n--)\r\n    {\r\n\t\tingain = x-&gt;gain * *(in+samplenumber);\r\n\t\tif(ingain &gt; 1)\r\n\t\t\t*(out+samplenumber) = 1.0f;\r\n\t\telse if(ingain &lt; -1) \t\t\t*(out+samplenumber) = -1.0f; \t\telse \t\t\t*(out+samplenumber) = a * ingain * ingain * ingain \t\t\t\t\t\t\t+ b * ingain * ingain \t\t\t\t\t\t\t+ c * ingain \t\t\t\t\t\t\t+ d; \t\tsamplenumber++;     }     return (w+5); }     \/* called to start DSP.  Here we call Pd back to add our perform     routine to a linear callback list which Pd in turn calls to grind     out the samples. *\/ static void softclip_dsp(t_softclip *x, t_signal **sp) { \tx-&gt;sample_rate = sp[0]-&gt;s_sr;\r\n    dsp_add(softclip_perform, 4, x, sp[0]-&gt;s_vec, sp[1]-&gt;s_vec, sp[0]-&gt;s_n);\r\n}\r\n\r\nstatic void *softclip_new(void)\r\n{\r\n    t_softclip *x = (t_softclip *)pd_new(softclip_class);\r\n    x-&gt;freq = 432.0f;\r\n   outlet_new(&amp;x-&gt;x_obj, gensym(\"signal\"));\r\n    return (x);\r\n}\r\n\r\n    \/* this routine, which must have exactly this name (with the \"~\" replaced\r\n    by \"_tilde) is called when the code is first loaded, and tells Pd how\r\n    to build the \"class\". *\/\r\nvoid softclip_tilde_setup(void)\r\n{\r\n    softclip_class = class_new(gensym(\"softclip~\"), (t_newmethod)softclip_new, 0,\r\n    \tsizeof(t_softclip), 0, A_DEFFLOAT, 0);\r\n\t\r\n\t\/* this is magic to declare that the leftmost, \"main\" inlet\r\n\t    takes signals; other signal inlets are done differently... *\/\r\n\t\/* also installs gain as the leftmost inlet float *\/\r\n    CLASS_MAINSIGNALIN(softclip_class, t_softclip, gain);\r\n\t\r\n\t\/* here we tell Pd about the \"dsp\" method, which is called back\r\n\twhen DSP is turned on. *\/\r\n    class_addmethod(softclip_class, (t_method)softclip_dsp, gensym(\"dsp\"), (t_atomtype)0);\r\n}\r\n<\/pre>\n<p>source for rms~. this shows how to allocate and deallocate an array<\/p>\n<pre>\r\n#include \"m_pd.h\"\r\n#include <stdlib.h>\r\n#include <math.h>\r\n#ifdef NT\r\n#pragma warning( disable : 4244 )\r\n#pragma warning( disable : 4305 )\r\n#endif\r\n\r\n\/* ------------------------ rms~ ----------------------------- *\/\r\n\r\n\/* tilde object to take the absolute value of a signal at audio rate *\/\r\n\/* an argument for window size may be entered upon instantiation *\/\r\n\r\nstatic t_class *rms_class;\r\n\r\ntypedef struct _rms\r\n{\r\n    t_object x_obj;\t\t\t\/\/ obligatory variable\r\n    t_float x_f;\t\t\t\/\/ stores message recieved on audio inlet\r\n\tt_int window;\t\t\t\/\/ window size set by object argument\r\n\tt_float sum;\t\t\t\/\/ running sum of squared values\r\n\tt_float *squaretab;\t\t\/\/ table to hold squared values\r\n\tt_int tabread1;\t\t\t\/\/ pointer offset for newest table value\r\n\tt_int tabread2;\t\t\t\/\/ pointer offset for oldest table value\r\n} t_rms;\r\n\r\nstatic t_int *rms_perform(t_int *w)\r\n{\r\n\tt_rms *x = (t_rms *)(w[1]);\r\n    t_float *in = (t_float *)(w[2]);\r\n    t_float *out = (t_float *)(w[3]);\r\n    int n = (int)(w[4]);\r\n\r\n\t\/\/ number of samples passed\r\n\tint blocksize = n;\r\n\t\/\/ sample from 0 up\r\n\tint sample = 0;\r\n\t\/\/ mean of squared value\r\n\tfloat mean = 0;\r\n\t\/\/ used to multiply instead of divide\r\n\tfloat oneOverWindow = 1.0f\/x->window;\r\n\r\n    while (n--)\r\n    {\r\n\t\t\/\/ store newest squared value in the table\r\n    \t*(x->squaretab+x->tabread1) = *(in+sample) * *(in+sample);\r\n\t\t\/\/ add this value to the running sum\r\n\t\tx->sum += *(x->squaretab+x->tabread1);\r\n\t\t\/\/ subtract the oldest value in the table\r\n\t\tx->sum -= *(x->squaretab+x->tabread2);\r\n\r\n\t\t\/\/ compute the current mean value\r\n    \tmean = x->sum * oneOverWindow;\r\n\r\n\t\t\/\/ take the square root and send the value to outlet\r\n        \r\n    \t*(out+sample) = sqrt(mean);\r\n\t\t\/\/ increment to next sample\r\n\t\tsample++;\r\n\t\t\/\/ increment to next table position\r\n        x->tabread1++;\r\n        x->tabread2++;\r\n\t\t\/\/ reset to beginning of table\r\n\t\tif(x->tabread1 >= x->window)\r\n\t\t\tx->tabread1 = 0;\r\n\t\t\/\/ increment to next table position\r\n \t\t\/\/ reset to beginning of table\r\n\t\tif(x->tabread2 >= x->window)\r\n\t\t\tx->tabread2 = 0;\r\n    }\r\n    return (w+5);\r\n}\r\n\r\nstatic void rms_dsp(t_rms *x, t_signal **sp)\r\n{\r\n    dsp_add(rms_perform, 4, x, sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n);\r\n}\r\n\r\n\/\/ setting window size\r\nvoid rms_windowset(t_rms *x, t_floatarg f)\r\n{\r\n\t\/\/ using a good value\r\n\tif( f >= 256 && f <= 4096 )\r\n\t\tx->window = f;\r\n\t\/\/ blocking bad values\r\n\telse if( f < 256 )\r\n\t{\r\n\t\tx->window = 256;\r\n\t\tpost(\"rms~: window size must be set to a value between 256 and 4096\");\r\n\t}\r\n\telse if( f > 4096 )\r\n\t{\r\n\t\tx->window = 4096;\r\n\t\tpost(\"rms~: window size must be set to a value between 256 and 4096\");\r\n\t}\r\n}\r\n\r\nstatic void *rms_new(t_floatarg f)\r\n{\r\n\tint i;\r\n\t\r\n    t_rms *x = (t_rms *)pd_new(rms_class);\r\n    outlet_new(&x->x_obj, gensym(\"signal\"));\r\n\tx->squaretab = 0;\r\n    x->x_f = 0;\r\n\t\/\/ initialize the sum\r\n\tx->sum = 0;\r\n\t\/\/ changing windowsize on creation\r\n\trms_windowset(x, f);\r\n\t\/\/ intializing table for largest window size\r\n    x->squaretab = (t_float *)malloc(4097 * sizeof(t_float));\r\n\t\/\/ initialzing the table to 0\r\n\tfor( i = 0; i < x->window; i++)\r\n\t\t*(x->squaretab+i) = 0;\r\n\t\/\/ initializing newest sample\r\n\tx->tabread1 = 0;\r\n\t\/\/ initializing oldest sample\r\n\tx->tabread2 = 1;\r\n\r\n    return (x);\r\n}\r\n\r\n\/\/ function to clear the allocated square table\r\nstatic void rms_free(t_rms *x)\r\n{\r\n    free(x->squaretab);\r\n\tif(x->squaretab != 0)\r\n\t{\r\n\t\tfree(x->squaretab);\r\n\t\tx->squaretab = 0;\r\n\t}\r\n}\r\n\r\nvoid rms_tilde_setup(void)\r\n{\r\n    rms_class = class_new(gensym(\"rms~\"), (t_newmethod)rms_new, (t_method)rms_free,\r\n    \tsizeof(t_rms), 0, A_DEFFLOAT, 0);\r\n    CLASS_MAINSIGNALIN(rms_class, t_rms, x_f);\r\n    class_addmethod(rms_class, (t_method)rms_dsp, gensym(\"dsp\"), (t_atomtype)0);\r\n}\r\n<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>source for softclip~. this shows how to pass the object structure &#8220;x&#8221; into the audio perform function. #include &#8220;m_pd.h&#8221; #include #include #ifdef NT #pragma warning( disable : 4244 ) #pragma warning( disable : 4305 ) #endif \/* &#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212; softclip~ &#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211; &hellip; <a href=\"https:\/\/tre.ucsd.edu\/wordpress\/?p=1412\">Continue reading <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[21,23],"tags":[],"_links":{"self":[{"href":"https:\/\/tre.ucsd.edu\/wordpress\/index.php?rest_route=\/wp\/v2\/posts\/1412"}],"collection":[{"href":"https:\/\/tre.ucsd.edu\/wordpress\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/tre.ucsd.edu\/wordpress\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/tre.ucsd.edu\/wordpress\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/tre.ucsd.edu\/wordpress\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=1412"}],"version-history":[{"count":2,"href":"https:\/\/tre.ucsd.edu\/wordpress\/index.php?rest_route=\/wp\/v2\/posts\/1412\/revisions"}],"predecessor-version":[{"id":1414,"href":"https:\/\/tre.ucsd.edu\/wordpress\/index.php?rest_route=\/wp\/v2\/posts\/1412\/revisions\/1414"}],"wp:attachment":[{"href":"https:\/\/tre.ucsd.edu\/wordpress\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=1412"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/tre.ucsd.edu\/wordpress\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=1412"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/tre.ucsd.edu\/wordpress\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=1412"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}