m_pd.c 13.7 KB
Newer Older
Miller Puckette's avatar
Miller Puckette committed
1
2
3
4
5
6
7
8
/* Copyright (c) 1997-1999 Miller Puckette.
* For information on usage and redistribution, and for a DISCLAIMER OF ALL
* WARRANTIES, see the file, "LICENSE.txt," in this distribution.  */

#include <stdlib.h>
#include "m_pd.h"
#include "m_imp.h"

9
10
11
#include "g_canvas.h"
#include <stdio.h>

Miller Puckette's avatar
Miller Puckette committed
12
13
    /* FIXME no out-of-memory testing yet! */

14
/*int canvas_check_duplicate = 0;
15
16
17

extern t_redundant_mem *rm_start;
extern t_redundant_mem *rm_end;
18
*/
19

Miller Puckette's avatar
Miller Puckette committed
20
21
t_pd *pd_new(t_class *c)
{
22
    t_pd *x = NULL;
Miller Puckette's avatar
Miller Puckette committed
23
24
    if (!c) 
        bug ("pd_new: apparently called before setup routine");
25

26
    x = (t_pd *)t_getbytes(c->c_size);
Miller Puckette's avatar
Miller Puckette committed
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
    *x = c;
    if (c->c_patchable)
    {
        ((t_object *)x)->ob_inlet = 0;
        ((t_object *)x)->ob_outlet = 0;
    }
    return (x);
}

void pd_free(t_pd *x)
{
    t_class *c = *x;
    if (c->c_freemethod) (*(t_gotfn)(c->c_freemethod))(x);
    if (c->c_patchable)
    {
        while (((t_object *)x)->ob_outlet)
            outlet_free(((t_object *)x)->ob_outlet);
        while (((t_object *)x)->ob_inlet)
            inlet_free(((t_object *)x)->ob_inlet);
        if (((t_object *)x)->ob_binbuf)
            binbuf_free(((t_object *)x)->ob_binbuf);
    }
    if (c->c_size) t_freebytes(x, c->c_size);
}

void gobj_save(t_gobj *x, t_binbuf *b)
{
    t_class *c = x->g_pd;
    if (c->c_savefn)
        (c->c_savefn)(x, b);
}

/* deal with several objects bound to the same symbol.  If more than one, we
actually bind a collection object to the symbol, which forwards messages sent
to the symbol. */

static t_class *bindlist_class;

typedef struct _bindelem
{
    t_pd *e_who;
    struct _bindelem *e_next;
69
    int e_delayed_free;
Miller Puckette's avatar
Miller Puckette committed
70
71
72
73
74
75
76
77
} t_bindelem;

typedef struct _bindlist
{
    t_pd b_pd;
    t_bindelem *b_list;
} t_bindlist;

78
79
80
81
static int change_bindlist_via_graph = 0;

static void bindlist_cleanup(t_bindlist *x)
{
82
83
    //fprintf(stderr,"bindlist_cleanup\n");
    t_bindelem *e, *e2;
84
    if (x->b_list->e_delayed_free == 1)
85
    {
86
        e = x->b_list;
87
88
        x->b_list = e->e_next;
        freebytes(e, sizeof(t_bindelem));
89
        //fprintf(stderr,"success B1a\n");
90
91
    }
    for (e = x->b_list; e2 = e->e_next; e = e2)
92
        if (e2->e_delayed_free == 1)
93
94
95
    {
        e->e_next = e2->e_next;
        freebytes(e2, sizeof(t_bindelem));
96
        //fprintf(stderr,"success B1b\n");
97
98
99
100
101
102
        break;
    }
    if (!x->b_list->e_next)
    {
        freebytes(x->b_list, sizeof(t_bindelem));
        pd_free(&x->b_pd);
103
        //fprintf(stderr,"success B2\n");
104
105
106
    }
}

Miller Puckette's avatar
Miller Puckette committed
107
108
109
static void bindlist_bang(t_bindlist *x)
{
    t_bindelem *e;
110
    int save = change_bindlist_via_graph;
111
    change_bindlist_via_graph = 1;
Miller Puckette's avatar
Miller Puckette committed
112
    for (e = x->b_list; e; e = e->e_next)
113
        if (e->e_who != NULL) pd_bang(e->e_who);
114
115
116
    if (change_bindlist_via_graph > 1)
        bindlist_cleanup(x);
    change_bindlist_via_graph = save;
Miller Puckette's avatar
Miller Puckette committed
117
118
119
120
121
}

