<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
  </head>
  <body>
    <p>Actually, there is no need to use a clock for every scheduled
      LISP function. You can also maintain a seperate scheduler, which
      is just a priority queue for callback functions. In C++, you could
      use a std::map<double, callback_type>. "double" is the
      desired (future) system time, which you can get with
      "clock_getsystimeafter". </p>
    <p>Then you create a *single* clock in the setup function *) with a
      tick method that reschedules itself periodically (e.g.
      clock_delay(x, 1) ). In the tick method, you get the current
      logical time with "clock_getlogicaltime", walk over the priority
      queue and dispatch + remove all items which have a time equal or
      lower. You have to be careful about possible recursion, though,
      because calling a scheduled LISP function might itself schedule
      another function. In the case of std::map, however, it is safe,
      because insertion doesn't invalidate iterators.<br>
    </p>
    <p>Some more ideas:</p>
    <p>Personally, I like to have both one-shot functions and repeated
      functions, being able to change the time/interval and also cancel
      them. For this, it is useful that the API returns some kind of
      identifier for each callback (e.g. an integer ID). This is what
      Javascript does with "setTimeout"/"clearTimeout" and
      "setInterval"/"clearInterval". I use a very similar system for the
      Lua scripting API of my 2D game engine, but I also have
      "resetTimeout" and "resetInterval" functions.</p>
    <p>On the other hand, you could also have a look at the scheduling
      API of the Supercollider, which is a bit different: if a routine
      yields a number N, it means that the routine will be scheduled
      again after N seconds.</p>
    <p>Generally, having periodic timers is very convenient in a musical
      environment :-)<br>
    </p>
    <p>Christof</p>
    <p>*) Don't just store the clock in a global variable, because Pd
      can have several instances. Instead, put the clock in a struct
      which you allocate in the setup function. The clock gets this
      struct as the owner.</p>
    <p>typedef struct _myscheduler { t_clock *clock; } t_myscheduler; //
      this would also be a good place to store the priority queue<br>
    </p>
    <p>t_scheduler *x = getbytes(sizeof(t_myscheduler));</p>
    <p>t_clock *clock = clock_new(x, (t_method)myscheduler_tick);</p>
    <p>x->clock = clock;<br>
    </p>
    <div class="moz-cite-prefix">On 25.10.2020 02:02, Iain Duncan wrote:<br>
    </div>
    <blockquote type="cite"
