[L2Ork-dev] coin-operated scripting language

Jonathan Wilkes jon.w.wilkes at gmail.com
Thu Oct 10 22:41:11 EDT 2019


On Thu, Oct 10, 2019 at 5:25 PM Ivica Bukvic <ico at vt.edu> wrote:
>
> On Thu, Oct 10, 2019 at 8:03 PM Jonathan Wilkes <jon.w.wilkes at gmail.com> wrote:
>>
>> On Thu, Oct 10, 2019 at 11:24 AM Ivica Bukvic <ico at vt.edu> wrote:
>> >
>> > Thank you, Jonathan. I like this as a fresh approach to allowing computation that maintains sync with the main thread. That said, I wonder what advantage this may have from designing simply an external that processes some kind of a potentially existing script and which runs in a separate thread and outputs whenever ready?
>>
>> To maintain determinism you'd need to specify a precise clock callback
>> time at which the results of the script are output. And if the
>> secondary
>> thread still isn't ready at that callback you'd need to block the main
>> thread until it is.
>
>
> Pd has void clock_delay(t_clock *x, double delaytime) exactly for this purpose. clock_delay(x, 0) essentially queues it for the next interrupt.

Right-- by "clock callback" I was talking about the clock_delay interface.

For arbitrary scripts of any complexity value "0" is almost certainly
not enough time. You'd hit the callback and just block until the
script is
ready with its output. So the user would be back to
guessing-and-checking a suitable latency value for their script. Or
like [pd~] you do a
per-instance delay of some number of blocks which you hope is
sufficient for a variety of use cases.

> This is what the disis_wiimote and pd-l2ork version of libcwiid utilizes extensively and it requires several threads to operate as seamlessly as possible in terms of recognizing things like the passthrough interleaved mode between nunchuk and plus. Granted, its threaded design still needs some form of semaphore or mutex that keeps things sane, but this can be fairly universal since its execution is always at the end of the completed computation (whatever that may be). This granularity is the limitation of pd as a language since it can only process updates within the interrupt, even if they occurred earlier during servicing of the audio output (if any), so the aforesaid should be no worse than anything else in the pd-land.
>
>>
>>
>> Additionally, I think there's a greater ease with which the coin
>> operated vm  can be extended and abused. If users really wanted to
>> be able to mutate global state from within the script (say, send to a
>> s/r symbol or write array data) anyone could do a sloppy job of
>> implementing
>> it in a commit and it would probably work. Judging from stackoverflow
>> incorrectness wrt writing a threadsafe refcounting algorithm, I
>> posit that anyone trying to do the same with a threaded design would
>> be merging all kinds of subtle bugs into the mainline repo.
>>
>> > This is how many of our input devices function with their input ostensibly being considerably slower than the interrupt of the main thread (e.g. mice/trackpads and wiimotes). This way the main thread only keeps the last data point stored until the next one is generated and outputted by the external. It seems to me that may be an easier approach than trying to somehow impose coin counting which may be difficult to account for given the CPU utilization will change with a growing complexity of a patch, thereby leaving less time for the object to do its thing before the audio buffer is starved and we get an xrun (assuming the patch involves audio).
>>
>> If the user will only ever need to sample the incoming data from the
>> worker thread that would make sense. But surely users will sometimes
>> need the entire lossless stream of data from the script, no?
>
>
> I suppose, although it is only as lossless as the pd interrupt allows it to be, so on some level this is moot unless it is an audio signal thread.

It's moot for unidirectional data arriving from outside of Pd. But
scripts presumably have an input and an output, and Pd is designed so
that
control data flows in zero logical time. What I'm trying to do is find
a way to break that design pattern while still measuring time and
delivering
output in a predictable and reproducible manner.

I think that can be done with a "script thread" as well but it still
requires the user to provide explicit delays. And AFAICT it requires
your
script to be completely cordoned off from the containing Pd instance.
If a user says, "pretty please let me write to garrays from the script
I swear I'll be careful," and you give in and a decade later the
entire economy of Iceland tanks. :)

Also-- given a sufficient number of coins a "vm" script becomes
synchronous. With your design you'd have to make a special branch
to do that.

On the other hand, I was thinking to limit the number of coins to
something small to encourage thriftiness. :)

-Jonathan