static void bindlist_float(t_bindlist *x, t_float f)
{
    t_bindelem *e;
122
    int save = change_bindlist_via_graph;
123
    change_bindlist_via_graph = 1;
Miller Puckette's avatar
Miller Puckette committed
124
    for (e = x->b_list; e; e = e->e_next)
125
        if (e->e_who != NULL) pd_float(e->e_who, f);
126
127
128
    if (change_bindlist_via_graph > 1)
        bindlist_cleanup(x);
    change_bindlist_via_graph = save;
Miller Puckette's avatar
Miller Puckette committed
129
130
131
132
133
}

static void bindlist_symbol(t_bindlist *x, t_symbol *s)
{
    t_bindelem *e;
134
    int save = change_bindlist_via_graph;
135
    change_bindlist_via_graph = 1;
Miller Puckette's avatar
Miller Puckette committed
136
    for (e = x->b_list; e; e = e->e_next)
137
        if (e->e_who != NULL) pd_symbol(e->e_who, s);
138
139
140
    if (change_bindlist_via_graph > 1)
        bindlist_cleanup(x);
    change_bindlist_via_graph = save;
Miller Puckette's avatar
Miller Puckette committed
141
142
143
144
145
}

static void bindlist_pointer(t_bindlist *x, t_gpointer *gp)
{
    t_bindelem *e;
146
    int save = change_bindlist_via_graph;
147
    change_bindlist_via_graph = 1;
Miller Puckette's avatar
Miller Puckette committed
148
    for (e = x->b_list; e; e = e->e_next)
149
        if (e->e_who != NULL) pd_pointer(e->e_who, gp);
150
151
152
    if (change_bindlist_via_graph > 1)
        bindlist_cleanup(x);
    change_bindlist_via_graph = save;
Miller Puckette's avatar
Miller Puckette committed
153
154
155
156
157
158
}

static void bindlist_list(t_bindlist *x, t_symbol *s,
    int argc, t_atom *argv)
{
    t_bindelem *e;
159
    int save = change_bindlist_via_graph;
160
    change_bindlist_via_graph = 1;
Miller Puckette's avatar
Miller Puckette committed
161
    for (e = x->b_list; e; e = e->e_next)
162
        if (e->e_who != NULL) pd_list(e->e_who, s, argc, argv);
163
164
165
    if (change_bindlist_via_graph > 1)
        bindlist_cleanup(x);
    change_bindlist_via_graph = save;
Miller Puckette's avatar
Miller Puckette committed
166
167
168
169
170
171
}

static void bindlist_anything(t_bindlist *x, t_symbol *s,
    int argc, t_atom *argv)
{
    t_bindelem *e;
172
    int save = change_bindlist_via_graph;
173
    change_bindlist_via_graph = 1;
Miller Puckette's avatar
Miller Puckette committed
174
    for (e = x->b_list; e; e = e->e_next)
175
        if (e->e_who != NULL) pd_typedmess(e->e_who, s, argc, argv);
176
177
178
    if (change_bindlist_via_graph > 1)
        bindlist_cleanup(x);
    change_bindlist_via_graph = save;
Miller Puckette's avatar
Miller Puckette committed
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
}

void m_pd_setup(void)
{
    bindlist_class = class_new(gensym("bindlist"), 0, 0,
        sizeof(t_bindlist), CLASS_PD, 0);
    class_addbang(bindlist_class, bindlist_bang);
    class_addfloat(bindlist_class, (t_method)bindlist_float);
    class_addsymbol(bindlist_class, bindlist_symbol);
    class_addpointer(bindlist_class, bindlist_pointer);
    class_addlist(bindlist_class, bindlist_list);
    class_addanything(bindlist_class, bindlist_anything);
}

