Commitecdada7cRecorded23 Sep 2026Repositorymotif

Let every bed kind take cents: (a just-tuned drone on tracker notes)

Message

Tracker notes are equal-tempered; Harkfell's drone is just-tuned (H5 is 13.7 cents under F#, H7 31.2 under C). cents: multiplies the note by 2^(cents/1200) in every kind of (motif patches beds). test-beds checks a 220 Hz note at +1200 sounds at 440 and C5 at -31.17 sounds at 513.9 Hz.

Changed
 src/motif/patches/beds.sgl | 21 +++++++++++++++------
 src/motif/tests/beds.sgl   | 19 +++++++++++++++++++
 2 files changed, 34 insertions(+), 6 deletions(-)
Diff
src/motif/patches/beds.sglmodified
@@ -20,6 +20,8 @@
20
;;; finding-tone a soft FM tone that pulses, darkened and quietened by
21
;;; `cutoff` and the note volume (how far away it is)
22
;;;
+23
;;; Every kind takes `seed:` (see the drone kinds) and `cents:` (a pitch offset).
+24
;;;
25
;;; Speaker-first (Harkfell design D10): the drone kinds are never pure
26
;;; sines; `bright` (drone-saw) and `index` (drone-fm) keep partials above
27
;;; 300 Hz so a phone speaker carries a low pitch.
@@ -38,6 +40,13 @@
40
(define (wander-gain p rate lo)
41
(if (>= lo 1.0) 1.0 (g:randi rate lo 1.0 (setting p (quote seed) 0.0))))
42
+43
;; The note moved by `cents:` (a just-tuned drone on equal-tempered
+44
;; notes: H5 is -13.7 cents from F#, H7 -31.2 from C); every kind here
+45
;; takes it.
+46
(define (tuned freq p)
+47
(let ((c (setting p (quote cents) 0.0)))
+48
(if (= c 0.0) freq (g:mul freq (expt 2.0 (/ c 1200.0))))))
+49
50
(define (times x y)
51
(cond ((and (number? y) (= y 1.0)) x)
52
((and (number? x) (number? y)) (* x y))
@@ -63,7 +72,7 @@
72
73
(define (noise-bed-graph p)
74
(graph-begin)
−66
(let* ((freq (g:freq))
+75
(let* ((freq (tuned (g:freq) p))
76
(gate (g:gate))
77
(src (noise-source (setting p 'color 'pink) (setting p 'level 0.5) (setting p 'seed 0.0)))
78
(centre (let ((c (setting p 'centre 900.0)))
@@ -103,7 +112,7 @@
112
113
(define (drip-graph p)
114
(graph-begin)
−106
(let* ((freq (g:freq))
+115
(let* ((freq (tuned (g:freq) p))
116
(gate (g:gate))
117
(pitch-env (g:adsr gate 0.0005 (setting p 'sweep 0.04) 0.0 0.01))
118
;; rises from freq to freq * (1 + rise) as pitch-env falls 1 -> 0
@@ -127,7 +136,7 @@
136
137
(define (pipe-breath-graph p)
138
(graph-begin)
−130
(let* ((freq (g:freq))
+139
(let* ((freq (tuned (g:freq) p))
140
(gate (g:gate))
141
(w (min 1.0 (setting p 'width 0.08)))
142
(air (g:pink 1.0 (setting p 'seed 0.0)))
@@ -155,7 +164,7 @@
164
165
(define (drone-saw-graph p)
166
(graph-begin)
−158
(let* ((freq (g:freq))
+167
(let* ((freq (tuned (g:freq) p))
168
(gate (g:gate))
169
(ratio (expt 2.0 (/ (setting p 'detune 4.0) 2400.0)))
170
(a (g:saw (g:mul freq ratio) 0.5))
@@ -177,7 +186,7 @@
186
187
(define (drone-fm-graph p)
188
(graph-begin)
−180
(let* ((freq (g:freq))
+189
(let* ((freq (tuned (g:freq) p))
190
(gate (g:gate))
191
(index (setting p 'index 1.4))
192
(iw (setting p 'index-wander 0.4))
@@ -196,7 +205,7 @@
205
206
(define (finding-tone-graph p)
207
(graph-begin)
−199
(let* ((freq (g:freq))
+208
(let* ((freq (tuned (g:freq) p))
209
(gate (g:gate))
210
(x (g:fosc freq (setting p 'index 1.1) 1.0 2.0 (setting p 'level 0.4)))
211
(x (g:butlp x (setting p 'cutoff 5000.0)))
src/motif/tests/beds.sglmodified
@@ -565,6 +565,24 @@
565
'((drip (decay . 0.02) (echo . 0.4) (feedback . 0.7))
566
(noise-bed (release . 0.1)))))
567
+568
;; cents: moves the pitch. A drone-fm at 220 Hz with cents 1200 sounds
+569
;; at 440; with cents -31.17 on C5 (523.25) it is H7 of D2, 513.9 Hz.
+570
(define (test-cents)
+571
(display "[cents]\n")
+572
(let* ((n sr)
+573
(graph (lambda (params freq)
+574
(bv->vector (%render-graph (make-synth-graph 'drone-fm params) n sr freq 1.0 #f))))
+575
(up (graph '((cents . 1200.0) (breath-lo . 1.0) (index-wander . 0.0) (attack . 0.01)) 220.0))
+576
(h7 (graph '((cents . -31.17) (breath-lo . 1.0) (index-wander . 0.0) (attack . 0.01)) 523.25))
+577
(a440 (tone-amplitude up 440.0 4410 22050))
+578
(a220 (tone-amplitude up 220.0 4410 22050))
+579
(a514 (tone-amplitude h7 513.9 4410 22050))
+580
(a523 (tone-amplitude h7 523.25 4410 22050)))
+581
(assert "cents 1200 puts a 220 Hz note at 440 (440 over 10x 220)"
+582
(> a440 (* 10.0 a220)) (string-append (num a440) " vs " (num a220)))
+583
(assert "cents -31.17 on C5 sounds H7 of D2, 513.9 Hz (over 523.25)"
+584
(> a514 (* 2.0 a523)) (string-append (num a514) " vs " (num a523)))))
+585
586
(define (run-bed-tests)
587
(dsp-init sr)
588
(test-colours)
@@ -573,5 +591,6 @@
591
(test-bandpass)
592
(test-exciter)
593
(test-kinds)
+594
(test-cents)
595
(display (string-append "Beds: " (num passes) " passed, " (num failures) " failed\n"))
596
(if (= failures 0) 0 1))))