cite="mid:CAN9NcLxQDOckHL-AUrrKE5rcrKx_SN950t3_LsGotn1E5_sYcQ@mail.gmail.com">
      <meta http-equiv="content-type" content="text/html; charset=UTF-8">
      <div dir="ltr">Thanks Christof, that's very helpful. 
        <div><br>
        </div>
        <div>iain</div>
      </div>
      <br>
      <div class="gmail_quote">
        <div dir="ltr" class="gmail_attr">On Sat, Oct 24, 2020 at 5:53
          PM Christof Ressi <<a href="mailto:info@christofressi.com"
            moz-do-not-send="true">info@christofressi.com</a>> wrote:<br>
        </div>
        <blockquote class="gmail_quote" style="margin:0px 0px 0px
          0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
          <div>
            <p>But if you're still worried, creating a pool of objects
              of the same size is actually quite easy, just use a <a
                href="https://en.wikipedia.org/wiki/Free_list"
                target="_blank" moz-do-not-send="true">https://en.wikipedia.org/wiki/Free_list</a>.</p>
            <p>Christof<br>
            </p>
            <div>On 25.10.2020 02:45, Christof Ressi wrote:<br>
            </div>
            <blockquote type="cite">
              <p> </p>
              <blockquote type="cite">
                <div>A) Am I right, both about being bad, and about
                  clock pre-allocation and pooling being a decent
                  solution?</div>
                <div>B) Does anyone have tips on how one should
                  implement and use said clock pool?</div>
              </blockquote>
              ad A), basically yes, but in Pd you can get away with it.
              Pd's scheduler doesn't run in the actual audio callback
              (unless you run Pd in "callback" mode) and is more
              tolerant towards operations that are not exactly realtime
              friendly (e.g. memory allocation, file IO, firing lots of
              messages, etc.). The audio callback and scheduler thread
              exchange audio samples via a lockfree ringbuffer. The
              "delay" parameter actually sets the size of this
              ringbuffer, and a larger size allows for larger CPU
              spikes.
              <p>In practice, allocating a small struct is pretty fast
                even with the standard memory allocator, so in the case
                of Pd it's nothing to worry about. In Pd land, external
                authors don't really care too much about realtime
                safety, simply because Pd itself doesn't either.<br>
              </p>
              <p>---<br>
              </p>
              <p>Now, in SuperCollider things are different. Scsynth and
                Supernova are quite strict regarding realtime safety
                because DSP runs in the audio callback. In fact, they
                use a special realtime allocator in case a plugin needs
                to allocate memory in the audio thread. Supercollider
                also has a seperate non-realtime thread where you would
                execute asynchronous commands, like loading a soundfile
                into a buffer.</p>
              <p>Finally, all sequencing and scheduling runs in a
                different program (sclang). Sclang sends OSC bundles to
                scsynth, with timestamps in the near future.
                Conceptually, this is a bit similar to Pd's ringbuffer
                scheduler, with the difference that DSP itself never
                blocks. If Sclang blocks, OSC messages will simply
                arrive late at the Server.<br>
              </p>
              <p>Christof<br>
              </p>
              <div>On 25.10.2020 02:10, Iain Duncan wrote:<br>
              </div>
              <blockquote type="cite">
                <div dir="ltr">Hi folks, I'm working on an external for
                  Max and PD embedding the S7 scheme interpreter. It's
                  mostly intended to do things at event level, (algo
                  comp, etc) so I have been somewhat lazy around real
                  time issues so far. But I'd like to make sure it's as
                  robust as it can be, and can be used for as much as
                  possible. Right now, I'm pretty sure I'm being a bad
                  real-time-coder. When the user wants to delay a
                  function call, ie  (delay 100 foo-fun), I'm doing the
                  following:
                  <div><br>
                  </div>
                  <div>- callable foo-fun gets registered in a scheme
                    hashtable with a gensym unique handle</div>
                  <div>- C function gets called with the handle</div>
                  <div>- C code makes a clock, storing it in a hashtable
                    (in C) by the handle, and passing it a struct (I
                    call it the "clock callback info struct") with the
                    references it needs for it's callback</div>
                  <div>- when the clock callback fires, it gets passed a
                    void pointer to the clock-callback-info-struct, uses
                    it to get the cb handle and the ref to the external
                    (because the callback only gets one arg), calls back
                    into Scheme with said handle</div>
                  <div>- Scheme gets the callback out of it's
                    registry and executes the stashed function</div>
                  <div><br>
                  </div>
                  <div>This is working well, but.... I am both
                    allocating and deallocating memory in those
                    functions: for the clock, and for the info struct I
                    use to pass around the reference to the external and
                    the handle. Given that I want to be treating this
                    code as high priority, and having it execute as
                    timing-accurate as possible, I assume I should not
                    be allocating and freeing in those functions,
                    because I could get blocked on the memory calls,
                    correct? I think I should probably have a
                    pre-allocated pool of clocks and their associated
                    info structs so that when a delay call comes in, we
                    get one from the pool, and only do memory management
                    if the pool is empty. (and allow the user to set
                    some reasonable config value of the clock pool). I'm
                    thinking RAM is cheap, clocks are small, people
                    aren't likely to have more than 1000 delay functions
                    running concurrently or something at once, and they
                    can be allocated from the init routine.</div>
                  <div><br>
                  </div>
                  <div>My questions:</div>
                  <div>A) Am I right, both about being bad, and about
                    clock pre-allocation and pooling being a decent
                    solution?</div>
                  <div>B) Does anyone have tips on how one should
                    implement and use said clock pool?</div>
                  <div><br>
                  </div>
                  <div>I suppose I should probably also be ensuring the
                    Scheme hash-table doesn't do any unplanned
                    allocation too, but I can bug folks on the S7
                    mailing list for that one...</div>
                  <div><br>
                  </div>
                  <div>Thanks!</div>
                  <div>iain</div>
                </div>
                <br>
                <fieldset></fieldset>
                <pre>_______________________________________________
Pd-dev mailing list
<a href="mailto:Pd-dev@lists.iem.at" target="_blank" moz-do-not-send="true">Pd-dev@lists.iem.at</a>
<a href="https://lists.puredata.info/listinfo/pd-dev" target="_blank" moz-do-not-send="true">https://lists.puredata.info/listinfo/pd-dev</a>
</pre>
              </blockquote>
              <br>
              <fieldset></fieldset>
              <pre>_______________________________________________
Pd-dev mailing list
<a href="mailto:Pd-dev@lists.iem.at" target="_blank" moz-do-not-send="true">Pd-dev@lists.iem.at</a>
<a href="https://lists.puredata.info/listinfo/pd-dev" target="_blank" moz-do-not-send="true">https://lists.puredata.info/listinfo/pd-dev</a>
</pre>
            </blockquote>
          </div>
          _______________________________________________<br>
          Pd-dev mailing list<br>
          <a href="mailto:Pd-dev@lists.iem.at" target="_blank"
            moz-do-not-send="true">Pd-dev@lists.iem.at</a><br>
          <a href="https://lists.puredata.info/listinfo/pd-dev"
            rel="noreferrer" target="_blank" moz-do-not-send="true">https://lists.puredata.info/listinfo/pd-dev</a><br>
        </blockquote>
      </div>
    </blockquote>
  </body>
</html>