load-scheduler # each object is a PF task load-matrix # for pf <-> dsp # never block PD if there's nothing to do, we're polled. 0 microsleep ! # * all words starting with pd- have a ( msg -- msg ) stack effect. # this includes the pd message handlers. # MESSAGE PROTOCOL # call/yield to PD : pd-exchange # "TO PD:" p ps c-yield # "FROM PD:" p ps ; # if this gets errors, they are passed upstream : pd-safe-interpret # msg -- msg try split interpret # dispatch message recover ` error 3 pack # return the error + original message endtry ; # swap running current task with the one stored in the current pd # object. if pd object doesn't have a task (undefined), a new one is # created here. defer new-pd-task : swap/create-object-task # task -- task ` swaptask 2 pack # construct (task <...>) return message pd-exchange # send to pd unpack drop # unpack message undef? if drop new-pd-task then ; # pd task swapper: swap current task with the one stored in object, # passing along the message on top of the data stack. : pd-swaptask # msg -- msg 1 new-task swaptask # swap in dummy task with message swap/create-object-task # swap task with pd object task task-ds-cons # add message to task data stack swaptask drop ; # swap out dummy task : detach-pd-object 0 detach ; # object event loop: first message is constructor : pd-object-loop # \ msg -- begin pd-safe-interpret # interpret message: msg -- msg pd-swaptask # pass control back to driver: msg -- msg again ; :: detach-pd-object pd-object-loop ; is new-pd-task # UTIL -- some library functions for interacting with pd, abstracting # away the message protocol. # since i can't really find a good way to solve all your problems, # 'done' will reset the data stack. note that it is perfectly legal to # keep state on the stack between pd calls. having this as a default # seems a bit safer. : done stack drop () ; # a command is a message with void return : cmd pack pd-exchange drop ; # msg -- : make-outlet ` make-outlet 1 cmd ;; : make-inlet swap ` make-inlet 3 cmd ;; # these will recurse, so we need to swap out the current context : cmd/swap pack pd-swaptask ; : outlet >int ` outlet 3 cmd/swap ;; : send ` send 3 cmd/swap ;; # BASE OBJECT method pd-free :: done ; is pd-free method pd-forth :: interpret-list done ; is pd-forth variable pd-state method pd-bang :: pd-state @ 0 outlet done ; is pd-bang # object factories for different families. # [pf] -> just load a script. runs in fresh task context. : pd-pf size 0 > if split dup load-class interpret then ; # perform a single interaction with PD, then pass the message to the # task associated with the current object. : pd-dispatch-loop # msg -- msg begin pd-exchange # send/receive cycle pd-swaptask # swap in the current task to process message again ; # DONE (initialized) pd-dispatch-loop