-
-
Save weefuzzy/024f8784d0e4d44203e18728e6fb6200 to your computer and use it in GitHub Desktop.
Baby steps towards running Max DSP graphs on buffer~s
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdlib.h> | |
#include "ext.h" | |
#include "ext_obex.h" | |
#include "z_dsp.h" | |
#include "ext_buffer.h" | |
#include "ext_dictobj.h" | |
typedef struct _bufproc_binding | |
{ | |
t_buffer_obj* buf; | |
t_atom_long offset; | |
t_atom_long num_frames; | |
t_atom_long num_chans; | |
t_atom_long start_chan; | |
t_atom_long process_count; | |
} t_bufproc_binding; | |
typedef struct _bufproc | |
{ | |
t_pxobject ob; | |
t_symbol* output_buffer; | |
t_buffer_ref** inputs; | |
t_buffer_ref* output; | |
void* resultOutlet; | |
void* lambda_outlet; | |
long inlet_num; | |
long num_ins; | |
long num_outs; | |
void** inlet_proxies; | |
t_object* processor; | |
t_object* processor_copy; | |
long latency; //TODO | |
long tail; //TODO | |
long num_hops; | |
long hop_count; | |
long remainder; | |
void* old_scheduler; | |
void* new_scheduler; | |
t_bufproc_binding* input_bindings; | |
t_bufproc_binding* output_bindings; | |
t_int32_atomic working; | |
t_dspchain* chain; | |
double shift; | |
} t_bufproc; | |
typedef struct _bufproc_inproxy | |
{ | |
t_pxobject x_obj; | |
long num; | |
t_bufproc_binding* binding; | |
} t_bufproc_inproxy; | |
typedef struct _bufproc_outproxy | |
{ | |
t_pxobject x_obj; | |
long num; | |
t_bufproc_binding* binding; | |
} t_bufproc_outproxy; | |
void bufproc_bang(t_bufproc *x); | |
void* bufproc_new(t_symbol* s, long ac, t_atom* av); | |
void bufproc_free(t_bufproc* x); | |
void bufproc_anything(t_bufproc* x, t_symbol *s, long argc, t_atom *argv); | |
void* bufproc_subpatcher(t_bufproc *x, long index, void *arg); | |
void bufproc_dsp(t_bufproc *x, t_object *chain, short* count, double sr, long bs, long flags){} | |
t_max_err bufproc_patchlineupdate(t_bufproc *x, t_object *patchline, long updatetype, t_object *src, long srcout, t_object *dst, long dstin); | |
t_ptr_int bufproc_connectionaccept(t_bufproc *src, t_object *dst, long srcout, long dstin, t_object *outlet, t_object *inlet); | |
t_max_err bufproc_notify(t_bufproc *x, t_symbol *s, t_symbol *msg, void *sender, void *data); | |
t_max_err bufproc_get_ownsdspchain(t_object *pv, t_object *attr, long *argc, t_atom **argv); | |
void* bufproc_inproxy_new(t_symbol* s, long ac, t_atom* av); | |
void bufproc_inproxy_dsp(t_bufproc_inproxy *x, t_object *chain, short* count, double sr, long bs, long flags); | |
void bufproc_inproxy_free(t_bufproc_inproxy* x); | |
void* bufproc_outproxy_new(t_symbol* s, long ac, t_atom* av); | |
void bufproc_outproxy_dsp(t_bufproc_outproxy *x, t_object *chain, short* count, double sr, long bs, long flags); | |
void bufproc_outproxy_free(t_bufproc_outproxy* x); | |
t_class *bufproc_class; | |
t_class *bufproc_inproxy_class; | |
t_class *bufproc_outproxy_class; | |
void ext_main(void *r) | |
{ | |
bufproc_class = class_new("bufproc", (method)bufproc_new, (method)bufproc_free, sizeof(t_bufproc), 0L, A_GIMME, 0); | |
class_addmethod(bufproc_class, (method)bufproc_bang, "bang", 0); | |
class_addmethod(bufproc_class, (method) bufproc_patchlineupdate, "patchlineupdate",A_CANT,0); | |
class_addmethod(bufproc_class, (method)bufproc_connectionaccept, "connectionaccept",A_CANT,0); | |
class_addmethod(bufproc_class, (method)bufproc_anything, "anything", A_GIMME, 0); | |
class_addmethod(bufproc_class, (method)bufproc_notify, "notify", A_CANT, 0); | |
class_addmethod(bufproc_class, (method)bufproc_dsp, "dsp64", A_CANT, 0); | |
class_addmethod(bufproc_class, (method)bufproc_subpatcher, "subpatcher", A_CANT, 0); | |
CLASS_ATTR_LONG(bufproc_class, "numins", 0, t_bufproc, num_ins); | |
CLASS_ATTR_LONG(bufproc_class, "numouts", 0, t_bufproc, num_outs); | |
CLASS_ATTR_MIN(bufproc_class, "numins", 0, "0"); | |
CLASS_ATTR_MIN(bufproc_class, "numouts", 0, "0"); | |
CLASS_ATTR_OBJ(bufproc_class, "ownsdspchain", ATTR_SET_OPAQUE | ATTR_SET_OPAQUE_USER, t_bufproc, ob); | |
CLASS_ATTR_ACCESSORS(bufproc_class, "ownsdspchain", (method) bufproc_get_ownsdspchain, (method) 0); | |
CLASS_ATTR_INVISIBLE(bufproc_class, "ownsdspchain", 0); | |
class_dspinit(bufproc_class); | |
class_register(CLASS_BOX, bufproc_class); | |
bufproc_inproxy_class = class_new("bufproc_inproxy", (method)bufproc_inproxy_new, (method)bufproc_inproxy_free, sizeof(t_bufproc_inproxy),0L, A_GIMME, 0); | |
class_dspinit(bufproc_inproxy_class); | |
class_addmethod(bufproc_inproxy_class, (method)bufproc_inproxy_dsp, "dsp64", A_CANT, 0); | |
class_register(CLASS_BOX, bufproc_inproxy_class); | |
bufproc_outproxy_class = class_new("bufproc_outproxy", (method)bufproc_outproxy_new,(method)bufproc_outproxy_free, sizeof(t_bufproc_outproxy), 0L, A_GIMME, 0); | |
class_dspinit(bufproc_outproxy_class); | |
class_addmethod(bufproc_outproxy_class, (method)bufproc_outproxy_dsp, "dsp64", A_CANT, 0); | |
class_register(CLASS_BOX, bufproc_outproxy_class); | |
} | |
t_max_err bufproc_get_ownsdspchain(t_object *pv, t_object *attr, long *argc, t_atom **argv) | |
{ | |
char alloc = false; | |
if (atom_alloc(argc, argv, &alloc)) | |
return MAX_ERR_GENERIC; | |
// This prevents getdspchain on child patchers from walking up past this object | |
atom_setlong(*argv,1); | |
return MAX_ERR_NONE; | |
} | |
void* bufproc_inproxy_new(t_symbol* s, long ac, t_atom* av) | |
{ | |
if(ac < 1) return NULL; | |
t_bufproc_inproxy* obj = (t_bufproc_inproxy*)object_alloc(bufproc_inproxy_class); | |
dsp_setup((t_pxobject*)obj, 0); | |
outlet_new((t_object*)obj, "signal"); | |
t_atom_long arg = atom_getlong(av); | |
obj->num = arg > 0 ? arg : 1; | |
return obj; | |
} | |
void bufproc_inproxy_free(t_bufproc_inproxy* x) | |
{ | |
dsp_free((t_pxobject*)x); | |
} | |
void bufproc_inproxy_perform(t_bufproc_inproxy* x, t_object* dsp64,double** ins, long nIns, double **outs, long nOuts, long bs, long flags, void* user) | |
{ | |
t_bufproc_binding* binding = x->binding; | |
long n = binding->offset + (binding->process_count * binding->num_chans); | |
long offset = binding->offset + binding->start_chan; | |
long stride = binding->num_chans; | |
t_float* samps = buffer_locksamples(binding->buf); | |
if(!samps) return; | |
t_double* output = outs[0]; | |
//buffers are interleaved, so we have to use this strided copy | |
for(long i = offset, j=0; i < n; i+=stride, ++j) | |
output[j] = samps[i]; | |
buffer_unlocksamples(binding->buf); | |
} | |
void bufproc_inproxy_dsp(t_bufproc_inproxy *x, t_object *chain, short* count, double sr, long bs, long flags) | |
{ | |
if(x->binding && x->binding->buf) | |
object_method(chain,gensym("dsp_add64"),x,bufproc_inproxy_perform,0, NULL); | |
} | |
void* bufproc_outproxy_new(t_symbol* s, long ac, t_atom* av) | |
{ | |
if(ac < 1) return NULL; | |
t_bufproc_outproxy* obj = (t_bufproc_outproxy*)object_alloc(bufproc_outproxy_class); | |
obj->num = atom_getlong(av); | |
dsp_setup((t_pxobject*)obj,1); | |
t_atom_long arg = atom_getlong(av); | |
obj->num = arg > 0 ? arg : 1; | |
return obj; | |
} | |
void bufproc_outproxy_free(t_bufproc_outproxy* x) | |
{ | |
dsp_free((t_pxobject*)x); | |
} | |
void bufproc_outproxy_perform(t_bufproc_outproxy* x, t_object* dsp64,double** ins, long nIns, | |
double **outs, long nOuts, long bs, long flags, void* user) | |
{ | |
t_bufproc_binding* binding = x->binding; | |
long n = binding->offset + (binding->process_count * binding->num_chans); | |
long offset = binding->offset + binding->start_chan; | |
long stride = binding->num_chans; | |
t_float* samps = buffer_locksamples(binding->buf); | |
if(!samps) return; | |
t_double* input = ins[0]; | |
//buffers are interleaved, so we have to use this strided copy | |
for(long i = offset, j=0; i < n; i+=stride, ++j) | |
samps[i] += input[j]; | |
buffer_unlocksamples(binding->buf); | |
} | |
void bufproc_outproxy_dsp(t_bufproc_outproxy *x, t_object *chain, short* count, double sr, long bs, long flags) | |
{ | |
if(x->binding && x->binding->buf) | |
object_method(chain,gensym("dsp_add64"),x,bufproc_outproxy_perform,0, NULL); | |
} | |
void* bufproc_new(t_symbol* s, long ac, t_atom* av) | |
{ | |
t_bufproc *x; | |
x = (t_bufproc *)object_alloc(bufproc_class); | |
x->num_ins = 1; | |
x->num_outs = 1; | |
x->processor = NULL; | |
attr_args_process(x, ac, av); | |
x->inputs = (t_buffer_ref**)sysmem_newptr(sizeof(t_buffer_ref*) * x->num_ins); | |
for(int i = 0; i < x->num_ins;++i) | |
{ | |
x->inputs[i] = buffer_ref_new((t_object*)x, NULL); | |
} | |
if(x->num_ins > 1) | |
{ | |
x->inlet_proxies = (void**)sysmem_newptr(sizeof(void*) * (x->num_ins - 1)); | |
for(long i = x->num_ins - 2; i >= 0; --i) | |
{ | |
x->inlet_proxies[i] = proxy_new(x, i+1, &x->inlet_num); | |
} | |
} else x->inlet_proxies = NULL; | |
//Make the output buffer | |
x->output_buffer = symbol_unique(); | |
t_atom buffer_name; | |
atom_setsym(&buffer_name, x->output_buffer); | |
object_new_typed(CLASS_BOX, gensym("buffer~"), 1, &buffer_name); | |
x->output = buffer_ref_new((t_object*)x, x->output_buffer); | |
x->lambda_outlet = outlet_new(x,NULL); | |
x->resultOutlet = outlet_new(x, NULL); | |
x->input_bindings = (t_bufproc_binding*) sysmem_newptr(sizeof(t_bufproc_binding) * x->num_ins); | |
x->output_bindings = (t_bufproc_binding*) sysmem_newptr(sizeof(t_bufproc_binding) * x->num_outs); | |
x->working = 0; | |
return(x); | |
} | |
void bufproc_free(t_bufproc* x) | |
{ | |
dsp_free((t_pxobject*)x); | |
if(x->inlet_proxies) | |
{ | |
for(int i = 0; i < x->num_ins - 1;++i) | |
{ | |
object_free(x->inlet_proxies[i]); | |
object_free(x->inputs[i]); | |
} | |
sysmem_freeptr(x->inlet_proxies); | |
} | |
object_free(x->output); | |
sysmem_freeptr(x->inputs); | |
sysmem_freeptr(x->input_bindings); | |
sysmem_freeptr(x->output_bindings); | |
} | |
void bufproc_anything(t_bufproc* x, t_symbol *s, long argc, t_atom *argv) | |
{ | |
long inlet = proxy_getinlet((t_object*) x); | |
buffer_ref_set(x->inputs[inlet], s); | |
} | |
void* bufproc_subpatcher(t_bufproc *x, long index, void *arg) | |
{ | |
if ((t_ptr_uint) arg > 1) | |
if (!NOGOOD(arg)) | |
if (ob_sym(arg) == gensym("dspchain")) | |
return NULL; | |
return x->processor_copy; | |
} | |
t_max_err bufproc_patchlineupdate(t_bufproc *x, t_object *patchline, long updatetype, t_object *src, long srcout, t_object *dst, long dstin) | |
{ | |
if((t_object*)x == src && srcout == 1) | |
{ | |
switch(updatetype) | |
{ | |
case JPATCHLINE_CONNECT: | |
x->processor = dst; | |
break; | |
case JPATCHLINE_DISCONNECT: | |
x->processor = NULL; | |
break; | |
} | |
} | |
return MAX_ERR_NONE; | |
} | |
t_ptr_int bufproc_connectionaccept(t_bufproc *src, t_object *dst, long srcout, long dstin, t_object *outlet, t_object *inlet) | |
{ | |
t_symbol* dstclass = object_classname(dst); | |
//Connections can only be made from lambda outlet if not already connected, and target is a patcher | |
return (srcout == 0 || (src->processor == NULL && dstclass == gensym("jpatcher") && srcout == 1)); | |
} | |
void map_io_objects(t_bufproc *x, t_object* patcher) | |
{ | |
t_symbol* bufproc_inproxy_name = gensym("bufproc_inproxy"); | |
t_symbol* bufproc_outproxy_name = gensym("bufproc_outproxy"); | |
for (t_object* box = jpatcher_get_firstobject(patcher); box; box = jbox_get_nextobject(box)) | |
{ | |
t_object* obj = jbox_get_object(box); | |
t_symbol* cn = object_classname(obj); | |
if(cn == bufproc_inproxy_name) | |
{ | |
t_bufproc_inproxy* inprox = (t_bufproc_inproxy*) obj; | |
long idx = inprox->num - 1; | |
if(idx < x->num_ins) | |
{ | |
if(x->input_bindings[idx].buf) | |
{ | |
inprox->binding = &x->input_bindings[idx]; | |
} | |
} | |
else | |
object_error((t_object*)x, "Input %d out of range (%d)", idx + 1,x->num_ins); | |
} | |
if(cn == bufproc_outproxy_name) | |
{ | |
t_bufproc_outproxy* outprox = (t_bufproc_outproxy*) obj; | |
long idx = outprox->num - 1; | |
if(idx < x->num_outs) | |
outprox->binding = &x->output_bindings[idx]; | |
else | |
object_error((t_object*)x, "Output %d out of range (%d)", idx + 1,x->num_outs); | |
} | |
} | |
} | |
t_max_err bufproc_notify(t_bufproc *x, t_symbol *s, t_symbol *msg, void *sender, void *data) | |
{ | |
for(int i = 0; i < x->num_ins; ++i) buffer_ref_notify(x->inputs[i], s, msg, sender, data); | |
buffer_ref_notify(x->output, s, msg, sender, data); | |
if(x->processor_copy) | |
{ | |
object_method((t_object*)x->processor_copy,gensym("notify"),s,msg,sender,data); | |
} | |
return 0; | |
} | |
t_object* copy_patcher(t_object* patcher) | |
{ | |
t_dictionary* d = dictionary_new(); | |
object_method(patcher,gensym("appendtodictionary"),d); | |
t_symbol* name = symbol_unique(); | |
t_object* p2 = (t_object*) jpatcher_load_fromdictionary(name->s_name, 0, (t_object*)d, 0, NULL); | |
object_free(d); | |
return p2; | |
} | |
void bufproc_docleanup (t_bufproc* x, t_symbol *s, short argc, t_atom *argv) | |
{ | |
scheduler_set(x->old_scheduler); | |
sched_resume(); //TODO needed? | |
object_free(x->new_scheduler); | |
x->new_scheduler = NULL; | |
object_free(x->chain); | |
x->chain = NULL; | |
object_method(x->output_bindings[0].buf, gensym("dirty")); | |
object_free(x->processor_copy); | |
x->processor_copy = NULL; | |
outlet_anything(x->resultOutlet, x->output_buffer, 0, NULL); | |
ATOMIC_DECREMENT(&x->working); | |
} | |
void bufproc_dotick (t_bufproc* x, t_symbol *s, short argc, t_atom *argv) | |
{ | |
t_atom_long i = x->hop_count; | |
double next_logical_time = x->shift * i; | |
//still work to do? | |
if(i <= x->num_hops) | |
{ | |
t_atom_long process_count = i == x->num_hops ? x->remainder : 64; | |
for(int j = 0; j < x->num_ins; ++j) | |
{ | |
x->input_bindings[j].offset = i * 64 * buffer_getchannelcount(x->input_bindings[j].buf); | |
x->input_bindings[j].process_count = process_count; | |
} | |
for(int j = 0; j < x->num_outs; ++j) | |
{ | |
x->output_bindings[j].offset = i * 64 * buffer_getchannelcount(x->output_bindings[j].buf); | |
x->output_bindings[j].process_count = process_count; | |
} | |
dspchain_tick(x->chain); | |
scheduler_shift(x->new_scheduler,next_logical_time); | |
x->hop_count++; | |
} | |
//all done? | |
if(x->hop_count > x->num_hops) | |
{ | |
defer(x,(method)bufproc_docleanup, NULL,0,NULL); //TODO: Must I defer this? | |
} | |
else //keep going | |
{ | |
schedulef(x,(method)bufproc_dotick,next_logical_time, NULL,0,NULL); | |
} | |
} | |
int setSubAssoc(t_patcher *p, t_object *x) | |
{ | |
t_object *assoc; | |
object_method(p, gensym("getassoc"), &assoc); | |
if (!assoc) | |
object_method(p, gensym("setassoc"), x); | |
return 0; | |
} | |
void bufproc_bang(t_bufproc *x) | |
{ | |
if(x->working) | |
{ | |
object_error((t_object*)x, "Still working"); | |
return; | |
} | |
ATOMIC_INCREMENT(&x->working); | |
if(!x->processor) | |
{ | |
object_error((t_object*)x, "No processing patch!"); | |
return; | |
} | |
t_atom_long numframes = 0; | |
t_atom_float sample_rate = 0; | |
for(int i = 0; i < x->num_ins; ++i) | |
{ | |
if(!buffer_ref_exists(x->inputs[i])) | |
{ | |
object_error((t_object*)x, "No buffer~ found for input %d",i); | |
ATOMIC_DECREMENT(&x->working); | |
return; | |
} | |
x->input_bindings[i].buf = buffer_ref_getobject(x->inputs[i]); | |
if(!x->input_bindings[i].buf) | |
{ | |
object_error((t_object*)x, "buffer~ at input %d not valid",i); | |
ATOMIC_DECREMENT(&x->working); | |
return; | |
} | |
} | |
//hygiene check | |
for(int i = 0; i < x->num_ins; ++i) | |
{ | |
//For now, just use the minimum frame count and sr of first valid buf | |
t_buffer_obj* buf = x->input_bindings[i].buf; | |
if(!buf) continue; | |
x->input_bindings[i].num_chans = buffer_getchannelcount(buf); | |
t_atom_long f = buffer_getframecount(buf); | |
t_atom_float sr = buffer_getsamplerate(buf); | |
if(numframes == 0) numframes = f; | |
if(numframes > 0 && f != numframes) | |
{ | |
object_warn((t_object*)x, "frame count mismatch at buffer~ %d",i); | |
if(f < numframes) | |
{ | |
numframes = f; | |
object_warn((t_object *)x, "Going with new smaller frame count (%d)",numframes); | |
} | |
} | |
if(sample_rate > 0) | |
{ | |
if(sample_rate != sr) object_warn((t_object *)x, "Sample rate mistmatch at input %d",i); | |
} else sample_rate = sr; | |
} | |
if(numframes == 0 || !(sample_rate > 0)) | |
{ | |
object_error((t_object *)x, "Failed to get valid frame count or sample rate from inputs"); | |
ATOMIC_DECREMENT(&x->working); | |
return; | |
} | |
//resize output and set sr | |
t_buffer_obj* output_buffer_object = buffer_ref_getobject(x->output); | |
t_symbol* resize_msg = gensym("sizeinsamps"); | |
t_atom outputsize[2]; | |
atom_setlong(&outputsize[0], numframes); | |
atom_setlong(&outputsize[1], x->num_outs); | |
object_method_typed(output_buffer_object, resize_msg, 2, outputsize, NULL); | |
t_atom sr; | |
atom_setfloat(&sr, sample_rate); | |
t_symbol* sr_msg = gensym("sr"); | |
object_method_typed(output_buffer_object, sr_msg, 1, &sr, NULL); | |
//make sure output is 0'd | |
t_symbol* clear_msg = gensym("clear"); | |
object_method(output_buffer_object, clear_msg); | |
buffer_setdirty(output_buffer_object); | |
//initalize bindings | |
for(int i = 0; i < x->num_ins; ++i) | |
{ | |
x->input_bindings[i].num_frames = numframes; | |
x->input_bindings[i].offset = 0; | |
x->input_bindings[i].process_count = 0; | |
x->input_bindings[i].start_chan = 0; | |
} | |
for(int i = 0; i < x->num_outs; ++i) | |
{ | |
x->output_bindings[i].buf = buffer_ref_getobject(x->output); | |
x->output_bindings[i].offset = 0; | |
x->output_bindings[i].start_chan = i; | |
x->output_bindings[i].num_frames = numframes; | |
x->output_bindings[i].num_chans = buffer_getchannelcount(output_buffer_object); | |
} | |
//setup new scheduler | |
x->new_scheduler = scheduler_new(); | |
x->old_scheduler = scheduler_set(x->new_scheduler); | |
//copy the processing patch | |
x->processor_copy = copy_patcher(x->processor); | |
object_method(x->processor_copy, gensym("setassoc"), x); | |
long result = 0; | |
object_method(x->processor_copy, gensym("traverse"), setSubAssoc, x, &result); | |
object_method(x->processor_copy, gensym("loadbang")); | |
//assign proxies from patcher | |
map_io_objects(x, x->processor_copy); | |
//compile DSP | |
x->chain = dspchain_compile(x->processor_copy, 64, sample_rate); | |
//setup processing loop | |
x->num_hops = numframes / 64; | |
x->remainder = numframes % 64; | |
x->shift = 64 * (1000/sample_rate); | |
x->hop_count = 0; | |
for(int i = 0; i < x->num_ins; ++i) | |
{ | |
x->input_bindings[i].offset = 0; | |
x->input_bindings[i].process_count = 0; | |
} | |
for(int i = 0; i < x->num_outs; ++i) | |
{ | |
x->output_bindings[i].offset = 0; | |
x->output_bindings[i].process_count = 0; | |
} | |
//we seem to need an initial tick to make the scheduler in the proecssing patch come alive. Don't underdtand why | |
dspchain_tick(x->chain); | |
schedulef(x, (method)bufproc_dotick, 0, NULL, 0, NULL); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<pre><code> | |
----------begin_max5_patcher---------- | |
4253.3oc6cs0iihiE94p9UXEsR6tiRGgs459zrR6Kyaq1KOM8nRDvIgoIPVt | |
zUU8no+su9FI.IPbHgJPF5VJoBlPN9iiO93i+NG9smeZ1x32Hoy.+MvOCd5o | |
e64mdheH1AdR94mls08MuP2T9oMKh7Z7xec1bQSYj2x3GdGH0aCwOOjjTzVf | |
OuE5Y+IjcwAix2FDERx3WLM4A24l4sIHZ8KIDuLgvfrWXLG.Q3EZyAVP1qHz | |
BMvub35DmmcxKDUBDhuT9eZ1pfPxWIIoAwQrlfykG2c2tRG9oReEVm9Wi4WH | |
646OTPj3Pv8GJg70fhuOd+QcSncmLZeIOgvwf2L0mc3xD6SRhxC3WIwA+8mK | |
DINPG4tkjty0S7kY2OJZ9..owgDSN7XawdyzFd.fn2FWGF68EheI74oYw6HQ | |
AQ6RHojnL2LojuuYexJ27vrWVEGkkF7M9uOjB6mp8UR46jMx5Abg+umD3FtW | |
7WmD3GGwDhJ2GXGt3m6mAPCVug85gNC+Lhb2chuLU+hBJMzXJsSlmtzMgcaZ | |
YH+W.UzXVbbX0l1+8BIqxjMuKHJpFJlEuq4FSBVuoku6xXZiaa6ZyaI8k7HQ | |
quP0HxdI08qUQ6L2vP4XwpW92biB15lQxBD2BPZ6ajD4R6naR8RhCCqzeEs7 | |
0SzhOUC2i7Zfe1F9OTYkA5oGrqPIZ196x9AqIoYUOVl65zpGIM6cAnW5P4Kk | |
ifeIircWHsWT6D1D+JU6xcYk6iUrgUdPbYaYUNdMaZzQaotqI6GhV1vF01QH | |
EM.TaEguCxnpyQqCIfMtgqJN3Z2fHpzH+T7pUojLvmfkubkrEBsK2PE6gnRM | |
bBahXKa9fd9HRpER85VEOgkQXoVDGN68cxAZylA9khV+8met3Ol2QTj7MeWu | |
u2Pu1nqcZjCah.CH2dmtQwqszk0tg8o1zLn1VRxZ5lrSm6u7atXaG9ang0s3 | |
JS9WyAfP22+NvOeK.0DlX1Hl.OClv060M428sTQsG2FljFrNhMoT4+ZIcX8s | |
EqVlSMzG0DVnOqRWNgNeYF0rmvNbYK5WJVA03fEDycM.oW7ZWUft8.SKJQYf | |
kr+2DnAmckfhk.TDCttFUHNpLu162TTpMKOteKXaNc93FfIstaq0pzDLFvQi | |
wmk4qVQR9NPBLfeL0c6tTpqq55XmFfI8tpLULMrNerEz1TAXB0FLsJL1Mqez | |
hT.y903n07WBeegavpFPKbWQKc9XMK9z2PDZ.iUdwa2RWUzomcKI1iNfj10. | |
79XSC8rJ2vx7k0VWwkqpI7F.ZxWMLzTAq4ZenpOM.DHsNap1AK77QWLm+3bv | |
EcE1zkh5CnqDnADx9JmKSBPVCLODaaZKlQl4.wTlmd3SmWkfDTjybIbTbb31 | |
Lvc6xfctM5nXmM7JmLuPOAq.jnU+JdHTZU6dMFRslBqVsu9oBuVCgXq4vrc9 | |
Ps0T31pDxMEB6VsPuoiEdSpyAXcwaXCspX6oi.mBQgSkHwc1nwoXD4ZIpbpE | |
YtyDctyFgtyFktyDotyGstyFwNEhZmJQt6RhdWKQv6rQwq8H40dz7ZOhdsFU | |
ulhr2oitWCQ3Son7wOoltUeTr9paYotM4iZ+rSXUasVDe.D7IcCJPAfK3gBj | |
dHD3vQp+caXQFsNoViVwghUvKb8qgEaz9ramcFtJyxUcltqEcOZlupfK02L+ | |
Z9Cz1BOZcNvFQPLV.c7kfXXeq.vZ9Sd+.Qpm3rkm7BUBou+16UB.WqAgqS3I | |
zxfsXDrF2UKHDpHfpM.Qp1F5VwYzNgTF1CVfRMqd+InBl3fWuMNSQzAvbDxA | |
8PYhK0yMj.9DjiiexTCXp0FXhZELMUFLcDtnpY7XAlTeHS2Dm8c.rUTDdiTI | |
M4S2ZCuUfnHXDCAjjspSehGcsQTrr8YLzZEL0U0NHRL7FpoJZhNGZdz93bzE | |
j42s+Kh0e7haVVRvx7Lg+iO0HNRWToWVvWKVyCUjqecehYe7E9Ha9s8ptPKV | |
PYbbh+K78Jt9RqKeBoumR8A9jm.aWk4W8iu3zuII4DJbxVdkvVLiT7Yfs1Bb | |
0+cbGp.VO5J916eqZOsR6UTduipxjHtpbKpwN2lYyYd+bQZw5WrV77OJM6tn | |
VShXaSI8G7EeNILLa7b7xSjK5cApgSYefM5iwO9KoKBOHSb8MNp0fTNt0vOO | |
qY2HOxKrnGcxwEsL7Lf041EGtOxNP0G.OhGGV3cMKxVmaYHsuJDMkmfFK7bT | |
S+gxMm5HYateitVjzfG9RqQINx6ns46x0BNN6wF7d8sa.zT6TJ14w5QASXLw | |
m7VsXWeDdVMbrgAQmKFY7tJ67ZGrSiyS7Jja4rnfiA.eRZVPzdyc+7AGGYmb | |
mzCtFADdIBH7NHfnKQ.Q2AADeIBH9CV.MuDcP3cPGTenOHAeABn9cP9PWf74 | |
bGjOn9PW.uDDDdOtEWLvTMIDcOjPsKYpDy6kDpLFZbVIrTik2cbUVq4ucs6f | |
35v3ktgx8Eb+dU2vlL97wcfa.KMdk1MWEmrsINMYVkaWL5OsWPycLwZZZFNM | |
y6IC0n0ijhpF72LampWlJQ7oV9iP5xbYu+QR5P1Ja.KiWB9QN7jRcv4GEcqz | |
loN90xKHGQ3ZzruV5j0LZcHYkNx+6C.3oFpWBFOZHtc8Q3ML59HehJEhAkty | |
1WBF5HaTy1F3uKNHJSBQPnEeaxLj6vsf9eU+DTvdIMD+LYe5z8Us6ZeE1xcA | |
TuHYPmKTz5GoPU.RuOEBSEEBi9VHfJJDv9RHLTUonOQBcUEhdUJf0WscSRgc | |
eKEJgEF8sTnhtY8kjdakBsKP4r2FgnnLzqJEpd2.2nPHOXgu5myO8eqK4sa6 | |
9kW2mbgvweUfQWUEE3yyBh1wbKzMxGv3rC8u+7rSUdAz6V4EvVrWdHioxKPc | |
NNOUdAlJu.SkWfSS43aal.q0WYBrgf2qvAah.e1xtPZPDv9hSeyykjqhTgQl | |
mY5NitjbkOoXQJtpq4zTBth5blCISVHIgsLLGoIsYBImmwlBWG.TAdIc5XvO | |
jluM8GnvXVLHaiaFvaiK0RXXCvnSmySXA4AEg0SvGSj1GVpapBvHzjJvksD2 | |
nTJhP.TUKBPntA7nFDoWGfmaDXIAv9pDe5YkDmudCU1At.YxwdwU9CkvOAOO | |
zcbFP32+5.9w4mQg+o7OT.mAT+VCCiek3OmhkYfMto.+.FlxfSB8OntUPuXk | |
9AXKevKNWvD.zMNQrEkRKgutXwGv3AAbduRtZGoSt50lm7AN4pEYtnrKOkb0 | |
M3yjDeFS4VM2TdOkb0RGIEzf2zdDka0xHHT3AfaXfKyLymmc6y1ZcTYiIX8o | |
zsteR2ZCCAzh0mR25ozsdJcqKeacDjt0mKAuBV+cvmzVXzmYxAFYcnpxZbyx | |
Pt8opw8m.4+v2YYcQafn8UmgbhkPHJBkBSyOXfn26dgjuCPskogV2HXTuzZc | |
evfwKJoqu5rSWhmxJM1nL6zUIqOt5bSGZ3zGo8wXUuS+ZwSc6CA6aTo0Qmp. | |
14xuARUfQXeC+Hae65SVKkUyFyiZmRYqAbJacOXwt8.W9rt.4y9NHeFWf7gu | |
CI71iTxFgmxghdLGJflNrbnvznq4Pggjs35+QKEJfGRgB3EmBEpskH3QZFTn | |
LgS0al79Z2YpvZ7QmcGpRdaTORP1+.j5Kl77YA4Hx0EjLUkp7I4duoyyQF9m | |
9PUQGDoRvDasGCr0doaZf2oHmMrajyVF3.qItYOwM6ItYOwM66.2rw81SoIr | |
vOZcM8w5SoolfrtS2SIjniuQKz397rYhS3nlxicLtqbvRW7zbPW7zOSef8nY | |
p0QQF80fHwTf5xRw3iyXHqYWGfHFAAO8tsLLFAcKnCL51RGXCArYHnc9HhNv | |
c+4pH1obW9wkNvP6qbRIIB8XQHXTmqpJESUKlLZTwH3szkozDdbEOi6rJONB | |
Nw82aE2egBvD5Hdv+J+zQ648D2em396D2eG4b+8RpezS7eaPx+MKqI9u0B+2 | |
fSDfah.bSDf6Cl.bSDjZhfTCFBR01R1SIYfVCeLpyovqLxfxErOvhd74HMFp | |
UViYfgLViYi6JqwJhwiHevF0zF6rHoUKH4wpdWBJJzvdD.QkJKQUdpGVAhs6 | |
bsJFK2hGby4k3vuvDgJpLQr5gcSXjS2KfEhHsoI1hCS73Lj0moLX2DGNwZWY | |
Dak3VuxhydYODQ586lHJe5.+.sIhHz0sKhHYFTNV2EweZEuTVIp+GxZYUHIZ | |
c1lTfaBArMHcK2QP+4ffLPdJQT6qn3Tv17sf+haXFaxQ1yKuTfWbdnOq9W8Z | |
h6t4f3DvNWe16KVr3ut.7uH6hSxX6XYX75.O.cNX5EKPTDn.KoW+kwIeg3u3 | |
yQeN5m.anSSG8my.9wQDfaz6Yr6..2krxoUBw0m8oUIwaoBJ865l7d0tgrdk | |
kBdu5NdUo7Q4TCT7hCEg6mweLHxQGBsL0snNNYilq7gzMpnETdYqc1ltgoYY | |
tvHMsyxQ++3VapLJpMU36ylQ2Fj7eb+BgoVeH3xrhDGU0KiUX3hAHQ0PiJVx | |
xqGi1VrY3neEdbV.k.00zwSa3EPMWfe91sLUc52bAfMRQ7KUV2mdQRYWDwuj | |
.N4m5+cWbDeyNmS+81EHGLePDYGd6tfPZC+i+8+j+CljyK2c7BY2bfnhtIq1 | |
cof3UU+cmSu8mVpx2ApG0K4NuTpVEKpvfGEFV4IJ6gTgTd1xA2TKFdTa.Lrj | |
co1RQNF5Q+H+wJIE9BeeN30fLJpAxiB9e4D.yEdAVS+1rM5RX8fg.qBRRyJt | |
c75FRTYvmd1LSPMZCABaPaW+5lawtDucfFOzUbMIEKPlnoJtVadlJAnoRtVE | |
TAZ4L5XXAyNozH4MuJqIIZgTYw1XhnESDsXhnESDsXbPzhaNgJN1K85N0jQW | |
eZeVJ0f1lGph5PCsSUjluS66+4.GQcZltda1MqT1xIp5H9wUE7icPF00JClJ | |
PqoUIJUHdr.VufMOZf1h.dxQ.PeV.vJfMApoOfTHm3qyXiuNSz0YhtNSz04C | |
ltNSzgYhNLUoCyE+fYQIxvfL3AQvPebQFlV4BCVyRSSyrkLBSMtvfQNO7bgA | |
eNpvbcLg4Q.BuOOftjb7PN9b5AzUyHjXSBG1OftFPUxrhsZPNxbHRBFF1bLQ | |
Xn8iil993M0Gq6nw2j95+ArVOrLVBuDd0Pc6NlBmgAdeoNbubcIYgubRsEV1 | |
1HrAm1.bFDbrjrWUPsgBgj0tduWoiCqc0hipKGUdoxu9x0UNasEFbg8vq0+B | |
Mu+dE7GRSgmRYkB1+r7TREonb2IINm5XN+dkYk.ZNqbvwgmUAcNa9rrJKIf8 | |
6xQquRRZFJK2HCd35TEubDX558k0bQV8Ju1vbLgCdXLl.NVGSHdLFLMj3wYH | |
A1bXLjPezNMg3wC1dNtMMlX7Ol.MLFSfG2SSTT9llFRz7PhdovH6nXYUEOUi | |
ee5JpwuXnnz85vs7isEzAr5mLfhQBhxArA7isH+ZoXssE0mEXWKUAbidTHTs | |
ZGa0ixvPnzayJhiJoRfw8sTnDTzmUeZrp2Pv8olIFqpTnUMC1usRglplJ5U8 | |
Bkqa98oAKjxSQ3zmRgxiQ5SaVHkMZ0mVsPHEkBm9VHfp+3lneDB3kXsn2pY9 | |
JOB4C28NkEMnoh92YH3nuzitZeBYTx+N9mldHNL8Pb3oa+CwAdmqdtJvDhZ4 | |
lPsbR33bQn4bPndtGvghlx0fm+8m++7got3. | |
-----------end_max5_patcher----------- | |
</code></pre> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment