From: markt@dgp.toronto.edu ("Mark A. Tapia")
Newsgroups: comp.lang.lisp.mcl
Subject: Re:  Pattern records
Date: 10 Oct 92 22:29:58 GMT
Original-To: bill@cambridge.apple.com
Original-Cc: info-mcl@cambridge.apple.com


howell@cats.UCSC.EDU writes:
 
> The following code should produce lists of zeros pushed into
> "test" and it does not.  Can anyone tell me why not?  Is there
> a problem with "get-internal-real-time?"  This is causing a
> nightmare in a real-time playback system, a problem which has
> not, I think, existed (at least to this degree) in previous
> versions of Mac COMMON LISPSs.
 
> (setq test ())
> (play 60 1000 (get-internal-real-time))
 
> (defun play (MM counter start-time)
>   (cond ((equal counter 0)())
        ((<= start-time (get-internal-real-time))
         (progn
           (push (- start-time (get-internal-real-time)) test)
           ;(play-note 60)
           (play MM (1- counter)(+ start-time MM))))
        (t (play MM counter start-time))))
 
#|
(0 0 0 -13 0 0 0 0 0 0 -11 0 0 0 0 0 0 -7 0 0 0 0 0 0 0 -14 0 0 0 0 0 0 0 0 0 0
0 0 0 0)
3 > test
(0 0 0 -26 0 0 0 -13 0 0 0 0 0 0 -3 0 0 0 0 0 0 0)
|#


Answer:
You're seeing the result of an increased time resolution from
60 ticks per second to 1000 ticks per second (internal-time-units-per-second).
The gaps are on the order of between .003 seconds and .026 seconds
(between 0 seconds and 2/60 second). All gaps up to 17 would not be noticed
before.

Conversion 1 old tick = 50/3 new ticks (or less than 17 new ticks).
Choosing times that are a multiple of 1ms will be much better.

The clock is more likely to advance a tick between the first call to
get-internal-real-time and the second.

If your intention is to "wait" until a certain amount of time (in seconds) 
have elapsed, it would be better to code a specific wait function.
Using the wait function and running without interrupts eliminates
additional ticks.

Results of running the modified version of the play function
with a generalized wait function
                     time  ticks missing
with interrupts     1.930            620
without             1.617              0

(defparameter test nil)

(defun wait-ticks (current-time &optional (n 1/60))
  "wait until the internal time is current-time + n seconds
return the new time and either nil or the excess number of ticks"
  (declare (optimize (speed 3) (safety 0)))
  (let* ((end-time (+ (truncate (* n internal-time-units-per-second))
                      current-time))
         (next-time (get-internal-real-time))
         (wait-time (- end-time next-time)))
    (when (> wait-time 0)
      (loop until (>= next-time end-time)
            do (setq next-time (get-internal-real-time))))
    (values next-time
            (when (> next-time end-time)
              (- next-time end-time)))))

(defun play (MM counter start-time &key (wait-time 1/60))
  (loop until (<= counter 0)
        with gap and time = start-time and gaps = 0
        do (progn  (push (- time (get-internal-real-time)) test)
                   ;(play-note 60)
                   (multiple-value-setq (time gap)
                     (wait-ticks time wait-time))
                   (when gap (incf gaps gap))
                   (decf counter))
        finally (return gaps)))


? (progn
  (gc)
  (setq test nil) 
  (time (play 60 100 (get-internal-real-time))))
(PLAY 60 100 (GET-INTERNAL-REAL-TIME)) took 1930 milliseconds 
(1.930 seconds) to run.
 4056 bytes of memory allocated.
282

? (progn
  (gc)
  (setq test nil) 
  (time (without-interrupts (play 60 100 (get-internal-real-time)))))
(WITHOUT-INTERRUPTS (PLAY 60 100 (GET-INTERNAL-REAL-TIME))) took 1617 milliseconds 
(1.617 seconds) to run.
 4056 bytes of memory allocated.
0
0