>
> Best,
>
> Ico
>
>>
>>
>> -Jonathan
>>
>>
>>
>> >
>> > Best,
>> >
>> > Ico
>> >
>> > --
>> > Ivica Ico Bukvic, D.M.A.
>> > Director, Creativity + Innovation
>> > Institute for Creativity, Arts, and Technology
>> >
>> > Virginia Tech
>> > Creative Technologies in Music
>> > School of Performing Arts – 0141
>> > Blacksburg, VA 24061
>> > (540) 231-6139
>> > ico at vt.edu
>> >
>> > www.icat.vt.edu
>> > www.performingarts.vt.edu
>> > l2ork.icat.vt.edu
>> > ico.bukvic.net
>> >
>> > On Wed, Oct 9, 2019, 22:48 Jonathan Wilkes <jon.w.wilkes at gmail.com> wrote:
>> >>
>> >> Hi list,
>> >>
>> >> Ok, I've got a little scripting language prototype coded up
>> >> as a Purr Data class.
>> >>
>> >> It's something like this:
>> >>
>> >> [vm var1 var2 etc.;
>> >> + var1 42 10;
>> >> / var2 var1 5;
>> >> etc. etc.]
>> >>
>> >> The idea is that you put your parameters on the first line, then
>> >> you can refer to them in the body.
>> >>
>> >> At the moment I'm just using this notation: "operator destination
>> >> operand1 operand2." It's pretty easy to map another more user-friendly
>> >> syntax on
>> >> top of that with a Pratt parser or something.
>> >>
>> >> Currently I'm just setting a single parameter from the right inlet of the
>> >> object. Once the computation is done, the return value(s) can come out
>> >> of the right outlet.
>> >>
>> >> The novel business happens in the left inlet/outlet
>> >>
>> >> [bang, 12(
>> >> |
>> >> [vm foo;
>> >> + foo 20 1]
>> >> |        |
>> >> [vn bar;
>> >> - bar 63 bar]
>> >> |
>> >> [etc.]
>> >>
>> >> The "bang" tells "vm" to get ready for computation.
>> >>
>> >> The float method then sends 12 "coins" to the inlet. That means
>> >> that the object is allowed to do 12 operations before it suspends
>> >> computation.
>> >>
>> >> Notice in the first [vm] we've only got one explicit operation-- adding
>> >> two numbers. There's another implicit operation where the return value
>> >> is sent to the right outlet. So even though we had 12 "coins" to start,
>> >> our computation only used up 2 of them.
>> >>
>> >> After the right inlet spits out the output, the left outlet spits out the
>> >> "change"-- the leftover "coins" that went unused. Thus, the
>> >> next "vm" object receives "10" coins to its inlet.
>> >>
>> >> And so on and so forth all the way down the chain.
>> >>
>> >> So what happens if we don't give a "vm" enough coins to compute its
>> >> output? It just halts. But you can resume the computation where it left off
>> >> by sending more coins to the left inlet. (If you send coins after computation
>> >> is finished the "vm" just passes them through.)
>> >>
>> >> AFAICT this lets us deterministically suspend and resume computation in the
>> >> control domain without blocking DSP. Consider:
>> >>
>> >> [bang~]
>> >> |
>> >> [20(
>> >> |
>> >> [vm var1;
>> >> some large number;
>> >> of operations in this;
>> >> script to calculate;
>> >> some values for a;
>> >> physics engine;]
>> >>
>> >> Even though the script may not be able to finish in time for a DSP
>> >> deadline, we're only computing 20 operations of the script each block.
>> >> That's very unlikely to interrupt the audio. So as long as we can reach
>> >> the end of the script in time to update the graphics or whatever we're
>> >> trying to achieve, then we should repeatedly hit those deadlines without
>> >> a problem.
>> >>
>> >> Additionally, we can afford to be rather sloppy with the features here. We
>> >> can allow the users to make loops, even infinite ones, without fear of
>> >> locking up the running Purr Data instance. Of course allowing fancier
>> >> branches and loops in the scripts increases the likelihood of surprises
>> >> wrt the number of operations to compute the output. But Pd users seemed
>> >> used to testing weird things until they kind of work.
>> >>
>> >> Anyhow, I'll keep adding ops to this and start looking into some more
>> >> friendly syntax.
>> >>
>> >> The real sticking point will be the entry and exit points. I don't think we
>> >> want to allow arbitrary and/or dynamically sized lists and arrays to
>> >> be read and written. Otherwise we'll have to copy lots of data to protect
>> >> against stale references, and that will easily become a performance
>> >> bottleneck. But I think there's a way to require statically-sized,
>> >> protected data inside the "vm" while still getting pretty expressive
>> >> operations in the script.
>> >>
>> >> -Jonathan
>> >> _______________________________________________
>> >> L2Ork-dev mailing list
>> >> L2Ork-dev at disis.music.vt.edu
>> >> https://disis.music.vt.edu/listinfo/l2ork-dev
>> >
>> > _______________________________________________
>> > L2Ork-dev mailing list
>> > L2Ork-dev at disis.music.vt.edu
>> > https://disis.music.vt.edu/listinfo/l2ork-dev
>> _______________________________________________
>> L2Ork-dev mailing list
>> L2Ork-dev at disis.music.vt.edu
>> https://disis.music.vt.edu/listinfo/l2ork-dev
>
> _______________________________________________
> L2Ork-dev mailing list
> L2Ork-dev at disis.music.vt.edu
> https://disis.music.vt.edu/listinfo/l2ork-dev


More information about the L2Ork-dev mailing list