{"id":43,"date":"2023-07-25T11:53:47","date_gmt":"2023-07-25T11:53:47","guid":{"rendered":"https:\/\/atled.it\/atled\/?p=43"},"modified":"2023-07-27T14:09:37","modified_gmt":"2023-07-27T14:09:37","slug":"creating-an-object-with-max-sdk","status":"publish","type":"post","link":"https:\/\/atled.it\/atled\/it\/creating-an-object-with-max-sdk\/","title":{"rendered":"Creating an Object with MAX Sdk"},"content":{"rendered":"<p class=\"wp-block-paragraph\">La Software Development Kit di Cycling \u00e8 una libreria che permette, una volta aggiunta tra i packages di Max, di programmare un nuovo oggetto per Max stesso. Ho letto la documentazione ufficiale ed ho fatto qualche prova; questo articolo \u00e8 il riassunto di quanto ho concluso.<\/p>\n\n\n<p class=\"wp-block-paragraph translation-block\">L'idea \u00e8 quella di realizzare, in linguaggio C, un oggetto che permetta di filtrare un rumore bianco (o anche un rumore alternativo) attorno ad una specifica nota, ottenendo un suono il pi\u00f9 intonato possibile.<br>\nPartendo dall modello matematico di un filtro passa basso, ho definito la formulazione pi\u00f9 semplice che permettesse di isolare una banda di frequenze abbastanza stretta e con un taglio abbastanza netto: si tratta di un filtro passa basso con un'importante resonance sulla frequenza di taglio, che otterr\u00f2 tramite la seguente formula:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img decoding=\"async\" src=\"https:\/\/nicolafiorello.it\/articles\/creazione-oggetto-max-sdk\/eq1.png\" alt=\"\"\/><\/figure>\n\n\n<p class=\"wp-block-paragraph\">where&nbsp;<em>s<\/em>,&nbsp;<em>a1<\/em>&nbsp;and&nbsp;<em>a2<\/em>&nbsp;are coefficients to be calculated each time, based on even at the required cut-off frequency.<\/p>\n\n\n<p class=\"wp-block-paragraph\">The object will be called&nbsp;<em>notefilter~<\/em>, and the advice to start writing its behavior in C is to clone the folder of one of the audio object examples (<em>Max\/Packages\/max-sdk\/source\/audio<\/em>) and clear the&nbsp;<em>.c<\/em>&nbsp;file, renaming appropriately all files it contains. In this way you quickly obtain a project already structured with libraries in their place. Personally I worked with Max 8, using Visual Studio in its free version. If you are using (as it is likely to be) 64-bit Max, I remind you to select that mode in the Visual Studio drop-down menu!<br>Here&#8217;s how I wrote the&nbsp;<em>notefilter.c&nbsp;<\/em>file, step by step.<\/p>\n\n\n<p class=\"wp-block-paragraph\">I have included the libraries necessary for the functioning of an audio object, and I have defined the object class, calling it&nbsp;<em>notefilter_class<\/em><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>#include \"ext.h\"\n#include \"ext_obex.h\"\n#include \"z_dsp.h\"\n#include &lt;math.h&gt;\n\nvoid *notefilter_class;<\/code><\/pre>\n\n\n<p class=\"wp-block-paragraph\">then specifying the parameters, the first of which (t_pxobject l_obj) is indispensable for the correct definition of the object<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>typedef struct _notefilter\n{\n   t_pxobject l_obj;\n   double freq_cut; \/\/ cutoff frequency\n   double l_a1; \/\/ coefficient 1\n   double l_a2; \/\/ coefficient 2\n   double l_a1p; \/\/ previous coefficient 1\n   double l_a2p; \/\/ previous coefficient 2\n   double l_ym1; \/\/ previous output sample\n   double l_ym2; \/\/ previous output sample\n   double l_fqterm; \/\/ frequency coefficient\n   double l_resterm; \/\/ coefficient of resonance\n   double l_2pidsr; \/\/ 2 pi\n   short l_fcon; \/\/ signal related to the frequency input\n} t_notefilter;<\/code><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Finally I have declared all the headers of the functions that I am going to implement, whether they are actually methods of the object class or not.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>void notefilter_dsp64(t_notefilter *x, t_object *dsp64, short *count, double samplerate, long maxvectorsize, long flags);\nvoid notefilter_perform64(t_notefilter *x, t_object *dsp64, double **ins, long numins, double **outs, long numouts, long sampleframes, long flags, void *userparam);\nvoid notefilter_int(t_notefilter *x, int f);\nvoid notefilter_calc(t_notefilter *x);\nvoid *notefilter_new(double freq, double reso);<\/code><\/pre>\n\n\n<p class=\"wp-block-paragraph\">At this point the implementation of the actual functions begins, the first of which is called&nbsp;<em>ext_main<\/em>&nbsp;and takes care of physically creating the object through&nbsp;<em>class_new<\/em>, specifying the name, the methods of construction and destruction and the size (and other parameters that do not come used because unnecessary or obsolete). The same function also takes care of adding the methods to the class: the functions that until now are independent become methods via&nbsp;<em>class_addmethod<\/em>, which also requires you to pass a name to recognize that method within the function.<br><em>class_register<\/em>&nbsp;finally allows you to register the class defined in the&nbsp;<em>ClassBox<\/em>&nbsp;of Max.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>void ext_main(void *r)\n{\n   t_class *c;\n   c = class_new(\"notefilter~\",(method)notefilter_new, (method)dsp_free,\n   sizeof(t_notefilter), 0L, A_DEFFLOAT, A_DEFFLOAT, 0);\n   class_addmethod(c, (method)notefilter_dsp64, \"dsp64\", A_CANT, 0);\n   class_addmethod(c, (method)notefilter_int, \"int\", A_LONG, 0);\n   class_dspinit(c);\n   class_register(CLASS_BOX, c);\n   notefilter_class = c;\n   return 0;\n}<\/code><\/pre>\n\n\n<p class=\"wp-block-paragraph\">The next function,&nbsp;<em>notefilter_dsp64&nbsp;<\/em>, allows you to store the previous coefficients in special variables, and to store the input value provided at that instant; this step is added to the&nbsp;<em>dsp chain&nbsp;<\/em>, the list that specifies the signal processing functions defined by the object for its signals.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>void notefilter_dsp64(t_notefilter *x, t_object *dsp64, short *count, double samplerate, long maxvectorsize, long flags)\n{\n   x-&gt;l_2pidsr = (2.0 * PI) \/ samplerate;\n   notefilter_calc(x);\n   x-&gt;l_a1p = x-&gt;l_a1;\n   x-&gt;l_a2p = x-&gt;l_a2;\n   x-&gt;l_fcon = count&#91;1];\n\n   dsp_add64(dsp64, (t_object *)x, (t_perfroutine64)notefilter_perform64, 0, NULL);\n}<\/code><\/pre>\n\n\n<p class=\"wp-block-paragraph\">The core of the program lies in the next function,&nbsp;<em>notefilter_perform64<\/em>, which requires perhaps a slightly more detailed analysis.<br>After the definition of the temporary variables that are needed in the execution of the function, values ar loaded (in these newly created spaces) from the parameter set of the object, and a value called&nbsp;<em>scale<\/em>, given by the sum of the two coefficients increased of one is defined.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>void notefilter_perform64(t_notefilter *x, t_object *dsp64, double **ins, long numins, double **outs, long numouts, long sampleframes, long flags, void *userparam) {\n   t_double *in = ins&#91;0];\n   t_double *out = outs&#91;0];\n   t_double freq = x-&gt;freq_taglio;\n   double a1 = x-&gt;l_a1;\n   double a2 = x-&gt;l_a2;\n   double ym1 = x-&gt;l_ym1;\n   double ym2 = x-&gt;l_ym2;\n   double val, scale, temp, resterm;\n\n   scale = 1.0 + a1 + a2;\n}<\/code><\/pre>\n\n\n<p class=\"wp-block-paragraph\">The software now goes through all the available samples, processing the quantized value according to the mathematical formulation I have chosen.<br>To implement its operation, I used the temporary variables defined at the beginning of the function, and I structured a&nbsp;<em>while&nbsp;<\/em>loop to loop through the samples.<br>To make this key step easier to understand, I have summarized the operation in a diagram.<\/p>\n\n\n<p class=\"wp-block-paragraph\"><\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img decoding=\"async\" src=\"https:\/\/nicolafiorello.it\/articles\/creazione-oggetto-max-sdk\/schema_bis.png\" alt=\"\"\/><\/figure>\n\n\n\n<pre class=\"wp-block-code\"><code>while (sampleframes--) {\n   val = *in++;\n   temp = ym1;\n   ym1 = scale * val - a1 * ym1 - a2 * ym2;\n   ym2 = temp;\n   *out++ = ym1;\n}\nx-&gt;l_ym1 = ym1;\nx-&gt;l_ym2 = ym2;\n<\/code><\/pre>\n\n\n<p class=\"wp-block-paragraph\">In Max&#8217;s objects there can be different inputs, which accept data of different types. In this case, the first input will be reserved for the signal to be filtered (noise, if you want use&nbsp;<em>notefilter<\/em>&nbsp;as a synthesizer), while the second will receive an integer relative to the note midi around whose frequency you want to filter.<br>The&nbsp;<em>notefilter_int<\/em>&nbsp;function is in charge of defining the behavior of the object upon receiving that integer.<\/p>\n\n\n<p class=\"wp-block-paragraph\">The cutoff frequency is calculated starting from the midi-note, following the simple formula<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img decoding=\"async\" src=\"https:\/\/nicolafiorello.it\/articles\/creazione-oggetto-max-sdk\/eq2.png\" alt=\"\"\/><\/figure>\n\n\n<p class=\"wp-block-paragraph\">and its data is stored in the&nbsp;<em>cut_freq<\/em>&nbsp;parameter.<br>A&nbsp;<em>post<\/em>&nbsp;function (syntax analogous to the common&nbsp;<em>printf<\/em>&nbsp;function of C) allows you to print in the max console a message containing the note and frequency information in question. The function finally calls&nbsp;<em>notefilter_calc<\/em>, a method that performs the calculation of the coefficients, which I will discuss shortly.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>void notefilter_int(t_notefilter *x, int f)\n{\n   x-&gt;freq_taglio = (440.0 \/ 32.0) * pow(2.0,((f - 9.0) \/ 12.0));\n   post(\"nota n. %i - frequenza: %f\",f, x-&gt;freq_taglio);\n   notefilter_calc(x);\n}<\/code><\/pre>\n\n\n<p class=\"wp-block-paragraph\">The coefficients&nbsp;<em>a1<\/em>&nbsp;and&nbsp;<em>a2<\/em>&nbsp;are fundamental for a correct filtering operation: they characterize the intensity of the resonance and report the cutoff frequency; their calculation takes place in the function&nbsp;<em>notefilter_calc<\/em>&nbsp;according to the following expressions:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img decoding=\"async\" src=\"https:\/\/nicolafiorello.it\/articles\/creazione-oggetto-max-sdk\/eq3.png\" alt=\"\"\/><\/figure>\n\n\n<p class=\"wp-block-paragraph\">and the code with which I implement it is very simple:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>void notefilter_calc(t_notefilter *x)\n{\n   double resterm;\n   resterm = exp(0.125) * 0.882497;\n   x-&gt;l_fqterm = cos(x-&gt;l_2pidsr * x-&gt;freq_taglio);\n   x-&gt;l_a1 = -2. * resterm * x-&gt;l_fqterm;\n   x-&gt;l_a2 = resterm * resterm;\n   x-&gt;l_resterm = resterm;\n}<\/code><\/pre>\n\n\n<p class=\"wp-block-paragraph\">The last function of the software, which concludes the realization of the object, is&nbsp;<em>notefilter_new&nbsp;<\/em>, what is called when creating the object.<br>Some routine operations are performed, in order to allocate the memory necessary for the operation of the object, and the inlets (in our case 2) and the outlets are defined (in our case 1).<br>Some parametric values (such as&nbsp;<em>2pidsr<\/em>) can be calculated here, since their value does not have to be recalculated during the execution: these operations, in fact, come performed only when the object is created.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>void *notefilter_new(double val, double reso)\n{\n   t_notefilter *x = object_alloc(notefilter_class);\n   dsp_setup((t_pxobject *)x,2);\n\n   x-&gt;freq_taglio = val;\n   x-&gt;l_2pidsr = (2. * PI) \/ sys_getsr();\n   notefilter_calc(x);\n\n   x-&gt;l_a1p = x-&gt;l_a1;\n   x-&gt;l_a2p = x-&gt;l_a2;\n\n   outlet_new((t_object *)x, \"signal\");\n   return (x);\n}<\/code><\/pre>\n\n\n<p class=\"wp-block-paragraph\">The software works, and once compiled it has successfully generated the&nbsp;<em>notefilter~<\/em>&nbsp;object, which appears now among Max&#8217;s objects, complete with auto-fill when you start typing its name.<br>To test this, I made a simple patch where the noise produced by a&nbsp;<em>noise~<\/em>&nbsp;object is filtered from&nbsp;<em>notefilter~<\/em>, which receives from a&nbsp;<em>kslider<\/em>&nbsp;the note around which to filter the signal. The output is viewed via the&nbsp;<em>spectroscope<\/em>&nbsp;and reproduced via the sound card via the object&nbsp;<em>ezdac<\/em>.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img decoding=\"async\" src=\"https:\/\/nicolafiorello.it\/articles\/creazione-oggetto-max-sdk\/patch.jpg\" alt=\"\"\/><\/figure>\n\n\n<p class=\"wp-block-paragraph\">The result is a metallic sound and definitely not suitable for real use, but I am satisfied with how much I got because, after all, that&#8217;s what I expected. This is what the spectroscope shows during notefilter operation.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/nicolafiorello.it\/articles\/creazione-oggetto-max-sdk\/filtrato.jpg\" alt=\"\" width=\"337\" height=\"131\"\/><\/figure>","protected":false},"excerpt":{"rendered":"<p>The Cycling Software Development Kit is a library that allows, once added among the packages, to program a new object for Max. I have read the official documentation and have done some tests; this article is the summary of what I concluded. The idea is to create an object in C language that filters a &hellip;<\/p>","protected":false},"author":2,"featured_media":58,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[6,7],"tags":[],"_links":{"self":[{"href":"https:\/\/atled.it\/atled\/it\/wp-json\/wp\/v2\/posts\/43"}],"collection":[{"href":"https:\/\/atled.it\/atled\/it\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/atled.it\/atled\/it\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/atled.it\/atled\/it\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/atled.it\/atled\/it\/wp-json\/wp\/v2\/comments?post=43"}],"version-history":[{"count":10,"href":"https:\/\/atled.it\/atled\/it\/wp-json\/wp\/v2\/posts\/43\/revisions"}],"predecessor-version":[{"id":213,"href":"https:\/\/atled.it\/atled\/it\/wp-json\/wp\/v2\/posts\/43\/revisions\/213"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/atled.it\/atled\/it\/wp-json\/wp\/v2\/media\/58"}],"wp:attachment":[{"href":"https:\/\/atled.it\/atled\/it\/wp-json\/wp\/v2\/media?parent=43"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/atled.it\/atled\/it\/wp-json\/wp\/v2\/categories?post=43"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/atled.it\/atled\/it\/wp-json\/wp\/v2\/tags?post=43"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}