void pd_bind(t_pd *x, t_symbol *s)
{
195
    //fprintf(stderr,"pd_bind %s\n", s->s_name);
Miller Puckette's avatar
Miller Puckette committed
196
197
198
199
    if (s->s_thing)
    {
        if (*s->s_thing == bindlist_class)
        {
200
            //fprintf(stderr,"    pd_bind option 1A %lx\n", (t_int)x);
Miller Puckette's avatar
Miller Puckette committed
201
202
203
204
            t_bindlist *b = (t_bindlist *)s->s_thing;
            t_bindelem *e = (t_bindelem *)getbytes(sizeof(t_bindelem));
            e->e_next = b->b_list;
            e->e_who = x;
205
            e->e_delayed_free = 0;
Miller Puckette's avatar
Miller Puckette committed
206
207
208
209
            b->b_list = e;
        }
        else
        {
210
            //fprintf(stderr,"    pd_bind option 1B %lx\n", (t_int)x);
Miller Puckette's avatar
Miller Puckette committed
211
212
213
214
215
216
            t_bindlist *b = (t_bindlist *)pd_new(bindlist_class);
            t_bindelem *e1 = (t_bindelem *)getbytes(sizeof(t_bindelem));
            t_bindelem *e2 = (t_bindelem *)getbytes(sizeof(t_bindelem));
            b->b_list = e1;
            e1->e_who = x;
            e1->e_next = e2;
217
            e1->e_delayed_free = 0;
Miller Puckette's avatar
Miller Puckette committed
218
219
            e2->e_who = s->s_thing;
            e2->e_next = 0;
220
            e2->e_delayed_free = 0;
Miller Puckette's avatar
Miller Puckette committed
221
222
223
            s->s_thing = &b->b_pd;
        }
    }
224
    else {
225
226
227
        //fprintf(stderr,"pd_bind option 2 %lx\n", (t_int)x);
        s->s_thing = x;
    }
Miller Puckette's avatar
Miller Puckette committed
228
229
230
231
}

void pd_unbind(t_pd *x, t_symbol *s)
{
232
    //fprintf(stderr,"pd_unbind %s\n", s->s_name);
233
    if (s->s_thing == x) {
234
        //fprintf(stderr,"    pd_unbind option A %lx\n", (t_int)x);
235
236
        s->s_thing = 0;
    }
Miller Puckette's avatar
Miller Puckette committed
237
238
    else if (s->s_thing && *s->s_thing == bindlist_class)
    {
239
240
241
        /* bindlists always have at least two elements... if the number
           goes down to one, get rid of the bindlist and bind the symbol
           straight to the remaining element. */
Miller Puckette's avatar
Miller Puckette committed
242

243
244
245
246
247
248
        /* in pd-l2ork, we however also check whether changes to the bindlist
           occur via graph (through code execution, e.g. dynamic change of
           receives) and if so, we do not deallocate memory until the entire
           bindlist_<datatype> function is complete with its execution, after
           which we call bindlist_cleanup(). we control the execution via
           static int variable change_bindlist_via_graph */
249

250
        //fprintf(stderr,"    pd_unbind option B %lx\n", (t_int)x);
251

Miller Puckette's avatar
Miller Puckette committed
252
253
254
255
        t_bindlist *b = (t_bindlist *)s->s_thing;
        t_bindelem *e, *e2;
        if ((e = b->b_list)->e_who == x)
        {
256
257
258
259
260
261
262
263
264
265
            if (change_bindlist_via_graph)
            {
                change_bindlist_via_graph++;
                e->e_delayed_free = 1;
            }
            else
            {
                b->b_list = e->e_next;
                freebytes(e, sizeof(t_bindelem));
            }
266
            //fprintf(stderr,"    success B1a %d\n", e->e_delayed_free);
Miller Puckette's avatar
Miller Puckette committed
267
268
269
        }
        else for (e = b->b_list; e2 = e->e_next; e = e2)
        {
270
271
272
273
274
275
276
277
278
279
280
281
            if (e2->e_who == x)
            {
                if (change_bindlist_via_graph)
                {
                    change_bindlist_via_graph++;
                    e2->e_delayed_free = 1;
                }
                else
                {
                    e->e_next = e2->e_next;
                    freebytes(e2, sizeof(t_bindelem));
                }
282
                //fprintf(stderr,"    success B1b %d\n", e->e_delayed_free);
283
284
                break;
            }
Miller Puckette's avatar
Miller Puckette committed
285
        }
286

287
288
        int count_valid = 0;
        t_bindelem *e1 = NULL;
289
        for (e = b->b_list; e; e = e->e_next)
Miller Puckette's avatar
Miller Puckette committed
290
        {
291
292
293
294
295
            if (e->e_who != NULL && !e->e_delayed_free)
            {
                count_valid++;
                e1 = e;
            }
296

297
298
299
        }
        if (count_valid == 1)
        {
300
            s->s_thing = e1->e_who;
301
302
303
304
305
306
            if (!change_bindlist_via_graph)
            {
                freebytes(b->b_list, sizeof(t_bindelem));
                pd_free(&b->b_pd);
            }
            //fprintf(stderr,"success B2\n");
Miller Puckette's avatar
Miller Puckette committed
307
308
309
310
311
312
313
314
315
316
317
        }
    }
    else pd_error(x, "%s: couldn't unbind", s->s_name);
}

