diff options
| author | Jake Zerrer <him@jakezerrer.com> | 2025-11-18 13:55:24 -0500 |
|---|---|---|
| committer | Jake Zerrer <him@jakezerrer.com> | 2025-11-18 13:55:39 -0500 |
| commit | a78b717c4ecae0b436a47eb34355a54f2ca41f03 (patch) | |
| tree | 494c66650904e1da8e79e6260b9654195d83127c /src | |
| parent | 46a391d3542b142af9e2d196a30f3423216c0343 (diff) | |
Create >measure-clock
Diffstat (limited to 'src')
| -rw-r--r-- | src/unheard/clock.clj | 51 |
1 files changed, 48 insertions, 3 deletions
diff --git a/src/unheard/clock.clj b/src/unheard/clock.clj index 42e7930..89f18c7 100644 --- a/src/unheard/clock.clj +++ b/src/unheard/clock.clj @@ -24,7 +24,8 @@ ;; TODO: Make part of public API (defonce mono-clock-freq (atom 120)) ;; hz (defonce >mono-clock-freq - (m/watch mono-clock-freq)) + (m/signal + (m/watch mono-clock-freq))) (def >mono-clock "This is the base monotonic clock used for driving playback. @@ -55,15 +56,17 @@ (cancel)) (defonce bpm (atom 120)) -(defonce >bpm (m/watch bpm)) +(defonce >bpm + (m/signal + (m/watch bpm))) (def >beat-clock + "Counts beats at `bpm`. Guaranteed not to lose or gain time." (m/signal (m/relieve (let [init-beat 1] (m/reductions {} init-beat (m/ap - ;; Doesn't need to be atom (let [state (object-array 2) _ (aset state 0 (System/nanoTime)) _ (aset state 1 init-beat) @@ -95,3 +98,45 @@ (let [clock (atom 0) >clock (m/signal (m/watch clock))] [>clock clock])) + +(defonce numerator (atom 4)) +(defonce >numerator + (m/signal + (m/watch numerator))) + +(def >measure-clock + "Emits measure count. Increases at the end of the current measure. + Follows changes to numerator." + (m/signal + (m/relieve + (let [init-measure 1] + (m/reductions {} init-measure + (m/ap + (let [state (object-array 2) + last-measure-idx 0 + last-downbeat-idx 1 + _ (aset state last-measure-idx init-measure) + _ (aset state last-downbeat-idx init-measure) + [beat numerator] (m/?< (m/latest vector >beat-clock >numerator)) + last-measure (aget state last-measure-idx) + last-downbeat (aget state last-downbeat-idx) + next-downbeat (+ last-downbeat numerator)] + (if (<= next-downbeat beat) + (do (aset state last-measure-idx (inc last-measure)) + (aset state last-downbeat-idx next-downbeat) + (inc last-measure)) + (m/amb))))))))) + +(comment + (def cancel + ((m/reduce prn nil (m/latest vector >beat-clock >measure-clock)) prn prn)) + + (reset! mono-clock-freq 120) + (reset! bpm 120) + (reset! bpm -120) + (reset! bpm 160) + (reset! numerator 2) + (reset! numerator 3) + (reset! numerator 4) + + (cancel)) |
