On Thu, Oct 11, 2012 at 4:26 PM, John Clements
<[email protected]> wrote:
> As part of the rsound package, I find myself reinventing data flow languages; 
> or, at least, the parts that I need. I've come to a design question that I 
> don't know how to answer, and I'm hoping that those with more experience can 
> make suggestions.
>
> First: I'm re-inventing dataflow languages because:
> - the natural way to specify audio signals is as dataflow networks (e.g., I 
> have a low-frequency oscillator controlling the frequency of this other 
> oscillator…), and
> - FrTime is sadly not fast enough to use, here.

Yes.  There are significant opportunities for performance improvement
in FrTime, but for this sort of scenario, I think a "pull" evaluator
will be hard to beat.

> Also, I'm fine with dataflow, here, I don't need full FRP.
>
> The other connection here is to World-style programming; in a big-bang, you 
> specify an initial world and then a transition function (or functions), that 
> map one world to the next. I can't use this framework as-is because of 
> parallel composition issues; specifically, if I have the two oscillators I 
> describe above, then the natural way to represent their state would be as a 
> structure containing the state of each individual component. Allocating a new 
> one of these 44K times per second uses up a lot of memory really quickly. So, 
> I've developed my own framework, that uses mutation but hides it from the 
> user.
>
> Using my "network" syntax, I might specify the above as:
>
> (network ()
>         [lfo (sine-wave 2)]
>         [out (sine-wave (+ 200 (* 10 lfo)))])
>
> This creates a sine wave at 2 Hz, controlling another sine wave whose 
> frequency varies between 210 and 190 Hz twice per second.
>
> Everything fine so far.
>
> In order to make this work, we need signals that refer to old values of 
> themselves, as in the world model. To allow this, I have a "prev" primitive 
> that allows you to refer to the prior value of some signal node. So, for 
> instance, here's a simple counter that goes up one each tick:
>
> (define simple-ctr
>  (network ()
>           [out (add1 (prev out)) #:init 0]))
>
> So, this counter rises by one on each tick. Note that we need to specify an 
> initial value, as with big-bang.
>
> BUT, HERE COMES THE PROBLEM.
>
> What should the first value of this signal be? Should it be zero, or should 
> it be one? Put differently: does this node's updater get called on the first 
> tick, producing 1, or should we just use the initial value, zero?
>
> Zero is the one I really want, but then I have a problem: how do I 
> distinguish between clauses, like this one, that should not be evaluated the 
> first time through, from others, something like this:

Can you not just use the presence of the #:init keyword to disable
evaluation for the first step (or the first n steps in general)?
That's probably what I'd do, though I may be missing something that
makes this problematic...

--Greg

> [sum (+ sig-a sig-b)]
>
> … that *should* be evaluated the first time through?
>
> My current solution is to treat them uniformly, and to evaluate all of them 
> each time. This means that I wind up with dreadful hacks like this one:
>
> [out (add1 (prev out)) #:init -1]
>
> … so that the -1 gets bumped up to a zero on the first output. It turns out 
> that this trick is fragile; if you don't know what the increment will be, you 
> can't accurately "pre-decrement" it.
>
>
> I can imagine doing something more complicated, but what I really want to ask 
> is this: for those of you with experience in other dataflow languages, how do 
> they solve this?
>
>
> Sorry for the long e-mail; I'm hoping that someone can point to a nice 
> solution that exists in another language!
>
>
> John
>
>
>

____________________
  Racket Users list:
  http://lists.racket-lang.org/users

Reply via email to