void zz(void) {}

t_pd *pd_findbyclass(t_symbol *s, t_class *c)
{
    t_pd *x = 0;
    
318
    //fprintf(stderr,"pd_findbyclass\n");
Miller Puckette's avatar
Miller Puckette committed
319
320
321
322
323
    if (!s->s_thing) return (0);
    if (*s->s_thing == c) return (s->s_thing);
    if (*s->s_thing == bindlist_class)
    {
        t_bindlist *b = (t_bindlist *)s->s_thing;
Mathieu L Bouchard's avatar
Mathieu L Bouchard committed
324
        t_bindelem *e;
Miller Puckette's avatar
Miller Puckette committed
325
326
        int warned = 0;
        for (e = b->b_list; e; e = e->e_next)
327
        {
328
            //if (e->e_who != NULL && *e->e_who == c)
329
            //fprintf(stderr, "(e_who == c)?%d || e->e_delayed_free=%d\n", (*e->e_who == c ? 1 : 0), e->e_delayed_free);
330
            if (e->e_delayed_free != 1 && *e->e_who == c)
331
            {
332
                //fprintf(stderr,"...found %lx", e);
333
334
335
336
337
338
339
340
341
                if (x && !warned)
                {
                    zz();
                    post("warning: %s: multiply defined", s->s_name);
                    warned = 1;
                }
                x = e->e_who;
            }
        }
Miller Puckette's avatar
Miller Puckette committed
342
    }
343
    //fprintf(stderr,"====\n");
Miller Puckette's avatar
Miller Puckette committed
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
    return x;
}

/* stack for maintaining bindings for the #X symbol during nestable loads.
*/

typedef struct _gstack
{
    t_pd *g_what;
    t_symbol *g_loadingabstraction;
    struct _gstack *g_next;
} t_gstack;

static t_gstack *gstack_head = 0;
static t_pd *lastpopped;
static t_symbol *pd_loadingabstraction;

int pd_setloadingabstraction(t_symbol *sym)
{
    t_gstack *foo = gstack_head;
    for (foo = gstack_head; foo; foo = foo->g_next)
        if (foo->g_loadingabstraction == sym)
            return (1);
    pd_loadingabstraction = sym;
    return (0);
}

void pd_pushsym(t_pd *x)
{
    t_gstack *y = (t_gstack *)t_getbytes(sizeof(*y));
    y->g_what = s__X.s_thing;
    y->g_next = gstack_head;
    y->g_loadingabstraction = pd_loadingabstraction;
    pd_loadingabstraction = 0;
    gstack_head = y;
    s__X.s_thing = x;
}

382
383
extern int abort_when_pasting_from_external_buffer;

Miller Puckette's avatar
Miller Puckette committed
384
385
void pd_popsym(t_pd *x)
{
386
387
388
389
390
    if (!gstack_head || s__X.s_thing != x)
    {
        abort_when_pasting_from_external_buffer = 1;
        bug("gstack_pop");
    }
Miller Puckette's avatar
Miller Puckette committed
391
392
393
394
395
396
397
398
399
400
401
402
403
    else
    {
        t_gstack *headwas = gstack_head;
        s__X.s_thing = headwas->g_what;
        gstack_head = headwas->g_next;
        t_freebytes(headwas, sizeof(*headwas));
        lastpopped = x;
    }
}

