Hi there -- I've recently started playing with Impromptu, and am thoroughly enjoying it (thanks!). However, I've found that the make-metre function doesn't always "sync" properly to the metronome. Often, when I ask for beat 1 (for example), it returns #f at a time when it should return #t. I debugged the problem and found that the problem seems to be in floating-point rounding.<div>
<br></div><div>I notice that in the documentation for fmod (which make-metre uses) you say Impromptu rounds to 4 decimal places to "try to avoid some floating point precision problems." I'm still seeing them, in my programs (basically variants on the Messiaen tutorial). Rather than doing rounding, perhaps you might consider using a tolerance/epsilon value in time comparisons.</div>
<div><br></div><div>I modified make-metre to a version which "always" (so far, at least ;-) returns the expected result, regardless of the metronome value and the total metre length (I'm using a length of 12 beats -- one bar in 12/8 time). In case it's useful for anyone, I'll post it here (this can replace the version in time-lib.scm)... With this, my examples work reliably -- without it, every now and then (depending on what value the metronome has at time of first call) my "composing" callback function just does nothing, missing all the beats, especially beat 1! The other problem, specific to queries for beat 1.0 was that often (if the metronome time was a fractional bit below the next beat, e.g. 11.9999), it would compare with "metre-length + 1", i.e. 13, rather than with 1, and so return #f. I added a test for this specific case, which solves all the problems I was having.</div>
<div><br></div><div>;=============== (a bit of time-lib.scm)</div><div><br></div><div><div>; x and y are the numbers to compare</div><div>; tol is the fractional tolerance of the smaller number below</div><div>; which they will be considered "close enough"</div>
<div>(define close-rel (lambda (x y tol)</div><div> (<= (abs (- x y)) (* (abs tol) (min (abs x) (abs y)) ) )</div><div> )</div><div> )</div><div><br></div><div>; this is another version, with an absolute</div>
<div>; tolerance (in units of x and y, not relative in percentage)</div><div>(define close-abs (lambda (x y tol)</div><div> (<= (abs (- x y)) (abs tol))</div><div> )</div><div> )</div>
<div><br></div><div>(define *metre-tol* 1.0e-3)</div><div><br></div><div>; creates a meter where metre is a list of numerators </div><div>; and base is a shared denominator (relative to impromptu beats. i.e. 1 = crotchet, 0.5 = eighth etc.)</div>
<div>; </div><div>; e.g. (define *metre* (make-metre '(2 3 2) 0.5)) = 2/8 3/8 2/8 rotating cycle.</div><div>; </div><div>; then call meter with time and beat </div><div>; if beat matches time then #t else #f</div><div>
;</div><div>; e.g. give the above define</div><div>; (*metre* 2.5 1.0) => #t because 0.0 = 1, 0.5 = 2, 1.0 = 1, 1.5 = 2, 2.0 = 3, 2.5 = 1, 3.0 = 2 and repeat.</div><div>(define make-metre</div><div> (lambda (metre base)</div>
<div> (let ((metre-length (apply + metre)))</div><div> (lambda (time beat)</div><div> (close-abs (let loop ((qtime (fmod (/ time base) metre-length))</div><div> (lst metre)</div>
<div> (valuea (car metre))</div><div> (valueb 0))</div><div> (if (close-abs qtime metre-length *metre-tol*)</div><div> 1.0</div>
<div> (if (< qtime valuea)</div><div> (+ 1.0 (- qtime valueb))</div><div> (loop qtime (cdr lst) (+ valuea (cadr lst)) (+ valueb (car lst)) ) )</div>
<div> )</div><div> )</div><div> beat *metre-tol*)</div><div> )</div><div> )</div><div> )</div><div>)</div><div><br></div><div><div>;===============</div>
<div><br></div><div>Hope this is helpful. Keep up the great work with Impromptu,</div><div>Glen F.</div><div><br></div></div></div>