void pd_doloadbang(void)
{
    if (lastpopped)
404
405
406
    {
        pd_vmess(lastpopped, gensym("loadbang"), "f", LB_LOAD);
    }
Miller Puckette's avatar
Miller Puckette committed
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
    lastpopped = 0;
}

void pd_bang(t_pd *x)
{
    (*(*x)->c_bangmethod)(x);
}

void pd_float(t_pd *x, t_float f)
{
    (*(*x)->c_floatmethod)(x, f);
}

void pd_pointer(t_pd *x, t_gpointer *gp)
{
    (*(*x)->c_pointermethod)(x, gp);
}

void pd_symbol(t_pd *x, t_symbol *s)
{
    (*(*x)->c_symbolmethod)(x, s);
}

Hans-Christoph Steiner's avatar
Hans-Christoph Steiner committed
430
431
432
433
434
435
void pd_blob(t_pd *x, t_blob *st) /* MP20061226 blob type */
{
    /*post("pd_blob: st %p length %lu (*x)->c_blobmethod %p", st, st->s_length, (*x)->c_blobmethod);*/
    (*(*x)->c_blobmethod)(x, st);
}

Miller Puckette's avatar
Miller Puckette committed
436
437
438
439
440
441
442
443
444
445
446
void pd_list(t_pd *x, t_symbol *s, int argc, t_atom *argv)
{
    (*(*x)->c_listmethod)(x, &s_list, argc, argv);
}

void mess_init(void);
void obj_init(void);
void conf_init(void);
void glob_init(void);
void garray_init(void);

447
448
449
450
451
452
453
t_pdinstance *pd_this;

static t_symbol *midi_gensym(const char *prefix, const char *name)
{
    char buf[80];
    strncpy(buf, prefix, 79);
    buf[79] = 0;
454
    buf[79] = 0;
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
    strncat(buf, name, 79 - strlen(buf));
    return (gensym(buf));
}

static t_pdinstance *pdinstance_donew(int useprefix)
{
    t_pdinstance *x = (t_pdinstance *)getbytes(sizeof(t_pdinstance));
    char midiprefix[80];
    if (useprefix)
        sprintf(midiprefix, "%p", x);
    else midiprefix[0] = 0;
    x->pd_systime = 0;
    x->pd_clock_setlist = 0;
    x->pd_dspchain = 0;
    x->pd_dspchainsize = 0;
    x->pd_canvaslist = 0;
    x->pd_dspstate = 0;
472
    x->pd_dspstate_user = 0;
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
    x->pd_midiin_sym = midi_gensym(midiprefix, "#midiin");
    x->pd_sysexin_sym = midi_gensym(midiprefix, "#sysexin");
    x->pd_notein_sym = midi_gensym(midiprefix, "#notein");
    x->pd_ctlin_sym = midi_gensym(midiprefix, "#ctlin");
    x->pd_pgmin_sym = midi_gensym(midiprefix, "#pgmin");
    x->pd_bendin_sym = midi_gensym(midiprefix, "#bendin");
    x->pd_touchin_sym = midi_gensym(midiprefix, "#touchin");
    x->pd_polytouchin_sym = midi_gensym(midiprefix, "#polytouchin");
    x->pd_midirealtimein_sym = midi_gensym(midiprefix, "#midirealtimein");
    return (x);
}

EXTERN t_pdinstance *pdinstance_new(void)
{
    return (pdinstance_donew(1));
}

Miller Puckette's avatar
Miller Puckette committed
490
491
void pd_init(void)
{
492
493
    if (!pd_this)
        pd_this = pdinstance_donew(0);
Miller Puckette's avatar
Miller Puckette committed
494
495
496
497
498
499
    mess_init();
    obj_init();
    conf_init();
    glob_init();
    garray_init();
}
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519

EXTERN void pd_setinstance(t_pdinstance *x)
{
    pd_this = x;
}

EXTERN void pdinstance_free(t_pdinstance *x)
{
    /* placeholder - LATER free symtab, dsp chain, classes and canvases */
}

EXTERN t_canvas *pd_getcanvaslist(void)
{
    return (pd_this->pd_canvaslist);
}

EXTERN int pd_getdspstate(void)
{
    return (pd_this->pd_dspstate);
}