Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

3121 line
109KB

  1. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  2. ;;; Suggestions, comments and bug reports are welcome. Please
  3. ;;; address email to: nando@ccrma.stanford.edu
  4. ;;;
  5. ;;; see the file COPYING for license info.
  6. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  7. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  8. ;;; Dynamic multichannel three-dimentional signal locator
  9. ;;; (wow that sound good! :-)
  10. ;;;
  11. ;;; by Fernando Lopez Lezcano
  12. ;;; CCRMA, Stanford University
  13. ;;; nando@ccrma.stanford.edu
  14. ;;;
  15. ;;; Thanks to Juan Pampin for help in the initial coding of the new version
  16. ;;; and for prodding me to finish it. To Joseph L. Anderson and Marcelo Perticone
  17. ;;; for insights into the Ambisonics coding and decoding process.
  18. ;;; http://www.york.ac.uk/inst/mustech/3d_audio/ambison.htm for more details...
  19. ;;; CHANGES:
  20. ;;; 01/28/2012: third order ambisonics support (Nando).
  21. ;;; 04/18/2011: various small changes from lint.scm.
  22. ;;; 04/26/2010: add delay hack to remove artifacts in delay output, fix other bugs (Nando)
  23. ;;; added proper doppler src conversion thanks to Bill's code in dsp.scm
  24. ;;; merged in code for higher order ambisonics (up to 2nd order h/v)
  25. ;;; 06/28/2009: remove class/method stuff for s7 (Bill)
  26. ;;; 01/08/2007: make a few functions local etc (Bill)
  27. ;;; 07/05/2006: translate to scheme, use move-sound generator (Bill)
  28. ;;; 04/29/2002: fixed reverb envelopes for no reverb under clisp
  29. ;;; 01/14/2001: added multichannel reverb output with local and global control
  30. ;;; in the reverberator (the hrtf code is currently not merged into
  31. ;;; this version). Reverb-amount can now be an envelope. Ambisonics
  32. ;;; now outputs signal to the reverb stream.
  33. ;;; 02/05/2000: . don't compile as part of the clm package, import symbols
  34. ;;; . switched over to clm-2, otherwise convolve HAS to operate
  35. ;;; on a file, we want convolve to process the output of the
  36. ;;; doppler delay line (for the hrtf code)
  37. ;;; 02/03/2000: started working on hrtf's
  38. ;;; 01/15/2000: rewrote transform-path code to account for 3d paths
  39. ;;; 01/13/2000: . changed order of b-format output file to W:X:Y:Z from X:Y:Z:W
  40. ;;; . plot method would bomb with paths that had constant velocity,
  41. ;;; fixed norm function
  42. ;;; . added make-literal-path and friends to enable to create
  43. ;;; paths with user supplied coordinates
  44. ;;; . decoded-ambisonics was rotating sounds in the wrong direction
  45. ;;; . in change-direction: only check for change if both points are
  46. ;;; different (intersect-inside-radius can create a redundant point)
  47. ;;; 11/28/1999: decoded-ambisonics is now working for N channels
  48. ;;; includes reverberation send
  49. ;;; 11/27/1999: set minimum segment distance for rendering, otherwise for long
  50. ;;; lines the amplitude envelope does not reflect power curve.
  51. ;;; 11/26/1999: added code to check for intersection with inner radius
  52. ;;; fixed nearest-point to handle trivial cases
  53. ;;; 01/21/2001: fix envelope generated for mono reverberation stream.
  54. ;;; change input and output to use frames and mixers
  55. ;;; fix supersonic movement warning code
  56. ;;; > add warnings when object goes outside of area covered by speakers
  57. ;;; > fix one common vertice case of 3 speaker group transitions
  58. ;;; > redo the old code for multiple images (reflections in a rectangular room)
  59. ;;; a bit of a pain, would have to add z (ceiling and floor reflections)
  60. ;;; would be better to find general purpose code for non-rectangular rooms
  61. ;;; > we really need a good N-channel reverb [fixed with freeverb]
  62. ;;; > change reverb to be multichannel, add local and global reverb
  63. ;;; 11/24/1999: should use a waveguide reverb like pph@ccrma project
  64. ;;; would be a good idea to inject the signal through a center
  65. ;;; injection point that moves inside the virtual cube, more like
  66. ;;; a physical model of what actually happens in a room
  67. ;;; | add ambisonics back-end
  68. ;;; 11/24/1999: code to b-format sort of working
  69. ;;; how to deal with the inner space and 0:0:0?
  70. ;;; decoded format not working if we incorporate distance att
  71. ;;; formulas are wrong...
  72. ;;; > add hrtf back-end
  73. ;;; > extract a supath from an existing path
  74. ;;; > recode the transformation functions
  75. ;;; > add arcs of circles and other basic geometric paths
  76. ;;; make it so that you can concatenate them...
  77. ;;; | 11/25/1999 fix the "diagonal case" (sounds go through the head of the listener)
  78. (provide 'snd-dlocsig.scm)
  79. #|
  80. (define* (envelope-interp x e base) ;e is list of x y breakpoint pairs, interpolate at x returning y
  81. ;; "(envelope-interp x e (base 1.0)) -> value of e at x; base controls connecting segment type: (envelope-interp .3 '(0 0 .5 1 1 0) -> .6"
  82. (cond ((null? e) 0.0) ;no data -- return 0.0
  83. ((or (<= x (car e)) ;we're sitting on x val (or if < we blew it)
  84. (null? (cddr e))) ;or we're at the end of the list
  85. (cadr e)) ;so return current y value
  86. ((> (caddr e) x) ;x <= next env x axis value
  87. (if (or (= (cadr e) (cadddr e))
  88. (and base (= base 0.0)))
  89. (cadr e) ;y1=y0, so just return y0 (avoid endless calculations below)
  90. (if (or (not base) (= base 1.0))
  91. (+ (cadr e) ;y0+(x-x0)*(y1-y0)/(x1-x0)
  92. (* (- x (car e))
  93. (/ (- (cadddr e) (cadr e))
  94. (- (caddr e) (car e)))))
  95. (+ (cadr e) ; this does not exactly match xramp-channel
  96. (* (/ (- (cadddr e) (cadr e))
  97. (- base 1.0))
  98. (- (expt base (/ (- x (car e))
  99. (- (caddr e) (car e))))
  100. 1.0))))))
  101. (else (envelope-interp x (cddr e) base)))) ;go on looking for x segment
  102. |#
  103. (define x-norm
  104. (let ((documentation "(x-norm e xmax) changes 'e' x axis values so that they run to 'xmax'"))
  105. (lambda (e xmax)
  106. (let x-norm-1 ((e e)
  107. (scl (/ xmax (e (- (length e) 2))))
  108. (new-e ()))
  109. (if (null? e)
  110. (reverse! new-e)
  111. (x-norm-1 (cddr e) scl (cons (cadr e) (cons (* scl (car e)) new-e))))))))
  112. ;;;;;;;;;;;;;;;;;;;;;
  113. ;;; Global Parameters
  114. ;;; Define the base in which all angles are expressed
  115. (define dlocsig-one-turn 360)
  116. (define one-turn-is
  117. (let ((documentation "(one-turn-is unit) sets dlocsig's angle unit (degrees=360, the default or radians=2*pi)"))
  118. (lambda (unit)
  119. (set! dlocsig-one-turn unit))))
  120. (define angles-in-degree
  121. (let ((documentation "(angles-in-degree) sets dlocsig's unit to degrees (the default)"))
  122. (lambda ()
  123. (one-turn-is 360))))
  124. (define angles-in-radians
  125. (let ((documentation "(angles-in-radians) sets dlocsig's unit to radians (default is degrees)"))
  126. (lambda ()
  127. (one-turn-is (* 2 pi)))))
  128. (define angles-in-turns
  129. (let ((documentation "(angles-in-turns) sets dlocsig's angle unit to turns"))
  130. (lambda ()
  131. (one-turn-is 1))))
  132. ;; speed of sound in air, in meters per second under normal conditions
  133. (define dlocsig-speed-of-sound 344)
  134. (define distances-in-meters
  135. (let ((documentation "(distances-in-meters) sets dlocsig's distances in meters (the default)"))
  136. (lambda ()
  137. (set! dlocsig-speed-of-sound 344))))
  138. (define distances-in-feet
  139. (let ((documentation "(distances-in-feet) sets dlocsig's distances in feet (default is meters)"))
  140. (lambda ()
  141. (set! dlocsig-speed-of-sound 1128))))
  142. ;; default for whether to use two or three-dimensional speaker configurations
  143. (define dlocsig-3d #f)
  144. ;;;;;;;;;;;;;;;;;;;;;;;;;
  145. ;;; Speaker Configuration
  146. (define* (make-group (id 0) (size 0) vertices speakers matrix)
  147. (list 'group id size vertices speakers matrix))
  148. (define group-id (dilambda (lambda (a) (a 1)) (lambda (a b) (set! (a 1) b))))
  149. (define group-size (dilambda (lambda (a) (a 2)) (lambda (a b) (set! (a 2) b))))
  150. (define group-vertices (dilambda (lambda (a) (a 3)) (lambda (a b) (set! (a 3) b))))
  151. (define group-speakers (dilambda (lambda (a) (a 4)) (lambda (a b) (set! (a 4) b))))
  152. (define group-matrix (dilambda (lambda (a) (a 5)) (lambda (a b) (set! (a 5) b))))
  153. (define* (make-speaker-config number dimension coords groups delays omap)
  154. (list 'speaker-config number dimension coords groups delays omap))
  155. (define speaker-config-number (dilambda (lambda (a) (a 1)) (lambda (a b) (set! (a 1) b))))
  156. (define speaker-config-dimension (dilambda (lambda (a) (a 2)) (lambda (a b) (set! (a 2) b))))
  157. (define speaker-config-coords (dilambda (lambda (a) (a 3)) (lambda (a b) (set! (a 3) b))))
  158. (define speaker-config-groups (dilambda (lambda (a) (a 4)) (lambda (a b) (set! (a 4) b))))
  159. (define speaker-config-delays (dilambda (lambda (a) (a 5)) (lambda (a b) (set! (a 5) b))))
  160. (define speaker-config-map (dilambda (lambda (a) (a 6)) (lambda (a b) (set! (a 6) b))))
  161. ;;; Create a speaker configuration structure based on a list of speakers
  162. ;;;
  163. ;;; speakers: list of angles of speakers with respect to 0
  164. ;;; delays: list of delays for each speaker, zero if nil
  165. ;;; distances: list relative speaker distances,
  166. ;;; (instead of delays)
  167. ;;; omap: mapping of speakers to output channels
  168. ;;; content should be output channel number, zero based
  169. (define cis
  170. (let ((documentation "(cis a) returns e^(ia)"))
  171. (lambda (a)
  172. (exp (* 0.0+1.0i a)))))
  173. (define third
  174. (let ((documentation "(third lst) returns the 3rd element of 'lst'"))
  175. (lambda (a)
  176. (and (>= (length a) 3) (a 2)))))
  177. (define fourth
  178. (let ((documentation "(fourth lst) returns the 4th element of 'lst'"))
  179. (lambda (a)
  180. (and (>= (length a) 4) (a 3)))))
  181. (define* (last lst (n 1))
  182. (and (pair? lst)
  183. (list-tail lst (- (length lst) n))))
  184. (define* (arrange-speakers (speakers ())
  185. (groups ())
  186. (delays ())
  187. (distances ())
  188. (channel-map ()))
  189. ;; sanity checking of configuration
  190. (define (has-duplicates? lst)
  191. (and (not (null? lst))
  192. (or (member (car lst) (cdr lst))
  193. (has-duplicates? (cdr lst)))))
  194. (define (invert3x3 mat) ; invert a 3x3 matrix using cofactors
  195. (let ((m (make-float-vector '(3 3))))
  196. (do ((i 0 (+ i 1)))
  197. ((= i 3))
  198. (do ((j 0 (+ j 1)))
  199. ((= j 3))
  200. (set! (m i j) (mat i j))))
  201. (set! (mat 0 0) (- (* (m 1 1) (m 2 2)) (* (m 1 2) (m 2 1))))
  202. (set! (mat 0 1) (- (* (m 0 2) (m 2 1)) (* (m 0 1) (m 2 2))))
  203. (set! (mat 0 2) (- (* (m 0 1) (m 1 2)) (* (m 0 2) (m 1 1))))
  204. (set! (mat 1 0) (- (* (m 1 2) (m 2 0)) (* (m 1 0) (m 2 2))))
  205. (set! (mat 1 1) (- (* (m 0 0) (m 2 2)) (* (m 0 2) (m 2 0))))
  206. (set! (mat 1 2) (- (* (m 0 2) (m 1 0)) (* (m 0 0) (m 1 2))))
  207. (set! (mat 2 0) (- (* (m 1 0) (m 2 1)) (* (m 1 1) (m 2 0))))
  208. (set! (mat 2 1) (- (* (m 0 1) (m 2 0)) (* (m 0 0) (m 2 1))))
  209. (set! (mat 2 2) (- (* (m 0 0) (m 1 1)) (* (m 0 1) (m 1 0))))
  210. (let ((det (+ (* (m 0 0) (mat 0 0))
  211. (* (m 0 1) (mat 1 0))
  212. (* (m 0 2) (mat 2 0)))))
  213. (and (> (abs det) 1e-06)
  214. (do ((invdet (/ 1.0 det))
  215. (row 0 (+ 1 row)))
  216. ((= row 3) mat)
  217. (do ((col 0 (+ 1 col)))
  218. ((= col 3))
  219. (set! (mat row col) (* (mat row col) invdet))))))))
  220. (define (invert2x2 mat) ; invert a 2x2 matrix
  221. (let ((m (make-float-vector '(2 2)))
  222. (det (- (* (mat 0 0) (mat 1 1))
  223. (* (mat 1 0) (mat 0 1)))))
  224. (and (> (abs det) 1e-06)
  225. (begin
  226. (set! (m 0 0) (/ (mat 1 1) det))
  227. (set! (m 1 1) (/ (mat 0 0) det))
  228. (set! (m 0 1) (- (/ (mat 0 1) det)))
  229. (set! (m 1 0) (- (/ (mat 1 0) det)))
  230. m))))
  231. (if (null? speakers)
  232. (error 'mus-error "a speaker configuration must have at least one speaker!~%"))
  233. (if (pair? groups)
  234. (let ((first-len (length (car groups))))
  235. (for-each
  236. (lambda (group)
  237. (if (not (= (length group) first-len))
  238. (error 'mus-error "all groups must be of the same length! (~A)~%" first-len)))
  239. groups))
  240. ;; if the speakers are defined with only azimuth angles (no elevation)
  241. (if (not (pair? (car speakers)))
  242. ;; then create the groups ourselves because it is a 2d configuration;
  243. ;; we could create the 3d configuration groups but the algorithm for
  244. ;; doing that in the generic case is not trivial
  245. (let ((len (length speakers)))
  246. (if (= len 1)
  247. (set! groups (list (list 0)))
  248. (do ((i 0 (+ i 1))
  249. (j 1 (+ j 1)))
  250. ((= i len)
  251. (set! groups (reverse groups)))
  252. (set! groups (cons (list i (modulo j len)) groups)))))))
  253. (if (null? groups)
  254. (error 'mus-error "no groups specified, speakers must be arranged in groups~%"))
  255. (when (pair? delays)
  256. (if (pair? distances)
  257. (error 'mus-error "please specify delays or distances but not both~%"))
  258. (if (> (length speakers) (length delays))
  259. (error 'mus-error "all speaker delays have to be specified, only ~A supplied [~A]~%" (length delays) delays)
  260. (if (< (length speakers) (length delays))
  261. (error 'mus-error "more speaker delays than speakers, ~A supplied instead of ~A [~A]~%" (length delays) (length speakers) delays)))
  262. (for-each
  263. (lambda (dly)
  264. (if (< dly 0.0) (error 'mus-error "delays must be all positive, ~A is negative~%" dly)))
  265. delays))
  266. (when (pair? distances)
  267. (if (> (length speakers) (length distances))
  268. (error 'mus-error "all speaker distances have to be specified, only ~A supplied [~A]~%" (length distances) distances)
  269. (if (< (length speakers) (length distances))
  270. (error 'mus-error "more speaker distances than speakers, ~A supplied instead of ~A [~A]~%" (length distances) (length speakers) distances)))
  271. (for-each
  272. (lambda (dly)
  273. (if (< dly 0.0) (error 'mus-error "distances must be all positive, ~A is negative~%" dly)))
  274. distances))
  275. (if (pair? channel-map)
  276. (if (> (length speakers) (length channel-map))
  277. (error 'mus-error "must map all speakers to output channels, only ~A mapped [~A]~%" (length channel-map) channel-map)
  278. (if (< (length speakers) (length channel-map))
  279. (error 'mus-error "trying to map more channels than there are speakers, ~A supplied instead of ~A [~A]~%"
  280. (length channel-map) (length speakers) channel-map))))
  281. ;; collect unit vectors describing the speaker positions
  282. (let* ((coords
  283. (let ((val ()))
  284. (for-each
  285. (lambda (s) ; speakers
  286. (let* ((evec (let ((e (if (pair? s) (or (cadr s) 0.0) 0.0)))
  287. (cis (/ (* e 2 pi) dlocsig-one-turn))))
  288. (avec (let ((a (if (pair? s) (car s) s)))
  289. (cis (/ (* a 2 pi) dlocsig-one-turn))))
  290. (dxy (real-part evec))
  291. (z (imag-part evec))
  292. (x (* dxy (imag-part avec)))
  293. (y (* dxy (real-part avec)))
  294. (mag (sqrt (+ (* x x) (* y y) (* z z)))))
  295. (set! val (cons (list (/ x mag) (/ y mag) (/ z mag)) val))))
  296. speakers)
  297. (reverse val)))
  298. ;; find delay times from specified distances or delays
  299. (times (let ((min-dist (if (pair? distances) ; minimum distance
  300. (apply min distances)
  301. 0.0))
  302. (v (make-float-vector (length speakers))))
  303. (do ((i 0 (+ i 1)))
  304. ((= i (length speakers)))
  305. (set! (v i) (let ((distance (and (pair? distances) (distances i)))
  306. (dly (and (pair? delays) (delays i))))
  307. (or dly
  308. (and (number? distance)
  309. (/ (- distance min-dist) dlocsig-speed-of-sound))
  310. 0.0))))
  311. v))
  312. ;; create the group structures
  313. (groups (let ((vals ())
  314. (id 0))
  315. (for-each
  316. (lambda (group)
  317. (let* ((size (length group))
  318. (vertices (map coords group))
  319. (matrix (if (= size 3)
  320. (do ((m (make-float-vector '(3 3)))
  321. (i 0 (+ i 1)))
  322. ((= i 3)
  323. (invert3x3 m))
  324. (do ((j 0 (+ j 1)))
  325. ((= j 3))
  326. (set! (m i j) ((vertices i) j))))
  327. (and (= size 2)
  328. (do ((m (make-float-vector '(2 2)))
  329. (i 0 (+ i 1)))
  330. ((= i 2)
  331. (invert2x2 m))
  332. (do ((j 0 (+ j 1)))
  333. ((= j 2))
  334. (set! (m i j) ((vertices i) j))))))))
  335. (set! vals (cons (make-group :id id
  336. :size size
  337. :speakers group
  338. :vertices vertices
  339. :matrix matrix)
  340. vals))
  341. (set! id (+ 1 id))))
  342. groups)
  343. (reverse vals))))
  344. ;; check validity of map entries
  345. (if channel-map
  346. (let ((entries (length channel-map)))
  347. (for-each
  348. (lambda (entry)
  349. (if (>= entry entries)
  350. (error 'mus-error "channel ~A in map ~A is out of range (max=~A)~%" entry channel-map entries)))
  351. channel-map)
  352. (if (has-duplicates? channel-map)
  353. (error 'mus-error "there are duplicate channels in channel-map ~A~%" channel-map))))
  354. ;; create the speaker configuration structure
  355. (make-speaker-config :number (length speakers)
  356. :dimension (group-size (car groups))
  357. :coords coords
  358. :groups groups
  359. :delays times
  360. :omap (do ((v (make-vector (length speakers)))
  361. (chan 0 (+ 1 chan)))
  362. ((= chan (length speakers)) v)
  363. (set! (v chan) (or (and (pair? channel-map) (channel-map chan))
  364. chan))))))
  365. ;;; Default speaker configurations
  366. (define dlocsig-speaker-configs
  367. ;; by default up to eight channels, 2-d and 3-d configurations
  368. (list
  369. (list
  370. ;;
  371. ;; 2-D speaker configurations
  372. ;; no channels: impossible
  373. #f
  374. ;; mono
  375. (arrange-speakers :speakers '(0))
  376. ;; stereo
  377. (arrange-speakers :speakers '(-60 60))
  378. ;; three channels
  379. (arrange-speakers :speakers '(-45 45 180))
  380. ;; four channels
  381. (arrange-speakers :speakers '(-45 45 135 225))
  382. ;; five channels (5.1 arrangement)
  383. (arrange-speakers :speakers '(-45 0 45 135 -135))
  384. ;; six channels
  385. (arrange-speakers :speakers '(-60 0 60 120 180 240))
  386. ;; seven channels
  387. (arrange-speakers :speakers '(-45 0 45 100 140 -140 -100))
  388. ;; eight speakers
  389. (arrange-speakers :speakers '(-22.5 22.5 67.5 112.5 157.5 202.5 247.5 292.5)))
  390. ;;
  391. ;; 3-D speaker configurations
  392. ;;
  393. (list
  394. ;; no channels: impossible
  395. #f
  396. ;; mono
  397. #f
  398. ;; stereo
  399. #f
  400. ;; three channels
  401. #f
  402. ;; four channels 3d
  403. (arrange-speakers :speakers '((-60 0) (60 0) (180 0)
  404. (0 90))
  405. :groups '((0 1 3) (1 2 3) (2 0 3)
  406. ;; floor
  407. (0 1 2)))
  408. ;; five channels 3d
  409. (arrange-speakers :speakers '((-45 0) (45 0) (135 0) (-135 0)
  410. (0 90))
  411. :groups '((0 1 4) (1 2 4) (2 3 4) (3 0 4)
  412. ;; floor
  413. (0 1 2) (2 3 0)))
  414. ;; six channels 3d
  415. (arrange-speakers :speakers '((-45 0) (45 0) (135 0) (-135 0)
  416. (-90 60) (90 60))
  417. :groups '((0 1 4) (1 4 5) (1 2 5) (2 3 5) (3 4 5) (3 0 4)
  418. ;; floor
  419. (0 1 2) (2 3 0)))
  420. ;; seven channels 3d
  421. (arrange-speakers :speakers '((-45 0) (45 0) (135 0) (-135 0)
  422. (-60 60) (60 60) (180 60))
  423. :groups '((0 1 4) (1 4 5) (1 2 5) (2 6 5) (2 3 6) (3 4 6) (3 0 4) (4 5 6)
  424. ;; floor
  425. (0 1 2) (2 3 0)))
  426. ;; eight speakers 3d
  427. (arrange-speakers :speakers '((-45 -10) (45 -10) (135 -10) (225 -10)
  428. (-45 45) (45 45) (135 45) (225 45))
  429. :groups '((0 4 5) (0 5 1) (5 1 2) (2 6 5) (6 7 2) (2 3 7)
  430. (3 7 4) (3 0 4)
  431. ;; ceiling
  432. (4 7 6) (6 5 4)
  433. ;; floor
  434. (0 1 2) (2 3 0))))))
  435. ;;; Set a particular speaker configuration
  436. (define set-speaker-configuration
  437. (let ((documentation "(set-speaker-configuration config (configs dlocsig-speaker-configs)) sets a dlocsig speaker configuration"))
  438. (lambda* (config (configs dlocsig-speaker-configs))
  439. (let ((lst ((if (< (speaker-config-dimension config) 3) car cadr) configs))
  440. (num (speaker-config-number config)))
  441. (set! (lst num) config)))))
  442. ;;; Get the speaker configuration for a given number of output channels
  443. (define get-speaker-configuration
  444. (let ((documentation "(get-speaker-configuration channels (3d dlocsig-3d) (configs dlocsig-speaker-configs)) returns a dlocsig speaker configuration"))
  445. (lambda* (channels (3d dlocsig-3d) (configs dlocsig-speaker-configs))
  446. (let ((config (((if 3d cadr car) configs) channels)))
  447. (if (null? config)
  448. (error 'mus-error "no speaker configuration exists for ~A ~A output channel~A~%~%"
  449. (if 3d "tridimensional" "bidimensional")
  450. channels (if (= channels 1) "s" "")))
  451. config))))
  452. ;;;;;;;;;;;;;;;;;;;;;;;;;;
  453. ;;; Dlocsig unit generator
  454. ;;;;;;;;;;;;;;;;;;;;;;;;;;
  455. ;;; global dlocsig parameters
  456. (define dlocsig-path ())
  457. (define dlocsig-scaler 1.0)
  458. (define dlocsig-direct-power 1.5)
  459. (define dlocsig-inside-direct-power 1.5)
  460. (define dlocsig-reverb-power 0.5)
  461. (define dlocsig-inside-reverb-power 0.5)
  462. (define dlocsig-initial-delay #f)
  463. (define dlocsig-unity-gain-distance #f)
  464. (define dlocsig-reverb-amount 0.04)
  465. (define dlocsig-inside-radius 1.0)
  466. (define dlocsig-minimum-segment-length 1.0)
  467. ;; render using:
  468. (define amplitude-panning 1)
  469. (define ambisonics 2)
  470. (define decoded-ambisonics 3)
  471. ;(define stereo-hrtf 4)
  472. ; for backwards compatibility
  473. (define b-format-ambisonics ambisonics)
  474. ; a reasonable default
  475. (define dlocsig-render-using amplitude-panning)
  476. ;; ambisonics horizontal and vertical order for encoding
  477. ;; the default is first order b-format WXYZ
  478. (define dlocsig-ambisonics-h-order 1)
  479. (define dlocsig-ambisonics-v-order 1)
  480. ;; globals for ambisonics
  481. (define point707 (cos (/ (* pi 2) 8.0)))
  482. (define dlocsig-ambisonics-scaler point707)
  483. (define dlocsig-ambisonics-ho-rev-scaler 0.05)
  484. ;; for 3rd order FuMa
  485. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  486. ;;; Get number of channels needed by ambisonics
  487. (define* (ambisonics-channels
  488. (h-order dlocsig-ambisonics-h-order)
  489. (v-order dlocsig-ambisonics-v-order))
  490. (if (< h-order 0)
  491. 0 ;; error: we need at least horizontal order 1!
  492. (let ((count 0))
  493. (if (>= h-order 1)
  494. ;; W X Y
  495. (set! count (+ count 3)))
  496. (if (>= v-order 1)
  497. ;; Z
  498. (set! count (+ count 1)))
  499. (if (>= v-order 2)
  500. ;; R S T
  501. (set! count (+ count 3)))
  502. (if (>= h-order 2)
  503. ;; U V
  504. (set! count (+ count 2)))
  505. (if (>= v-order 3)
  506. ;; K L M N O
  507. (set! count (+ count 5)))
  508. (if (>= h-order 3)
  509. ;; P Q
  510. (set! count (+ count 2)))
  511. count)))
  512. ;;;;;;;;;
  513. ;;; Paths
  514. ;;;;;;;;;
  515. ;;; Generic path class
  516. ;;; path is a list (type rx ry rz rv rt tx ty tz tt ...)
  517. (define path-rx (dilambda (lambda (p) (p 1)) (lambda (p val) (set! (p 1) val))))
  518. (define path-ry (dilambda (lambda (p) (p 2)) (lambda (p val) (set! (p 2) val))))
  519. (define path-rz (dilambda (lambda (p) (p 3)) (lambda (p val) (set! (p 3) val))))
  520. (define path-rv (dilambda (lambda (p) (p 4)) (lambda (p val) (set! (p 4) val))))
  521. (define path-rt (dilambda (lambda (p) (p 5)) (lambda (p val) (set! (p 5) val))))
  522. (define path-tx (dilambda (lambda (p) (p 6)) (lambda (p val) (set! (p 6) val))))
  523. (define path-ty (dilambda (lambda (p) (p 7)) (lambda (p val) (set! (p 7) val))))
  524. (define path-tz (dilambda (lambda (p) (p 8)) (lambda (p val) (set! (p 8) val))))
  525. (define path-tt (dilambda (lambda (p) (p 9)) (lambda (p val) (set! (p 9) val))))
  526. ;(define (make-path) (list 'path () () () () () () () () ()))
  527. #|
  528. (define (describe path)
  529. (format #f
  530. (if (memq (car path) '(bezier-path open-bezier-path))
  531. (values
  532. "<bezier-path>:~% rx: ~A~% ry: ~A~% rz: ~A~% rv: ~A~% rt: ~A~% tx: ~A~% ty: ~A~% tz: ~A~% tt: ~A~% ~
  533. x: ~A~% y: ~A~% z: ~A~% v: ~A~% bx: ~A~% by: ~A~% bz: ~A~% error: ~A~% curvature: ~A~%"
  534. (path-rx path) (path-ry path) (path-rz path) (path-rv path) (path-rt path) (path-tx path)
  535. (path-ty path) (path-tz path) (path-tt path) (bezier-x path) (bezier-y path)
  536. (bezier-z path) (bezier-v path) (bezier-bx path) (bezier-by path) (bezier-bz path)
  537. (bezier-error path) (bezier-curvature path))
  538. (values
  539. "<path>:~% rx: ~A~% ry: ~A~% rz: ~A~% rv: ~A~% rt: ~A~% tx: ~A~% ty: ~A~% tz: ~A~% tt: ~A~%"
  540. (path-rx path) (path-ry path) (path-rz path) (path-rv path) (path-rt path) (path-tx path)
  541. (path-ty path) (path-tz path) (path-tt path)))))
  542. |#
  543. ;;; Inquiries into the state of the path
  544. (define (not-rendered path)
  545. (null? (path-rx path)))
  546. (define (not-transformed path)
  547. (null? (path-tx path)))
  548. ;;; Reset any transformations on the originally rendered path
  549. (define (reset-transformation path)
  550. (set! (path-tt path) ())
  551. (set! (path-tx path) ())
  552. (set! (path-ty path) ())
  553. (set! (path-tz path) ())
  554. path)
  555. ;;; Reset the rendered path (and any transformations)
  556. (define (reset-rendering path)
  557. (set! (path-rt path) ())
  558. (set! (path-rv path) ())
  559. (set! (path-rx path) ())
  560. (set! (path-ry path) ())
  561. (set! (path-rz path) ())
  562. (reset-transformation path))
  563. ;;; Return the best possible set of coordinates
  564. (define list??
  565. (let ((documentation "list?? returns a if it is a list"))
  566. (lambda (a)
  567. (and (pair? a) a))))
  568. (define (path-x path)
  569. (or (list?? (path-tx path))
  570. (list?? (path-rx path))
  571. (path-rx (render-path path))))
  572. (define (path-y path)
  573. (or (list?? (path-ty path))
  574. (list?? (path-ry path))
  575. (path-ry (render-path path))))
  576. (define (path-z path)
  577. (or (list?? (path-tz path))
  578. (list?? (path-rz path))
  579. (path-rz (render-path path))))
  580. (define (path-time path)
  581. (or (list?? (path-tt path))
  582. (list?? (path-rt path))
  583. (path-rt (render-path path))))
  584. ;;;;;;;;;;;;;;;;
  585. ;;; Bezier paths
  586. ;;;;;;;;;;;;;;;;
  587. ;;; Parse a path as two or three-dimensional paths
  588. (define path-3d #f)
  589. ;;; Path class for bezier rendered paths
  590. ;;; bezier-path is path + path 3d polar x y z v bx by bz error curvature
  591. (define bezier-path (dilambda (lambda (p) (p 10)) (lambda (p val) (set! (p 10) val))))
  592. (define bezier-3d (dilambda (lambda (p) (p 11)) (lambda (p val) (set! (p 11) val))))
  593. (define bezier-polar (dilambda (lambda (p) (p 12)) (lambda (p val) (set! (p 12) val))))
  594. (define bezier-x (dilambda (lambda (p) (p 13)) (lambda (p val) (set! (p 13) val))))
  595. (define bezier-y (dilambda (lambda (p) (p 14)) (lambda (p val) (set! (p 14) val))))
  596. (define bezier-z (dilambda (lambda (p) (p 15)) (lambda (p val) (set! (p 15) val))))
  597. (define bezier-v (dilambda (lambda (p) (p 16)) (lambda (p val) (set! (p 16) val))))
  598. (define bezier-bx (dilambda (lambda (p) (p 17)) (lambda (p val) (set! (p 17) val))))
  599. (define bezier-by (dilambda (lambda (p) (p 18)) (lambda (p val) (set! (p 18) val))))
  600. (define bezier-bz (dilambda (lambda (p) (p 19)) (lambda (p val) (set! (p 19) val))))
  601. (define bezier-error (dilambda (lambda (p) (p 20)) (lambda (p val) (set! (p 20) val))))
  602. (define bezier-curvature (dilambda (lambda (p) (p 21)) (lambda (p val) (set! (p 21) val))))
  603. (define* (make-bezier-path (path ()) (3d #t) polar (error 0.01) curvature)
  604. (list 'bezier-path () () () () () () () () () path 3d polar () () () () () () () error curvature))
  605. ;;; Path class for open bezier paths
  606. (define initial-direction (dilambda (lambda (p) (p 22)) (lambda (p val) (set! (p 22) val))))
  607. (define final-direction (dilambda (lambda (p) (p 23)) (lambda (p val) (set! (p 23) val))))
  608. (define* (make-open-bezier-path (path ()) (3d #t) polar (error 0.01) curvature
  609. (initial-direction '(0.0 0.0 0.0)) (final-direction '(0.0 0.0 0.0)))
  610. (list 'open-bezier-path () () () () () () () () () path 3d polar () () () () () () () error curvature initial-direction final-direction))
  611. ;;;
  612. ;;; Generic defining function (for open, closed, polar and cartesian paths)
  613. ;;;
  614. (define make-path
  615. (let ()
  616. (define (make-path-error-checks path closed initial-direction final-direction)
  617. ;; some sanity checks
  618. (if (null? path)
  619. (error 'mus-error "Can't define a path with no points in it~%"))
  620. (when closed
  621. (if initial-direction
  622. (error 'mus-error "Can't specify initial direction ~A for a closed path ~A~%" initial-direction path))
  623. (if final-direction
  624. (error 'mus-error "Can't specify final direction ~A for a closed path ~A~%" final-direction path))
  625. (let ((closed? (if (pair? (car path))
  626. (let ((start (car path))
  627. (end (car (last path))))
  628. (and (= (car start) (car end))
  629. (= (cadr start) (cadr end))
  630. (or (not path-3d)
  631. (= (third start) (third end)))))
  632. (let ((end (last path (if path-3d 3 2))))
  633. (and (= (car path) (car end))
  634. (= (cadr path) (cadr end))
  635. (or (not path-3d)
  636. (= (third path) (third end))))))))
  637. (if (not closed?)
  638. (error 'mus-error "Closed path ~A is not closed~%" path)))))
  639. (lambda* (path
  640. (3d path-3d)
  641. polar
  642. closed
  643. curvature
  644. (error 0.01) ; this name ("error") is a bad idea -- it means we can't call the real error function (this is Scheme, not CL)
  645. ;; only for open paths
  646. initial-direction
  647. final-direction)
  648. (make-path-error-checks path closed initial-direction final-direction) ; the error check uses path-3d -- was 3d intended?
  649. ;; create the path structure
  650. (if closed
  651. (make-bezier-path
  652. :path path
  653. :3d 3d
  654. :polar polar
  655. :curvature curvature
  656. :error error)
  657. (make-open-bezier-path
  658. :path path
  659. :3d 3d
  660. :polar polar
  661. :curvature curvature
  662. :error error
  663. :initial-direction initial-direction
  664. :final-direction final-direction)))))
  665. ;;; Some convenient abbreviations
  666. (define* (make-polar-path path
  667. (3d path-3d)
  668. closed
  669. curvature
  670. (error 0.01)
  671. ;; only for open paths
  672. initial-direction
  673. final-direction)
  674. (if closed
  675. (make-path :path path
  676. :3d 3d
  677. :polar #t
  678. :closed closed
  679. :curvature curvature
  680. :error error)
  681. (make-path :path path
  682. :3d 3d
  683. :polar #t
  684. :closed closed
  685. :curvature curvature
  686. :error error
  687. :initial-direction initial-direction
  688. :final-direction final-direction)))
  689. (define* (make-closed-path path
  690. (3d path-3d)
  691. polar
  692. curvature
  693. (error 0.01))
  694. (make-path :path path
  695. :3d 3d
  696. :polar polar
  697. :closed #t
  698. :curvature curvature
  699. :error error))
  700. ;;;
  701. ;;; Parse a path and transform it into cartesian coordinates
  702. ;;;
  703. (define (not-parsed path)
  704. (null? (bezier-x path)))
  705. ;;; Parse a set of 2d or 3d points into the separate coordinates
  706. (define parse-cartesian-coordinates
  707. (let ((documentation "(parse-cartesian-coordinates points 3d) parses a set of 2d or 3d points into the separate coordinates"))
  708. (lambda (points 3d)
  709. (if (pair? (car points))
  710. ;; decode a list of lists into x:y:z:v components
  711. ;; 3d -> t [default]
  712. ;; '((x0 y0 z0 v0) (x1 y1 z1 v1)...(xn yn zn vn))
  713. ;; '((x0 y0 z0) (x1 y1 z1)...(xn yn zn))
  714. ;; '((x0 y0) (x1 y1)...(xn yn))
  715. ;; v: relative velocity
  716. ;; x, y, z: coordinates of source [missing z's assumed 0.0]
  717. ;; 3d -> nil
  718. ;; '((x0 y0 v0) (x1 y1 v1)...(xn yn vn))
  719. ;; '((x0 y0) (x1 y1)...(xn yn))
  720. ;; v: relative velocity
  721. ;; x, y, z: coordinates of source [missing z's assumed 0.0]
  722. (let ((v ())
  723. (x ())
  724. (y ())
  725. (z ()))
  726. (for-each
  727. (lambda (p)
  728. (set! x (cons (car p) x))
  729. (set! y (cons (cadr p) y))
  730. (set! z (cons (if 3d (or (third p) 0.0) 0.0) z))
  731. (set! v (cons ((if 3d fourth third) p) v)))
  732. points)
  733. (list (reverse x) (reverse y) (reverse z) (reverse v)))
  734. ;; decode a plain list
  735. (let ((px ())
  736. (py ())
  737. (len (length points)))
  738. (if 3d
  739. ;; it's a three dimensional list
  740. ;; '(x0 y0 z0 x1 y1 z1 ... xn yn zn)
  741. ;; x, y, z: coordinates of source
  742. (do ((pz ())
  743. (i 0 (+ i 3)))
  744. ((>= i len)
  745. (list (reverse px) (reverse py) (reverse pz) (make-list (length px) #f)))
  746. (set! px (cons (points i) px))
  747. (set! py (cons (points (+ i 1)) py))
  748. (set! pz (cons (points (+ i 2)) pz)))
  749. ;; it's a two dimensional list
  750. ;; '(x0 y0 x1 y1 ... xn yn)
  751. ;; x, y, z: coordinates of source [missing z's assumed 0.0]
  752. (do ((i 0 (+ i 2)))
  753. ((>= i len)
  754. (list (reverse px) (reverse py) (make-list (length px) 0.0) (make-list (length px) #f)))
  755. (set! px (cons (points i) px))
  756. (set! py (cons (points (+ i 1)) py)))))))))
  757. ;;; Parse a set of 2d or 3d polar points into the separate coordinates
  758. (define parse-polar-coordinates
  759. (let ((documentation "(parse-polar-coordinates points 3d) parses a polar path"))
  760. (lambda (points 3d)
  761. (let ((x ())
  762. (y ()))
  763. (if (pair? (car points))
  764. ;; decode a list of lists of d:a:e:v into x:y:z:v components
  765. ;; 3d --> t [default]
  766. ;; '((d0 a0 e0 v0) (d1 a1 e1 v1)...(dn an en vn))
  767. ;; '((d0 a0 e0) (d1 a1 e1)...(dn an en))
  768. ;; '((d0 a0) (d1 a1)...(dn an))
  769. ;; 3d --> nil
  770. ;; '((d0 a0 v0) (d1 a1 v1)...(dn an vn))
  771. ;; '((d0 a0) (d1 a1)...(dn an))
  772. ;; v: velocity
  773. ;; d: distance
  774. ;; a: azimut angle
  775. ;; e: elevarion angle [missing elevations assumed 0.0]
  776. (let ((z ())
  777. (v ()))
  778. (for-each
  779. (lambda (p)
  780. (let ((d (car p))
  781. (evec (let ((e (if (and 3d (pair? (cddr p))) (caddr p) 0.0)))
  782. (cis (/ (* e 2 pi) dlocsig-one-turn)))))
  783. (let ((dxy (* d (real-part evec)))
  784. (avec (let ((a (cadr p)))
  785. (cis (/ (* a 2 pi) dlocsig-one-turn)))))
  786. (set! x (cons (* dxy (imag-part avec)) x))
  787. (set! y (cons (* dxy (real-part avec)) y)))
  788. (set! z (cons (* d (imag-part evec)) z))
  789. (set! v (cons ((if 3d fourth third) p) v))))
  790. points)
  791. (list (reverse x) (reverse y) (reverse z) (reverse v)))
  792. ;; decode a list of d:a:e components
  793. (let ((len (length points)))
  794. (if 3d
  795. ;; decode a three dimensional list
  796. ;; '(d0 a0 e0 d1 a1 e1 ... dn an en)
  797. ;; d: distance
  798. ;; a: azimut angle
  799. ;; e: elevarion angle [missing elevations assumed 0.0]
  800. (do ((z ())
  801. (i 0 (+ i 3)))
  802. ((>= i len)
  803. (list (reverse x) (reverse y) (reverse z) (make-list (length x) #f)))
  804. (let* ((d (points i))
  805. (evec (let ((e (points (+ i 2))))
  806. (cis (/ (* e 2 pi) dlocsig-one-turn))))
  807. (dxy (* d (real-part evec)))
  808. (avec (let ((a (points (+ i 1))))
  809. (cis (/ (* a 2 pi) dlocsig-one-turn)))))
  810. (set! x (cons (* dxy (imag-part avec)) x))
  811. (set! y (cons (* dxy (real-part avec)) y))
  812. (set! z (cons (* d (imag-part evec)) z))))
  813. ;; decode a two dimensional list
  814. ;; '(d0 a0 d1 a1 ... dn an)
  815. ;; d: distance
  816. ;; a: azimut angle
  817. ;; e: elevarion angle [missing elevations assumed 0.0]
  818. (do ((i 0 (+ i 2)))
  819. ((>= i len)
  820. (list (reverse x) (reverse y) (make-list (length x) 0.0) (make-list (length x) #f)))
  821. (let ((d (points i))
  822. (avec (let ((a (points (+ i 1))))
  823. (cis (/ (* a 2 pi) dlocsig-one-turn)))))
  824. (set! x (cons (* d (imag-part avec)) x))
  825. (set! y (cons (* d (real-part avec)) y)))))))))))
  826. (define (xparse-path xpath)
  827. (let ((polar (bezier-polar xpath))
  828. (points (bezier-path xpath))
  829. (3d (bezier-3d xpath)))
  830. (let ((vals ((if polar parse-polar-coordinates parse-cartesian-coordinates) points 3d)))
  831. (set! (bezier-x xpath) (car vals))
  832. (set! (bezier-y xpath) (cadr vals))
  833. (set! (bezier-z xpath) (caddr vals))
  834. (set! (bezier-v xpath) (cadddr vals))))
  835. (for-each
  836. (lambda (v)
  837. (if (and (real? v)
  838. (< v 0))
  839. (error 'mus-error "velocities for path ~A must be all positive~%" (bezier-path xpath))))
  840. (bezier-v xpath))
  841. (reset-fit xpath))
  842. ;;;
  843. ;;; Bezier curve fitting auxiliary functions
  844. ;;;
  845. ;;; Pythagoras
  846. (define distance
  847. (let ((documentation "(distance x y z) returns the euclidean distance of (x y z) from the origin"))
  848. (lambda (x y z)
  849. (sqrt (+ (* x x) (* y y) (* z z))))))
  850. ;;; Nearest point in a line
  851. (define (nearest-point x0 y0 z0 x1 y1 z1 px py pz)
  852. (define (vcos a0 b0 c0 a1 b1 c1)
  853. (/ (+ (* a0 a1) (* b0 b1) (* c0 c1))
  854. (* (distance a0 b0 c0) (distance a1 b1 c1))))
  855. (define (same a0 b0 c0 a1 b1 c1)
  856. (and (= a0 a1) (= b0 b1) (= c0 c1)))
  857. (cond ((same x0 y0 z0 px py pz) (list x0 y0 z0))
  858. ((same x1 y1 z1 px py pz) (list x1 y1 z1))
  859. ((same x0 y0 z0 x1 y1 z1) (list x0 y0 z0))
  860. (else (let* ((xm0 (- x1 x0))
  861. (ym0 (- y1 y0))
  862. (zm0 (- z1 z0))
  863. (ratio (let ((p (let ((xm1 (- px x0))
  864. (ym1 (- py y0))
  865. (zm1 (- pz z0)))
  866. (* (distance xm1 ym1 zm1)
  867. (vcos xm0 ym0 zm0 xm1 ym1 zm1)))))
  868. (/ p (distance xm0 ym0 zm0)))))
  869. (list (+ x0 (* xm0 ratio))
  870. (+ y0 (* ym0 ratio))
  871. (+ z0 (* zm0 ratio)))))))
  872. ;;; Bezier curve fitting auxilliary functions
  873. (define path-ak-even #f)
  874. (define path-ak-odd #f)
  875. (define path-maxcoeff 8)
  876. (define (make-a-even)
  877. (let ((g (let ((path-gtab #f))
  878. (lambda (m)
  879. (if (not path-gtab)
  880. (begin
  881. (set! path-gtab (make-vector path-maxcoeff))
  882. (set! (path-gtab 0) 1)
  883. (set! (path-gtab 1) -4)
  884. (do ((i 2 (+ i 1)))
  885. ((= i path-maxcoeff))
  886. (set! (path-gtab i) (- (* -4 (path-gtab (- i 1)))
  887. (path-gtab (- i 2)))))))
  888. (path-gtab m)))))
  889. (set! path-ak-even (make-vector (- path-maxcoeff 1)))
  890. (do ((m 1 (+ 1 m)))
  891. ((= m path-maxcoeff))
  892. (set! (path-ak-even (- m 1)) (make-vector m))
  893. (do ((k 1 (+ k 1)))
  894. ((> k m))
  895. (set! ((path-ak-even (- m 1)) (- k 1)) (* 1.0 (/ (- (g (- m k))) (g m))))))))
  896. (define (make-a-odd)
  897. (let ((f (let ((path-ftab #f))
  898. (lambda (m)
  899. (if (not path-ftab)
  900. (begin
  901. (set! path-ftab (make-vector path-maxcoeff))
  902. (set! (path-ftab 0) 1)
  903. (set! (path-ftab 1) -3)
  904. (do ((i 2 (+ i 1)))
  905. ((= i path-maxcoeff))
  906. (set! (path-ftab i) (- (* -4 (path-ftab (- i 1)))
  907. (path-ftab (- i 2)))))))
  908. (path-ftab m)))))
  909. (set! path-ak-odd (make-vector (- path-maxcoeff 1)))
  910. (do ((m 1 (+ 1 m)))
  911. ((= m path-maxcoeff))
  912. (set! (path-ak-odd (- m 1)) (make-vector m))
  913. (do ((k 1 (+ k 1)))
  914. ((> k m))
  915. (set! ((path-ak-odd (- m 1)) (- k 1)) (* 1.0 (/ (- (f (- m k))) (f m))))))))
  916. ;;; Calculate bezier difference vectors for the given path
  917. ;;; (path-x (make-path '((-10 10)(0 5)(10 10))))
  918. (define (fit path)
  919. (let ((n (- (length (bezier-x path )) 1)))
  920. (cond ((not (eq? (car path) 'open-bezier-path))
  921. (let ((m (/ (- n (if (odd? n) 3 4)) 2))
  922. ;; data points P(i)
  923. (p (vector (apply vector (bezier-x path))
  924. (apply vector (bezier-y path))
  925. (apply vector (bezier-z path))))
  926. ;; control points D(i)
  927. (d (let ((maker (lambda () (make-vector n 0.0))))
  928. (vector (maker) (maker) (maker)))))
  929. (define (a-1 k n)
  930. (if (odd? (min (+ (* path-maxcoeff 2) 1) n))
  931. (begin
  932. (if (not path-ak-odd) (make-a-odd))
  933. ((path-ak-odd (/ (- n 3) 2)) (- k 1)))
  934. (begin
  935. (if (not path-ak-even) (make-a-even))
  936. ((path-ak-even (/ (- n 4) 2)) (- k 1)))))
  937. (define (xvector-ref z j i)
  938. (z j (if (> i (- n 1))
  939. (- i n)
  940. (if (< i 0)
  941. (+ i n) i))))
  942. (do ((i 0 (+ i 1)))
  943. ((= i n))
  944. (do ((k 1 (+ k 1)))
  945. ((> k m))
  946. (do ((a 0 (+ 1 a)))
  947. ((> a 2))
  948. (set! (d a i)
  949. (+ (d a i)
  950. (* (a-1 k n)
  951. (- (xvector-ref p a (+ i k))
  952. (xvector-ref p a (- i k)))))))))
  953. (if (bezier-curvature path)
  954. (do ((i 0 (+ i 1)))
  955. ((= i n))
  956. (set! (d 0 i) (* (d 0 i) (bezier-curvature path)))
  957. (set! (d 1 i) (* (d 1 i) (bezier-curvature path)))
  958. (set! (d 2 i) (* (d 2 i) (bezier-curvature path)))))
  959. (list (- n 1) p d)))
  960. (else
  961. (let ((m (- n 1))
  962. ;; data points P(i)
  963. (p (vector (apply vector (bezier-x path))
  964. (apply vector (bezier-y path))
  965. (apply vector (bezier-z path))))
  966. ;; control points D(i)
  967. (d (vector (make-vector (+ n 1) 0.0)
  968. (make-vector (+ n 1) 0.0)
  969. (make-vector (+ n 1) 0.0))))
  970. (define (ac k n)
  971. (let ((un (min n path-maxcoeff)))
  972. (if (not path-ak-even) (make-a-even))
  973. ((path-ak-even (- un 2)) (- k 1))))
  974. (define (ref z j i)
  975. (cond ((> i n) (z j (- i n)))
  976. ((< i 0) (z j (+ i n)))
  977. ((= i n) (- (z j n) (d j n)))
  978. ((= i 0) (+ (z j 0) (d j 0)))
  979. (else (z j i))))
  980. ;; forced initial direction
  981. (if (initial-direction path)
  982. (begin
  983. (set! (d 0 0) (car (initial-direction path)))
  984. (set! (d 1 0) (cadr (initial-direction path)))
  985. (set! (d 2 0) (third (initial-direction path))))
  986. (begin
  987. (set! (d 0 0) 0.0)
  988. (set! (d 1 0) 0.0)
  989. (set! (d 2 0) 0.0)))
  990. ;; forced final direction
  991. (if (final-direction path)
  992. (begin
  993. (set! (d 0 n) (car (final-direction path)))
  994. (set! (d 1 n) (cadr (final-direction path)))
  995. (set! (d 2 n) (caddr (final-direction path))))
  996. (begin
  997. (set! (d 0 n) 0.0)
  998. (set! (d 1 n) 0.0)
  999. (set! (d 2 n) 0.0)))
  1000. ;; calculate fit
  1001. (do ((i 1 (+ i 1)))
  1002. ((= i n))
  1003. (do ((k 1 (+ k 1)))
  1004. ((> k (min m (- path-maxcoeff 1))))
  1005. (let ((d0 (d 0 i))
  1006. (d1 (d 1 i))
  1007. (d2 (d 2 i)))
  1008. (set! (d 0 i) (+ d0 (* (ac k n)
  1009. (- (ref p 0 (+ i k))
  1010. (ref p 0 (- i k))))))
  1011. (set! (d 1 i) (+ d1 (* (ac k n)
  1012. (- (ref p 1 (+ i k))
  1013. (ref p 1 (- i k))))))
  1014. (set! (d 2 i) (+ d2 (* (ac k n)
  1015. (- (ref p 2 (+ i k))
  1016. (ref p 2 (- i k)))))))))
  1017. (list n p d))))))
  1018. ;;; Calculate bezier control points for the given open path
  1019. (define (not-fitted path)
  1020. (null? (bezier-bx path)))
  1021. (define (reset-fit path)
  1022. (set! (bezier-bx path) ())
  1023. (set! (bezier-by path) ())
  1024. (set! (bezier-bz path) ())
  1025. (reset-rendering path))
  1026. (define (fit-path path)
  1027. (cond ((eq? (car path) 'open-bezier-path)
  1028. (if (not-parsed path)
  1029. (xparse-path path))
  1030. (let ((points (length (bezier-x path))))
  1031. (cond ((> points 2)
  1032. (let ((vals (fit path)))
  1033. (let ((n (car vals))
  1034. (p (cadr vals))
  1035. (d (caddr vals)))
  1036. (let ((c (bezier-curvature path))
  1037. (cs (make-vector n)))
  1038. ;; setup the curvatures array
  1039. (cond ((memq c '(#f ())) ; no curvature specified, default is 1.0
  1040. (do ((i 0 (+ i 1)))
  1041. ((= i n))
  1042. (set! (cs i) (list 1.0 1.0))))
  1043. ((number? c) ; same curvature for all segments
  1044. (do ((i 0 (+ i 1)))
  1045. ((= i n))
  1046. (set! (cs i) (list c c))))
  1047. ((and (pair? c) (= n (length c))) ; list of curvatures
  1048. (let ((i 0))
  1049. (for-each
  1050. (lambda (ci)
  1051. (set! (cs i) (if (pair? ci)
  1052. (if (= (length ci) 2)
  1053. ci
  1054. (error 'mus-error "curvature sublist must have two elements ~A~%" ci))
  1055. (list ci ci)))
  1056. (set! i (+ i 1)))
  1057. c)))
  1058. (else (error 'mus-error "bad curvature argument ~A to path, need ~A elements~%" c n)))
  1059. ;; calculate control points
  1060. (do ((xc ())
  1061. (yc ())
  1062. (zc ())
  1063. (i 0 (+ i 1)))
  1064. ((= i n)
  1065. (set! (bezier-bx path) (reverse xc))
  1066. (set! (bezier-by path) (reverse yc))
  1067. (set! (bezier-bz path) (reverse zc)))
  1068. (set! xc (cons (list (p 0 i)
  1069. (+ (p 0 i) (* (d 0 i) (car (cs i))))
  1070. (- (p 0 (+ i 1)) (* (d 0 (+ i 1)) (cadr (cs i))))
  1071. (p 0 (+ i 1))) xc))
  1072. (set! yc (cons (list (p 1 i)
  1073. (+ (p 1 i) (* (d 1 i) (car (cs i))))
  1074. (- (p 1 (+ i 1)) (* (d 1 (+ i 1)) (cadr (cs i))))
  1075. (p 1 (+ i 1))) yc))
  1076. (set! zc (cons (list (p 2 i)
  1077. (+ (p 2 i) (* (d 2 i) (car (cs i))))
  1078. (- (p 2 (+ i 1)) (* (d 2 (+ i 1)) (cadr (cs i))))
  1079. (p 2 (+ i 1))) zc)))))))
  1080. ((= points 2)
  1081. ;; just a line, stays a line
  1082. (let ((x1 (car (bezier-x path)))
  1083. (x2 (cadr (bezier-x path)))
  1084. (y1 (car (bezier-y path)))
  1085. (y2 (cadr (bezier-y path)))
  1086. (z1 (car (bezier-z path)))
  1087. (z2 (cadr (bezier-z path))))
  1088. (set! (bezier-bx path) (list (list x1 x1 x2 x2)))
  1089. (set! (bezier-by path) (list (list y1 y1 y2 y2)))
  1090. (set! (bezier-bz path) (list (list z1 z1 z2 z2)))))
  1091. ((= points 1)
  1092. ;; just one point, bezier won't do much here
  1093. (set! (bezier-bx path) ())
  1094. (set! (bezier-by path) ())
  1095. (set! (bezier-bz path) ())))
  1096. (reset-rendering path)))
  1097. (else
  1098. (if (not-parsed path)
  1099. (xparse-path path))
  1100. (if (> (length (bezier-x path)) 4)
  1101. (let ((vals (fit path)))
  1102. (do ((n (car vals))
  1103. (p (cadr vals))
  1104. (d (caddr vals))
  1105. ;; enough points, fit path
  1106. (xc ())
  1107. (yc ())
  1108. (zc ())
  1109. (i 0 (+ i 1)))
  1110. ((= i n)
  1111. (set! (bezier-bx path) (append (reverse xc) (list (list (p 0 n)
  1112. (+ (p 0 n) (d 0 n))
  1113. (- (p 0 0) (d 0 0))
  1114. (p 0 0)))))
  1115. (set! (bezier-by path) (append (reverse yc) (list (list (p 1 n)
  1116. (+ (p 1 n) (d 1 n))
  1117. (- (p 1 0) (d 1 0))
  1118. (p 1 0)))))
  1119. (set! (bezier-bz path) (append (reverse zc) (list (list (p 2 n)
  1120. (+ (p 2 n) (d 2 n))
  1121. (- (p 2 0) (d 2 0))
  1122. (p 2 0))))))
  1123. (set! xc (cons (list (p 0 i)
  1124. (+ (p 0 i) (d 0 i))
  1125. (- (p 0 (+ i 1)) (d 0 (+ i 1)))
  1126. (p 0 (+ i 1))) xc))
  1127. (set! yc (cons (list (p 1 i)
  1128. (+ (p 1 i) (d 1 i))
  1129. (- (p 1 (+ i 1)) (d 1 (+ i 1)))
  1130. (p 1 (+ i 1))) yc))
  1131. (set! zc (cons (list (p 2 i)
  1132. (+ (p 2 i) (d 2 i))
  1133. (- (p 2 (+ i 1)) (d 2 (+ i 1)))
  1134. (p 2 (+ i 1))) zc))))
  1135. ;; not enough points to fit a closed path
  1136. (do ((xc ())
  1137. (yc ())
  1138. (zc ())
  1139. (len (min (length (bezier-x path)) (length (bezier-y path)) (length (bezier-z path))))
  1140. (i 0 (+ i 1)))
  1141. ((>= i len)
  1142. (format *stderr* "[fit-path:closed-path] not enough points to do bezier fit (~A points)" len)
  1143. (set! (bezier-bx path) (reverse xc))
  1144. (set! (bezier-by path) (reverse yc))
  1145. (set! (bezier-bz path) (reverse zc)))
  1146. (let ((x1 ((bezier-x path) i))
  1147. (x2 ((bezier-x path) (+ i 1)))
  1148. (y1 ((bezier-y path) i))
  1149. (y2 ((bezier-y path) (+ i 1)))
  1150. (z1 ((bezier-z path) i))
  1151. (z2 ((bezier-z path) (+ i 1))))
  1152. (set! xc (cons (list x1 x1 x2 x2) xc))
  1153. (set! yc (cons (list y1 y1 y2 y2) yc))
  1154. (set! zc (cons (list z1 z1 z2 z2) zc)))))
  1155. (reset-rendering path))))
  1156. ;;;;;;;;;;;;;;;;;
  1157. ;;; Literal paths
  1158. ;;;;;;;;;;;;;;;;;
  1159. (define literal-points (dilambda (lambda (p) (p 10)) (lambda (p val) (set! (p 10) val))))
  1160. (define literal-3d (dilambda (lambda (p) (p 11)) (lambda (p val) (set! (p 11) val))))
  1161. (define literal-polar (dilambda (lambda (p) (p 12)) (lambda (p val) (set! (p 12) val))))
  1162. ;;; Generic literal path creation function
  1163. (define* (make-literal-path (points ()) (3d path-3d) polar)
  1164. (list 'literal-path () () () () () () () () () points 3d polar))
  1165. ;;; Specific polar literal path creation function
  1166. (define* (make-literal-polar-path (points ()) (3d path-3d))
  1167. (make-literal-path points 3d #t))
  1168. ;;;;;;;;;;;
  1169. ;;; Spirals
  1170. ;;;;;;;;;;;
  1171. (define spiral-start-angle (dilambda (lambda (p) (p 13)) (lambda (p val) (set! (p 13) val))))
  1172. (define spiral-total-angle (dilambda (lambda (p) (p 14)) (lambda (p val) (set! (p 14) val))))
  1173. (define spiral-step-angle (dilambda (lambda (p) (p 15)) (lambda (p val) (set! (p 15) val))))
  1174. (define spiral-turns (dilambda (lambda (p) (p 16)) (lambda (p val) (set! (p 16) val))))
  1175. (define spiral-distance (dilambda (lambda (p) (p 17)) (lambda (p val) (set! (p 17) val))))
  1176. (define spiral-height (dilambda (lambda (p) (p 18)) (lambda (p val) (set! (p 18) val))))
  1177. (define spiral-velocity (dilambda (lambda (p) (p 19)) (lambda (p val) (set! (p 19) val))))
  1178. (define* (make-spiral-path (start-angle 0.0)
  1179. total-angle
  1180. step-angle
  1181. (turns ())
  1182. (distance '(0 10 1 10))
  1183. (height '(0 0 1 0))
  1184. (velocity '(0 1 1 1)))
  1185. (if (and total-angle (pair? turns))
  1186. (error 'mus-error "can't specify total-angle [~A] and turns [~A] at the same time for the spiral path~%" total-angle turns))
  1187. (list 'spiral-path () () () () () () () () () () path-3d #f
  1188. start-angle total-angle
  1189. (or step-angle (/ dlocsig-one-turn 100))
  1190. turns distance height velocity))
  1191. ;;; Transform a Bezier control point fit to a linear segment approximation
  1192. (define (bezier-render path)
  1193. (if (not-fitted path)
  1194. (fit-path path))
  1195. (let ((xrx ()) (xry ()) (xrz ()) (xrv ()))
  1196. (define (berny xl yl zl xh yh zh ul u uh c err)
  1197. ;; Create a linear segment rendering of a bezier segment
  1198. (define (bezier-point u c)
  1199. ;; Evaluate a point at parameter u in bezier segment
  1200. (let ((u1 (- 1 u))
  1201. (cr (vector (make-vector 3 0.0) (make-vector 3 0.0) (make-vector 3 0.0))))
  1202. (do ((j 0 (+ j 1)))
  1203. ((= j 3))
  1204. (set! (cr 0 j) (+ (* u1 (c 0 j)) (* u (c 0 (+ j 1)))))
  1205. (set! (cr 1 j) (+ (* u1 (c 1 j)) (* u (c 1 (+ j 1)))))
  1206. (set! (cr 2 j) (+ (* u1 (c 2 j)) (* u (c 2 (+ j 1))))))
  1207. (do ((i 1 (- i 1)))
  1208. ((< i 0))
  1209. (do ((j 0 (+ j 1)))
  1210. ((> j i))
  1211. (set! (cr 0 j) (+ (* u1 (cr 0 j)) (* u (cr 0 (+ j 1)))))
  1212. (set! (cr 1 j) (+ (* u1 (cr 1 j)) (* u (cr 1 (+ j 1)))))
  1213. (set! (cr 2 j) (+ (* u1 (cr 2 j)) (* u (cr 2 (+ j 1)))))))
  1214. (list (cr 0 0)
  1215. (cr 1 0)
  1216. (cr 2 0))))
  1217. (let ((vals (bezier-point u c)))
  1218. (let ((x (car vals))
  1219. (y (cadr vals))
  1220. (z (caddr vals)))
  1221. (let ((val1 (nearest-point xl yl zl xh yh zh x y z)))
  1222. (let ((xn (car val1))
  1223. (yn (cadr val1))
  1224. (zn (caddr val1)))
  1225. (if (<= (distance (- xn x) (- yn y) (- zn z)) err)
  1226. (list () () ())
  1227. (let ((val2 (berny xl yl zl x y z ul (/ (+ ul u) 2) u c err))
  1228. (val3 (berny x y z xh yh zh u (/ (+ u uh) 2) uh c err)))
  1229. (let ((xi (car val2))
  1230. (yi (cadr val2))
  1231. (zi (caddr val2))
  1232. (xj (car val3))
  1233. (yj (cadr val3))
  1234. (zj (caddr val3)))
  1235. (list (append xi (cons x xj))
  1236. (append yi (cons y yj))
  1237. (append zi (cons z zj)))))))))))
  1238. ;; Create linear segment approximations of the bezier segments
  1239. ;; make sure there are initial and final velocity values
  1240. (if (not (pair? (bezier-v path)))
  1241. (set! (bezier-v path) (list 1 1))
  1242. (if (not (car (bezier-v path)))
  1243. (begin
  1244. (set! ((bezier-v path) 0) 1)
  1245. (set! ((bezier-v path) (- (length (bezier-v path)) 1)) 1))))
  1246. ;; only one point means no movement, static source
  1247. (if (= (length (bezier-x path)) 1)
  1248. (begin
  1249. (set! (path-rx path) (bezier-x path))
  1250. (set! (path-ry path) (bezier-y path))
  1251. (set! (path-rz path) (bezier-z path))
  1252. (set! (path-rt path) (list 0.0))
  1253. (reset-transformation path)) ; after?
  1254. (begin
  1255. (let ((len (length (bezier-bx path))))
  1256. ;(path-x (make-path '((-10 10)(0 5)(10 10))))
  1257. ;; render the path only if it has at least two points
  1258. (do ((i 0 (+ i 1)))
  1259. ((= i len))
  1260. (let ((x-bz ((bezier-bx path) i))
  1261. (y-bz ((bezier-by path) i))
  1262. (z-bz ((bezier-bz path) i)))
  1263. (let ((vi-bz ((bezier-v path) i))
  1264. (vf-bz ((bezier-v path) (+ i 1)))
  1265. (xi-bz (car x-bz))
  1266. (xf-bz (x-bz (- (length x-bz) 1)))
  1267. (yi-bz (car y-bz))
  1268. (yf-bz (y-bz (- (length y-bz) 1)))
  1269. (zi-bz (car z-bz))
  1270. (zf-bz (z-bz (- (length z-bz) 1))))
  1271. (let ((vals (berny xi-bz yi-bz zi-bz xf-bz yf-bz zf-bz 0.0 0.5 1.0
  1272. (vector (apply vector x-bz)
  1273. (apply vector y-bz)
  1274. (apply vector z-bz))
  1275. (bezier-error path))))
  1276. ;; approximate the bezier curve with linear segments
  1277. (set! xry (append xry (cons yi-bz (cadr vals))))
  1278. (set! xrz (append xrz (cons zi-bz (caddr vals))))
  1279. (let ((xs (car vals)))
  1280. (set! xrx (append xrx (cons xi-bz xs)))
  1281. ;; accumulate intermediate unknown velocities as nils
  1282. (set! xrv (append xrv (cons vi-bz (make-list (length xs) #f))))
  1283. (if (= i (- len 1))
  1284. (begin
  1285. ;; add the last point
  1286. (set! xrx (append xrx (list xf-bz)))
  1287. (set! xry (append xry (list yf-bz)))
  1288. (set! xrz (append xrz (list zf-bz)))
  1289. (set! xrv (append xrv (list vf-bz)))))))))))
  1290. ;; calculate times for each velocity segment
  1291. (let ((ti 0)
  1292. (times (list 0)))
  1293. (let ((len (- (length xrx) 1))
  1294. (xseg (list (xrx 0)))
  1295. (yseg (list (xry 0)))
  1296. (zseg (list (xrz 0)))
  1297. (vseg (list (xrv 0)))
  1298. (vi (xrv 0)))
  1299. (do ((i 0 (+ i 1)))
  1300. ((= i len))
  1301. (let ((x (xrx (+ i 1)))
  1302. (y (xry (+ i 1)))
  1303. (z (xrz (+ i 1)))
  1304. (v (xrv (+ i 1))))
  1305. (set! xseg (append xseg (list x)))
  1306. (set! yseg (append yseg (list y)))
  1307. (set! zseg (append zseg (list z)))
  1308. (set! vseg (append vseg (list v)))
  1309. (when v
  1310. (let ((dseg (list))
  1311. (sum 0.0)
  1312. (len (- (length xseg) 1)))
  1313. (do ((i 0 (+ i 1)))
  1314. ((= i len))
  1315. (let ((xsi (xseg i))
  1316. (ysi (yseg i))
  1317. (zsi (zseg i))
  1318. (xsf (xseg (+ i 1)))
  1319. (ysf (yseg (+ i 1)))
  1320. (zsf (zseg (+ i 1))))
  1321. (set! sum (+ sum (distance (- xsf xsi) (- ysf ysi) (- zsf zsi))))
  1322. (set! dseg (cons sum dseg))))
  1323. (let ((df (car dseg)))
  1324. (set! dseg (reverse dseg))
  1325. (let ((tseg ()))
  1326. (let ((a (/ (* (- v vi) (+ v vi)) df 4)))
  1327. (if (= vi 0.0) (set! vi 1))
  1328. (for-each
  1329. (lambda (d)
  1330. (let ((seg (+ ti (if (= v vi)
  1331. (/ d vi)
  1332. (/ (- (sqrt (+ (* vi vi) (* 4 a d))) vi) (* 2 a))))))
  1333. (set! tseg (cons seg tseg))))
  1334. dseg))
  1335. (set! ti (car tseg))
  1336. (set! tseg (reverse tseg))
  1337. (set! times (append times tseg))
  1338. (set! xseg (list x))
  1339. (set! yseg (list y))
  1340. (set! zseg (list z))
  1341. (set! vseg (list v))
  1342. (set! vi v))))))))
  1343. (set! (path-rx path) xrx)
  1344. (set! (path-ry path) xry)
  1345. (set! (path-rz path) xrz)
  1346. (set! (path-rt path)
  1347. (let ((tf (times (- (length times) 1)))
  1348. (val ()))
  1349. (for-each
  1350. (lambda (ti)
  1351. (set! val (cons (/ ti tf) val)))
  1352. times)
  1353. (reverse val)))
  1354. (reset-transformation path))))))
  1355. ;; (set! p (make-path '((-10 10 0 0) (0 5 0 1) (10 10 0 0)) :error 0.01))
  1356. ;; (set! p (make-path '((-10 10 0 1) (-7 7 0 0.9) (0 5 0 0) (7 7 0 0.2) (10 10 0 1)) :error 0.001))
  1357. ;; (with-sound(:channels 4 :play #f) (sinewave 0 2 880 0.5 :path p))
  1358. (define (literal-render path)
  1359. ;; Render a user-defined literal path from the data points
  1360. ;; decode the points into coordinates
  1361. (let ((points (literal-points path))
  1362. (3d (literal-3d path))
  1363. (polar (literal-polar path)))
  1364. (let ((vals ((if polar parse-polar-coordinates parse-cartesian-coordinates) points 3d)))
  1365. (set! (path-rx path) (car vals))
  1366. (set! (path-ry path) (cadr vals))
  1367. (set! (path-rz path) (caddr vals))
  1368. (set! (path-rv path) (cadddr vals)))
  1369. ;; make sure there are initial and final velocity values
  1370. (if (not (car (path-rv path)))
  1371. (begin
  1372. (set! ((path-rv path) 0) 1)
  1373. (set! ((path-rv path) (- (length (path-rv path)) 1)) 1)))
  1374. ;; only one point means no movement, static source
  1375. (if (= (length (path-rx path)) 1)
  1376. (begin
  1377. (set! (path-rt path) (list 0.0))
  1378. (reset-transformation path))
  1379. (let ((rx (path-rx path))
  1380. (ry (path-ry path))
  1381. (rz (path-rz path))
  1382. (rv (path-rv path)))
  1383. (let ((xseg (list (car rx)))
  1384. (yseg (list (car ry)))
  1385. (zseg (list (car rz)))
  1386. (vseg (list (car rv)))
  1387. (vi (car rv))
  1388. (len (length rx))
  1389. (ti 0))
  1390. (let ((times (list ti)))
  1391. (do ((i 1 (+ i 1)))
  1392. ((= i len))
  1393. (let ((x (rx i))
  1394. (y (ry i))
  1395. (z (rz i))
  1396. (v (rv i)))
  1397. (set! xseg (append xseg (list x)))
  1398. (set! yseg (append yseg (list y)))
  1399. (set! zseg (append zseg (list z)))
  1400. (set! vseg (append vseg (list v)))
  1401. (when (number? v)
  1402. (let ((sofar 0.0)
  1403. (dseg ())
  1404. (len (- (length xseg) 1)))
  1405. (do ((i 0 (+ i 1)))
  1406. ((= i len))
  1407. (let ((xsi (xseg i))
  1408. (ysi (yseg i))
  1409. (zsi (zseg i))
  1410. (xsf (xseg (+ i 1)))
  1411. (ysf (yseg (+ i 1)))
  1412. (zsf (zseg (+ i 1))))
  1413. (set! sofar (+ sofar (distance (- xsf xsi) (- ysf ysi) (- zsf zsi))))
  1414. (set! dseg (cons sofar dseg))))
  1415. (let ((df (car dseg)))
  1416. (set! dseg (reverse dseg))
  1417. (let ((tseg ()))
  1418. (let ((a (/ (* (- v vi) (+ v vi)) df 4)))
  1419. (for-each
  1420. (lambda (d)
  1421. (let ((seg (+ ti (if (= v vi)
  1422. (/ d vi)
  1423. (/ (- (sqrt (+ (* vi vi) (* 4 a d))) vi) (* 2 a))))))
  1424. (set! tseg (cons seg tseg))))
  1425. dseg))
  1426. (set! ti (car tseg))
  1427. (set! tseg (reverse tseg))
  1428. (set! times (append times tseg))
  1429. (set! xseg (list x))
  1430. (set! yseg (list y))
  1431. (set! zseg (list z))
  1432. (set! vseg (list v))
  1433. (set! vi v)))))))
  1434. (set! (path-rt path) (let ((val ())
  1435. (tf (times (- (length times) 1))))
  1436. (for-each
  1437. (lambda (ti)
  1438. (set! val (cons (/ ti tf) val)))
  1439. times)
  1440. (reverse val)))
  1441. (reset-transformation path)))))))
  1442. (define (spiral-render path)
  1443. ;; Render a spiral path from the object data
  1444. (let* ((start (/ (* (spiral-start-angle path) 2 pi) dlocsig-one-turn))
  1445. (total (if (spiral-total-angle path)
  1446. (/ (* (spiral-total-angle path) 2 pi) dlocsig-one-turn)
  1447. (if (spiral-turns path)
  1448. (* (spiral-turns path) 2 pi)
  1449. (error 'mus-error "a spiral-path needs either a total-angle or turns, none specified~%"))))
  1450. (step (let ((steps (abs (/ (* total dlocsig-one-turn) (* (spiral-step-angle path) 2 pi)))))
  1451. (/ total (ceiling steps)
  1452. (if (< (spiral-step-angle path) 0) -1 1))))
  1453. (xdistance (x-norm (spiral-distance path) total))
  1454. (height (x-norm (spiral-height path) total)))
  1455. (let ((x ())
  1456. (y ())
  1457. (z ())
  1458. (len (+ 1 (round (abs (/ total step))))))
  1459. (do ((i 0 (+ i 1))
  1460. (angle start (+ angle step)))
  1461. ((>= i len))
  1462. (let ((xy (cis angle))
  1463. (d (envelope-interp angle xdistance)))
  1464. (set! x (cons (* d (imag-part xy)) x))
  1465. (set! y (cons (* d (real-part xy)) y))
  1466. (set! z (cons (envelope-interp angle height) z))))
  1467. (set! x (reverse x))
  1468. (set! y (reverse y))
  1469. (set! z (reverse z))
  1470. (let ((dp ())
  1471. (len (- (length x) 1))
  1472. (sofar 0.0))
  1473. (do ((i 0 (+ i 1)))
  1474. ((>= i len))
  1475. (let ((xi (x i))
  1476. (xf (x (+ i 1)))
  1477. (yi (y i))
  1478. (yf (y (+ i 1)))
  1479. (zi (z i))
  1480. (zf (z (+ i 1))))
  1481. (set! sofar (+ sofar (distance (- xf xi) (- yf yi) (- zf zi))))
  1482. (set! dp (cons sofar dp))))
  1483. (let ()
  1484. (set! dp (reverse dp))
  1485. (let ((tp ())
  1486. (td 0)
  1487. (len (- (length dp) 1)))
  1488. (do ((i 0 (+ i 1)))
  1489. ((>= i len))
  1490. (let* ((di (dp i))
  1491. (df (dp (+ i 1)))
  1492. (vp (x-norm (spiral-velocity path) df)))
  1493. (let ((vi (envelope-interp di vp))
  1494. (vf (envelope-interp df vp)))
  1495. (set! tp (cons td tp))
  1496. (set! td (+ td (/ (- df di) (+ vi vf) 2))))))
  1497. (let ((tf (car tp)))
  1498. (set! tp (reverse tp))
  1499. (set! (path-rx path) x)
  1500. (set! (path-ry path) y)
  1501. (set! (path-rz path) z)
  1502. (let ((val ()))
  1503. (for-each
  1504. (lambda (ti)
  1505. (set! val (cons (/ ti tf) val)))
  1506. tp)
  1507. (set! (path-rt path) (reverse val))))))))
  1508. (reset-transformation path)))
  1509. (define (render-path path)
  1510. ((case (car path)
  1511. ((bezier-path open-bezier-path) bezier-render)
  1512. ((literal-path) literal-render)
  1513. (else spiral-render))
  1514. path))
  1515. ;;;;;;;;;;;;;;;;;;;
  1516. ;;; Transformations
  1517. ;;;;;;;;;;;;;;;;;;;
  1518. ;;; Transform a rendered path using scaling, translation and rotation
  1519. ;;; Transform a path (scaling + translation + rotation)
  1520. (define* (transform-path path
  1521. scaling
  1522. translation
  1523. rotation
  1524. rotation-center
  1525. (rotation-axis '(0.0 0.0 1.0)))
  1526. ;; Derive a rotation matrix from an axis vector and an angle
  1527. (define (rotation-matrix x y z angle)
  1528. ;; translated from C routine by David Eberly
  1529. ;; (http://www.magic-software.com/)
  1530. (define (normalize a b c)
  1531. (let ((mag (distance a b c)))
  1532. (list (/ a mag) (/ b mag) (/ c mag))))
  1533. (let ((rotate (vector (vector 0.0 0.0 0.0) (vector 0.0 0.0 0.0) (vector 0.0 0.0 0.0)))
  1534. (I (vector (vector 1.0 0.0 0.0) (vector 0.0 1.0 0.0) (vector 0.0 0.0 1.0)))
  1535. (A (let ((vals (normalize x y z)))
  1536. (let ((dx (car vals))
  1537. (dy (cadr vals))
  1538. (dz (caddr vals)))
  1539. (vector (vector 0.0 dz (- dy)) (vector (- dz) 0.0 dx) (vector dy (- dx) 0.0)))))
  1540. (AA (vector (vector 0.0 0.0 0.0) (vector 0.0 0.0 0.0) (vector 0.0 0.0 0.0)))
  1541. (sn (sin (- angle)))
  1542. (omcs (- 1 (cos angle)))) ; (cos (- angle)) == (cos angle)
  1543. (do ((row 0 (+ 1 row)))
  1544. ((= row 3))
  1545. (do ((col 0 (+ 1 col)))
  1546. ((= col 3))
  1547. (set! (AA row col) 0.0)
  1548. (do ((mid 0 (+ 1 mid)))
  1549. ((= mid 3))
  1550. (set! (AA row col)
  1551. (+ (AA row col)
  1552. (* (A row mid)
  1553. (A mid col)))))))
  1554. ;; rotation matrix is I+sin(angle)*A+[1-cos(angle)]*A*A
  1555. (do ((row 0 (+ 1 row)))
  1556. ((= row 3))
  1557. (do ((col 0 (+ 1 col)))
  1558. ((= col 3))
  1559. (set! (rotate row col)
  1560. (+ (I row col)
  1561. (* sn (A row col))
  1562. (* omcs (AA row col))))))
  1563. rotate))
  1564. (if (not-rendered path)
  1565. (render-path path))
  1566. (if (or scaling translation rotation)
  1567. ;; there's at least one transformation to execute
  1568. (let* ((rotation (and (number? rotation)
  1569. (/ (* 2 pi rotation) dlocsig-one-turn)))
  1570. (matrix (and rotation (rotation-matrix (car rotation-axis)
  1571. (cadr rotation-axis)
  1572. (third rotation-axis)
  1573. rotation)))
  1574. (xc (path-x path))
  1575. (yc (path-y path))
  1576. (zc (path-z path)))
  1577. (if (and rotation-center (not (= (length rotation-center) 3)))
  1578. (error 'mus-error "rotation center has to have all three coordinates~%"))
  1579. (if (and rotation-axis (not (= (length rotation-axis) 3)))
  1580. (error 'mus-error "rotation axis has to have all three coordinates~%"))
  1581. (do ((xtr ())
  1582. (ytr ())
  1583. (ztr ())
  1584. (len (length xc))
  1585. (i 0 (+ i 1)))
  1586. ((= i len)
  1587. (set! (path-tx path) (reverse xtr))
  1588. (set! (path-ty path) (reverse ytr))
  1589. (set! (path-tz path) (reverse ztr)))
  1590. (let ((x (xc i))
  1591. (y (yc i))
  1592. (z (zc i)))
  1593. (let ((xw x)
  1594. (yw y)
  1595. (zw z))
  1596. (when rotation
  1597. ;; rotating around non-triple zero? translate first
  1598. (when rotation-center
  1599. (set! xw (- xw (car rotation-center)))
  1600. (set! yw (- yw (cadr rotation-center)))
  1601. (set! zw (- zw (third rotation-center))))
  1602. ;; rotation
  1603. (let ((xr (+ (* (matrix 0 0) xw)
  1604. (* (matrix 1 0) yw)
  1605. (* (matrix 2 0) zw)))
  1606. (yr (+ (* (matrix 0 1) xw)
  1607. (* (matrix 1 1) yw)
  1608. (* (matrix 2 1) zw)))
  1609. (zr (+ (* (matrix 0 2) xw)
  1610. (* (matrix 1 2) yw)
  1611. (* (matrix 2 2) zw))))
  1612. (set! xw xr)
  1613. (set! yw yr)
  1614. (set! zw zr))
  1615. ;; rotating around non-triple zero? untranslate
  1616. (when rotation-center
  1617. (set! xw (+ xw (car rotation-center)))
  1618. (set! yw (+ yw (cadr rotation-center)))
  1619. (set! zw (+ zw (third rotation-center)))))
  1620. ;; scaling
  1621. (when scaling
  1622. (set! xw (* xw (car scaling)))
  1623. (if (cadr scaling)
  1624. (set! yw (* yw (cadr scaling))))
  1625. (if (third scaling)
  1626. (set! zw (* zw (third scaling)))))
  1627. ;; translating
  1628. (when translation
  1629. (set! xw (+ xw (car translation)))
  1630. (if (cadr translation)
  1631. (set! yw (+ yw (cadr translation))))
  1632. (if (third translation)
  1633. (set! zw (+ zw (third translation)))))
  1634. ;; collect the points
  1635. (set! xtr (cons xw xtr))
  1636. (set! ytr (cons yw ytr))
  1637. (set! ztr (cons zw ztr))))))
  1638. (begin
  1639. ;; if there's no transformation just copy the rendered path
  1640. (set! (path-tt path) (copy (path-rt path)))
  1641. (set! (path-tx path) (copy (path-rx path)))
  1642. (set! (path-ty path) (copy (path-ry path)))
  1643. (set! (path-tz path) (copy (path-rz path)))))
  1644. path)
  1645. ;;; Scale a path
  1646. (define (scale-path path scaling)
  1647. (transform-path path :scaling scaling))
  1648. ;;; Translate a path
  1649. (define (translate-path path translation)
  1650. (transform-path path :translation translation))
  1651. ;;; Rotate a path
  1652. (define rotate-path
  1653. (let ((documentation "rotate-path is a dlocsig function that rotates a dlocsig path"))
  1654. (lambda* (path rotation rotation-center (rotation-axis '(0.0 0.0 1.0)))
  1655. (transform-path path
  1656. :rotation rotation
  1657. :rotation-center rotation-center
  1658. :rotation-axis rotation-axis))))
  1659. ;;; Mirror a path around an axis
  1660. (define* (mirror-path path (axis 'y) (around 0))
  1661. (if (not-transformed path)
  1662. (transform-path path))
  1663. (let ((val ()))
  1664. (if (eq? axis 'y)
  1665. (begin
  1666. (for-each
  1667. (lambda (x)
  1668. (set! val (cons (- around x) val)))
  1669. (path-tx path))
  1670. (set! (path-tx path) (reverse val)))
  1671. (begin
  1672. (for-each
  1673. (lambda (y)
  1674. (set! val (cons (- around y) val)))
  1675. (path-ty path))
  1676. (set! (path-ty path) (reverse val)))))
  1677. path)
  1678. ;;; Change the times of the rendered envelope so that the velocity is constant
  1679. (define constant-velocity
  1680. (let ((documentation "constant-velocity is a dlocsig function that changes the times of the rendered envelope so that the velocity is constant"))
  1681. (lambda (path)
  1682. (if (not (path-rx path))
  1683. (render-path path))
  1684. (reset-transformation path)
  1685. (let* ((xcoords (path-x path))
  1686. (ycoords (path-y path))
  1687. (zcoords (path-z path))
  1688. (tcoords (path-time path))
  1689. (total-distance
  1690. (do ((sum 0.0)
  1691. (len (length xcoords))
  1692. (i 0 (+ i 1)))
  1693. ((= i len) sum)
  1694. (let ((x1 (xcoords i))
  1695. (x2 (xcoords (+ i 1)))
  1696. (y1 (ycoords i))
  1697. (y2 (ycoords (+ i 1)))
  1698. (z1 (zcoords i))
  1699. (z2 (zcoords (+ i 1))))
  1700. (set! sum (+ sum (distance (- x2 x1) (- y2 y1) (- z2 z1)))))))
  1701. (start-time (car tcoords))
  1702. (velocity (/ total-distance (- (tcoords (- (length tcoords) 1)) start-time)))
  1703. (now ()))
  1704. (do ((dist 0.0)
  1705. (len (length xcoords))
  1706. (i 0 (+ i 1)))
  1707. ((= i len))
  1708. (let ((xp (xcoords i))
  1709. (x (xcoords (+ i 1)))
  1710. (yp (ycoords i))
  1711. (y (ycoords (+ i 1)))
  1712. (zp (zcoords i))
  1713. (z (zcoords (+ i 1))))
  1714. (set! dist (+ dist (distance (- x xp) (- y yp) (- z zp))))
  1715. (set! now (cons (/ dist velocity) now))))
  1716. (set! now (reverse now))
  1717. (set! (path-rt path) (cons start-time now))
  1718. (set! (path-tx path) (copy (path-rx path)))
  1719. (set! (path-ty path) (copy (path-ry path)))
  1720. (set! (path-tz path) (copy (path-rz path))))
  1721. path)))
  1722. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1723. ;;; Create a new dlocsig structure
  1724. (define* (make-dlocsig start-time
  1725. duration
  1726. (path dlocsig-path)
  1727. (scaler dlocsig-scaler)
  1728. (direct-power dlocsig-direct-power)
  1729. (inside-direct-power dlocsig-inside-direct-power)
  1730. (reverb-power dlocsig-reverb-power)
  1731. (inside-reverb-power dlocsig-inside-reverb-power)
  1732. (reverb-amount dlocsig-reverb-amount)
  1733. (initial-delay dlocsig-initial-delay)
  1734. (unity-gain-dist dlocsig-unity-gain-distance)
  1735. (inside-radius dlocsig-inside-radius)
  1736. (minimum-segment-length dlocsig-minimum-segment-length)
  1737. (render-using dlocsig-render-using)
  1738. (ambisonics-h-order dlocsig-ambisonics-h-order)
  1739. (ambisonics-v-order dlocsig-ambisonics-v-order)
  1740. out-channels
  1741. rev-channels)
  1742. (if (null? start-time)
  1743. (error 'mus-error "a start time is required in make-dlocsig~%"))
  1744. (if (null? duration)
  1745. (error 'mus-error "a duration has to be specified in make-dlocsig~%"))
  1746. ;; check to see if we have the right number of channels for b-format ambisonics
  1747. (if (= render-using ambisonics)
  1748. (begin
  1749. (if (or (> ambisonics-h-order 3)
  1750. (> ambisonics-v-order 3))
  1751. (error 'mus-error "ambisonics encoding is currently limited to third order components~%"))
  1752. (let ((channels (ambisonics-channels ambisonics-h-order ambisonics-v-order)))
  1753. (if (< (or out-channels (mus-channels *output*)) channels)
  1754. (error 'mus-error "ambisonics number of channels is wrong, dlocsig needs ~A output channels for h:~A, v:~A order (current number is ~A)~%"
  1755. channels ambisonics-h-order ambisonics-v-order (or out-channels (mus-channels *output*)))))))
  1756. (if (not out-channels)
  1757. (if *output*
  1758. (set! out-channels (channels *output*))
  1759. (begin
  1760. (format () "warning: no *output*? Will set out-channels to 2~%")
  1761. (set! out-channels 2))))
  1762. (if (not rev-channels)
  1763. (set! rev-channels (if *reverb* (channels *reverb*) 0)))
  1764. (let (;; speaker configuration for current number of channels
  1765. (speakers (and (not (= render-using ambisonics))
  1766. (get-speaker-configuration out-channels)))
  1767. ;; coordinates of rendered path
  1768. (xpoints (path-x path))
  1769. (ypoints (path-y path))
  1770. (zpoints (path-z path))
  1771. (tpoints (path-time path))
  1772. ;; array of gains -- envelopes
  1773. (channel-gains (make-vector out-channels ()))
  1774. (channel-rev-gains (make-vector out-channels ()))
  1775. ;; speaker output delays
  1776. (max-out-delay 0.0)
  1777. (out-delays (make-vector out-channels))
  1778. ;; speed of sound expressed in terms of path time coordinates
  1779. (dly ())
  1780. (doppler ())
  1781. (prev-time #f)
  1782. (prev-dist #f)
  1783. (first-dist #f)
  1784. (last-dist #f)
  1785. (min-dist #f)
  1786. (max-dist #f)
  1787. (delay-hack 1)
  1788. ;; channel offsets in output stream for ambisonics
  1789. ;; (depends on horizontal and vertical order, default is h=1,v=1)
  1790. (z-offset #f)
  1791. (r-offset #f)
  1792. (s-offset #f)
  1793. (t-offset #f)
  1794. (u-offset #f)
  1795. (v-offset #f)
  1796. (k-offset #f)
  1797. (l-offset #f)
  1798. (m-offset #f)
  1799. (n-offset #f)
  1800. (o-offset #f)
  1801. (p-offset #f)
  1802. (q-offset #f))
  1803. (when (= render-using ambisonics)
  1804. ;; calculate output channel offsets for ambisonics rendering
  1805. (let ((offset 3))
  1806. ;; the default is at least a horizontal order of 1
  1807. (if (>= ambisonics-v-order 1)
  1808. (begin
  1809. ;; add Z
  1810. (set! z-offset offset)
  1811. (set! offset (+ offset 1))))
  1812. (if (>= ambisonics-v-order 2)
  1813. (begin
  1814. ;; add R S T
  1815. (set! r-offset offset)
  1816. (set! s-offset (+ offset 1))
  1817. (set! t-offset (+ offset 2))
  1818. (set! offset (+ offset 3))))
  1819. (if (>= ambisonics-h-order 2)
  1820. (begin
  1821. ;; add U V
  1822. (set! u-offset offset)
  1823. (set! v-offset (+ offset 1))
  1824. (set! offset (+ offset 2))))
  1825. (if (>= ambisonics-v-order 3)
  1826. (begin
  1827. ;; add K L M N O
  1828. (set! k-offset offset)
  1829. (set! l-offset (+ offset 1))
  1830. (set! m-offset (+ offset 2))
  1831. (set! n-offset (+ offset 3))
  1832. (set! o-offset (+ offset 4))
  1833. (set! offset (+ offset 5))))
  1834. (if (>= ambisonics-h-order 3)
  1835. (begin
  1836. ;; add P Q
  1837. (set! p-offset offset)
  1838. (set! q-offset (+ offset 1)))
  1839. (set! offset (+ offset 2)))))
  1840. (define (dist->samples d) (round (* d (/ *clm-srate* dlocsig-speed-of-sound))))
  1841. ;; (define (dist->seconds d) (/ d dlocsig-speed-of-sound))
  1842. (define (time->samples time) (round (* time *clm-srate*)))
  1843. ;; calculate speaker gains for group
  1844. (define (find-gains x y z group)
  1845. (let ((zero-coord 1.0e-10)
  1846. (zero-gain 1.0e-10)
  1847. (size (group-size group))
  1848. (mat (group-matrix group))) ; returns float-vector
  1849. (if (and (< (abs x) zero-coord)
  1850. (< (abs y) zero-coord)
  1851. (< (abs z) zero-coord))
  1852. (list #t (list 1.0 1.0 1.0))
  1853. (case size
  1854. ((3)
  1855. (let* ((gain-a (+ (* (mat 0 0) x)
  1856. (* (mat 1 0) y)
  1857. (* (mat 2 0) z)))
  1858. (gain-b (+ (* (mat 0 1) x)
  1859. (* (mat 1 1) y)
  1860. (* (mat 2 1) z)))
  1861. (gain-c (+ (* (mat 0 2) x)
  1862. (* (mat 1 2) y)
  1863. (* (mat 2 2) z)))
  1864. (mag (distance gain-a gain-b gain-c)))
  1865. ;; truncate to zero roundoff errors
  1866. (if (< (abs gain-a) zero-gain)
  1867. (set! gain-a 0.0))
  1868. (if (< (abs gain-b) zero-gain)
  1869. (set! gain-b 0.0))
  1870. (if (< (abs gain-c) zero-gain)
  1871. (set! gain-c 0.0))
  1872. (list (and (>= gain-a 0) (>= gain-b 0) (>= gain-c 0))
  1873. (list (/ gain-a mag) (/ gain-b mag) (/ gain-c mag)))))
  1874. ((2)
  1875. (let* ((gain-a (+ (* (mat 0 0) x)
  1876. (* (mat 1 0) y)))
  1877. (gain-b (+ (* (mat 0 1) x)
  1878. (* (mat 1 1) y)))
  1879. (mag (sqrt (+ (* gain-a gain-a)
  1880. (* gain-b gain-b)))))
  1881. ;; truncate to zero roundoff errors
  1882. (if (< (abs gain-a) zero-gain)
  1883. (set! gain-a 0.0))
  1884. (if (< (abs gain-b) zero-gain)
  1885. (set! gain-b 0.0))
  1886. (list (and (>= gain-a 0) (>= gain-b 0))
  1887. (list (/ gain-a mag) (/ gain-b mag)))))
  1888. ((1)
  1889. (list #t (list 1.0)))))))
  1890. ;; Render a trajectory breakpoint through amplitude panning
  1891. (define famplitude-panning
  1892. (let ((speed-limit (/ (* dlocsig-speed-of-sound (- (car (last tpoints)) (car tpoints))) duration))
  1893. (prev-group #f)
  1894. (prev-x #f)
  1895. (prev-y #f)
  1896. (prev-z #f))
  1897. (define (equalp-intersection L1 L2)
  1898. (if (null? L2)
  1899. L2
  1900. (let loop1 ((L1 L1)
  1901. (result ()))
  1902. (cond ((null? L1)
  1903. (reverse! result))
  1904. ((member (car L1) L2)
  1905. (loop1 (cdr L1)
  1906. (cons (car L1)
  1907. result)))
  1908. (else (loop1 (cdr L1)
  1909. result))))))
  1910. (define (transition-point-3 vert-a vert-b xa ya za xb yb zb)
  1911. (define (cross v1 v2)
  1912. (list (- (* (cadr v1) (third v2))
  1913. (* (third v1) (cadr v2)))
  1914. (- (* (third v1) (car v2))
  1915. (* (car v1) (third v2)))
  1916. (- (* (car v1) (cadr v2))
  1917. (* (cadr v1) (car v2)))))
  1918. (define (dot v1 v2)
  1919. (+ (* (car v1) (car v2))
  1920. (* (cadr v1) (cadr v2))
  1921. (* (third v1) (third v2))))
  1922. (define (sub v1 v2)
  1923. (list (- (car v1) (car v2))
  1924. (- (cadr v1) (cadr v2))
  1925. (- (third v1) (third v2))))
  1926. (define (add v1 v2)
  1927. (list (+ (car v1) (car v2))
  1928. (+ (cadr v1) (cadr v2))
  1929. (+ (third v1) (third v2))))
  1930. (define (scale v1 c)
  1931. (list (* (car v1) c)
  1932. (* (cadr v1) c)
  1933. (* (third v1) c)))
  1934. (let* ((tolerance 1.0e-6)
  1935. (line-b (list xa ya za))
  1936. (line-m (sub (list xb yb zb) line-b))
  1937. (normal (cross vert-a vert-b))
  1938. (denominator (dot normal line-m)))
  1939. (and (> (abs denominator) tolerance)
  1940. (add line-b (scale line-m (/ (- (dot normal line-b)) denominator))))))
  1941. ;; calculate transition point between two adjacent two-speaker groups
  1942. ;; original line intersection code from Graphic Gems III
  1943. (define (transition-point-2 vert xa ya xb yb)
  1944. (let ((Ax (car vert))
  1945. (Bx (- xa xb))
  1946. (Ay (cadr vert))
  1947. (By (- ya yb)))
  1948. (let ((d (- (* By (- xa)) (* Bx (- ya))))
  1949. (f (- (* Ay Bx) (* Ax By))))
  1950. (and (not (= f 0))
  1951. (list (/ (* d Ax) f)
  1952. (/ (* d Ay) f))))))
  1953. ;; find the speaker group that contains a point
  1954. (define (find-group x y z)
  1955. (call-with-exit
  1956. (lambda (return)
  1957. (for-each
  1958. (lambda (group)
  1959. (let ((vals (find-gains x y z group)))
  1960. (let ((inside (car vals))
  1961. (gains (cadr vals)))
  1962. (if inside
  1963. (return (list group gains))))))
  1964. (speaker-config-groups speakers))
  1965. (list #f #f))))
  1966. ;; push zero gains on all channels
  1967. (define (push-zero-gains time)
  1968. (do ((len (speaker-config-number speakers))
  1969. (i 0 (+ i 1)))
  1970. ((= i len))
  1971. (set! (channel-gains i) (cons time (channel-gains i)))
  1972. (set! (channel-gains i) (cons 0.0 (channel-gains i))))
  1973. (do ((len rev-channels)
  1974. (i 0 (+ i 1)))
  1975. ((= i len))
  1976. (set! (channel-rev-gains i) (cons time (channel-rev-gains i)))
  1977. (set! (channel-rev-gains i) (cons 0.0 (channel-rev-gains i)))))
  1978. ;; push gain and time into envelopes
  1979. (define (push-gains group gains dist time)
  1980. (define* (position val lst (pos 0))
  1981. (call-with-exit
  1982. (lambda (return)
  1983. (and (not (null? lst))
  1984. (if (= val (car lst))
  1985. (return pos)
  1986. (position val (cdr lst) (+ 1 pos)))))))
  1987. (let ((outputs (make-vector out-channels 0.0))
  1988. (rev-outputs (make-vector rev-channels 0.0))
  1989. ;; attenuation with distance of reverberated signal
  1990. (ratt (if (>= dist inside-radius)
  1991. (expt dist (- reverb-power))
  1992. (- 1.0 (expt (/ dist inside-radius) (/ inside-reverb-power))))))
  1993. (let (;; attenuation with distance of direct signal
  1994. (att (if (>= dist inside-radius)
  1995. (expt dist (- direct-power))
  1996. (- 1.0 (expt (/ dist inside-radius) (/ inside-direct-power))))))
  1997. (if (>= dist inside-radius)
  1998. ;; outside the inner sphere, signal is sent to group
  1999. (do ((len (length gains))
  2000. (i 0 (+ i 1)))
  2001. ((= i len))
  2002. (let ((speaker ((group-speakers group) i))
  2003. (gain (gains i)))
  2004. (set! (outputs speaker) (* gain att))
  2005. (if (and (> rev-channels 1)
  2006. (< speaker (length rev-outputs)))
  2007. (set! (rev-outputs speaker) (* gain ratt)))))
  2008. (let ((gain 0.0)
  2009. (len (speaker-config-number speakers)))
  2010. (do ((speaker 0 (+ 1 speaker)))
  2011. ((= speaker len))
  2012. ;; inside the inner sphere, signal is sent to all speakers
  2013. (let ((found (position speaker (group-speakers group))))
  2014. (if found
  2015. ;; speaker belongs to group, add to existing gain
  2016. (begin
  2017. (set! gain (gains found))
  2018. (set! (outputs speaker) (+ gain (* (- 1.0 gain) att)))
  2019. (if (> rev-channels 1) (set! (rev-outputs speaker) (+ gain (* (- 1.0 gain) ratt)))))
  2020. ;; speaker outside of group
  2021. (begin
  2022. (set! (outputs speaker) att)
  2023. (if (> rev-channels 1) (set! (rev-outputs speaker) ratt)))))))))
  2024. ;; push all channel gains into envelopes
  2025. (let ((len (speaker-config-number speakers)))
  2026. (do ((i 0 (+ i 1)))
  2027. ((= i len))
  2028. (if (or (null? (channel-gains i))
  2029. (> time (cadr (channel-gains i))))
  2030. (begin
  2031. (set! (channel-gains i) (cons time (channel-gains i)))
  2032. (set! (channel-gains i) (cons (outputs i) (channel-gains i)))))))
  2033. (if (> rev-channels 1)
  2034. (do ((i 0 (+ i 1)))
  2035. ((= i rev-channels))
  2036. (if (or (null? (channel-rev-gains i))
  2037. (> time (cadr (channel-rev-gains i))))
  2038. (begin
  2039. (set! (channel-rev-gains i) (cons time (channel-rev-gains i)))
  2040. (set! (channel-rev-gains i) (cons (rev-outputs i) (channel-rev-gains i)))))))
  2041. ;; push reverb gain into envelope for mono reverb
  2042. (if (and (= rev-channels 1)
  2043. (or (null? (channel-rev-gains 0))
  2044. (> time (cadr (channel-rev-gains 0)))))
  2045. (begin
  2046. (set! (channel-rev-gains 0) (cons time (channel-rev-gains 0)))
  2047. (set! (channel-rev-gains 0) (cons ratt (channel-rev-gains 0)))))))
  2048. (lambda (x y z dist time)
  2049. ;; output gains for current point
  2050. (if prev-group
  2051. (let ((vals (find-gains x y z prev-group)))
  2052. (let ((inside (car vals))
  2053. (gains (cadr vals)))
  2054. ;; check that the source is not moving faster than sound
  2055. (if (not (= time prev-time))
  2056. (let ((speed (/ (- dist prev-dist) (- time prev-time))))
  2057. (if (> speed speed-limit)
  2058. (format () "warning: supersonic radial movement at [~F,~F,~F, ~F], speed=~F~%" x y z time speed))))
  2059. (if inside
  2060. ;; still in the same group
  2061. (begin
  2062. (push-gains prev-group gains dist time)
  2063. (set! prev-x x)
  2064. (set! prev-y y)
  2065. (set! prev-z z))
  2066. ;; left the group
  2067. (let ((vals (find-group x y z)))
  2068. (let ((group (car vals))
  2069. (gains (cadr vals)))
  2070. (if (not group)
  2071. (begin
  2072. ;; current point is outside all defined groups
  2073. ;; we should send a warning at this point...
  2074. (push-zero-gains time)
  2075. (set! prev-group #f))
  2076. (begin
  2077. ;; we have to interpolate a new point that lies on the shared
  2078. ;; edge of the adjacent groups so that the speakers opposite
  2079. ;; the edge have zero gain when the trajectory switches groups
  2080. (let ((edge (equalp-intersection (group-vertices group)
  2081. (group-vertices prev-group))))
  2082. (cond ((= (length edge) 2)
  2083. ;; the groups have two shared points (ie: share an edge)
  2084. ;; this must be a three speaker groups transition
  2085. (let ((pint (transition-point-3 (car edge) (cadr edge) x y z prev-x prev-y prev-z)))
  2086. (when pint
  2087. (let* ((xi (car pint))
  2088. (yi (cadr pint))
  2089. (zi (third pint))
  2090. (vals (find-gains xi yi zi prev-group)))
  2091. (let ((di (distance xi yi zi))
  2092. (ti (+ prev-time (max .00001 (* (/ (distance (- xi prev-x)
  2093. (- yi prev-y)
  2094. (- zi prev-z))
  2095. (distance (- x prev-x)
  2096. (- y prev-y)
  2097. (- z prev-z)))
  2098. (- time prev-time)))))
  2099. ;; see if we are inside the previous group
  2100. ;; we can be on either side due to roundoff errors
  2101. (inside (car vals))
  2102. (gains (cadr vals)))
  2103. (if inside
  2104. (push-gains prev-group gains di ti)
  2105. (let ((val1 (find-gains xi yi zi group)))
  2106. (let ((inside (car val1))
  2107. (gains (cadr val1)))
  2108. (if inside
  2109. (push-gains group gains di ti)
  2110. ;; how did we get here?
  2111. (error 'mus-error "Outside of both adjacent groups [~A:~A:~A @~A]~%~%" xi yi zi ti))))))))))
  2112. ((and (pair? edge)
  2113. (null? (cdr edge))
  2114. (= (group-size group) 2))
  2115. ;; two two-speaker groups share one point
  2116. ;; z coordinates are silently ignored
  2117. (let ((pint (transition-point-2 (car edge) x y prev-x prev-y)))
  2118. (when pint
  2119. (let* ((xi (car pint))
  2120. (yi (cadr pint))
  2121. (vals (find-gains xi yi 0.0 prev-group)))
  2122. (let ((di (distance xi yi 0.0))
  2123. (ti (+ prev-time (max .00001 (* (/ (distance (- xi prev-x)
  2124. (- yi prev-y)
  2125. 0.0)
  2126. (distance (- x prev-x)
  2127. (- y prev-y)
  2128. 0.0))
  2129. (- time prev-time)))))
  2130. ;; see if we are inside the previous group
  2131. ;; we can be on either side due to roundoff errors
  2132. (inside (car vals))
  2133. (gains (cadr vals)))
  2134. (if inside
  2135. (push-gains prev-group gains di ti)
  2136. (let ((val1 (find-gains xi yi 0.0 group)))
  2137. (let ((inside (car val1))
  2138. (gains (cadr val1)))
  2139. (if inside
  2140. (push-gains group gains di ti)
  2141. ;; how did we get here?
  2142. (format () "Outside of both adjacent groups [~A:~A @~A]~%~%" xi yi ti))))))))))
  2143. ((and (pair? edge)
  2144. (null? (cdr edge)))
  2145. ;; groups share only one point... for now a warning
  2146. ;; we should calculate two additional interpolated
  2147. ;; points as the trajectory must be crossing a third
  2148. ;; group
  2149. (for-each
  2150. (lambda (int-group)
  2151. (if (and (member (car edge) (group-vertices int-group))
  2152. (not (equal? int-group group))
  2153. (not (equal? int-group prev-group)))
  2154. (format () "e1=~A; e2=~A~%~%"
  2155. (equalp-intersection (group-vertices int-group)
  2156. (group-vertices prev-group))
  2157. (equalp-intersection (group-vertices int-group)
  2158. (group-vertices group)))))
  2159. (speaker-config-groups speakers))
  2160. (format () "warning: crossing between groups with only one point in common~% prev=~A~% curr=~A~%" prev-group group))
  2161. ;; groups don't share points... how did we get here?
  2162. ((null? edge)
  2163. (format () "warning: crossing between groups with no common points, ~A~A to ~A~A~%"
  2164. (group-id prev-group) (group-speakers prev-group)
  2165. (group-id group) (group-speakers group)))))
  2166. ;; finally push gains for current group
  2167. (push-gains group gains dist time)
  2168. (set! prev-group group)
  2169. (set! prev-x x)
  2170. (set! prev-y y)
  2171. (set! prev-z z))))))))
  2172. ;; first time around
  2173. (let ((vals (find-group x y z)))
  2174. (let ((group (car vals))
  2175. (gains (cadr vals)))
  2176. (if group
  2177. (begin
  2178. (push-gains group gains dist time)
  2179. (set! prev-group group)
  2180. (set! prev-x x)
  2181. (set! prev-y y)
  2182. (set! prev-z z))
  2183. (begin
  2184. (push-zero-gains time)
  2185. (set! prev-group #f)))))))))
  2186. ;; Render a trajectory breakpoint for ambisonics b-format coding
  2187. ;; http://www.york.ac.uk/inst/mustech/3d_audio/ambis2.htm
  2188. ;;
  2189. ;; Ambisonics b-format has four discrete channels encoded as follows:
  2190. ;; W 0.707107 0.707107
  2191. ;; X cos(A)cos(E) x
  2192. ;; Y sin(A)cos(E) y
  2193. ;; R 1.5sin(E)sin(E)-0.5 1.5zz-0.5
  2194. ;; S cos(A)sin(2E) 2zx
  2195. ;; T sin(A)sin(2E) 2yz
  2196. ;; U cos(2A)cos(E)cos(E) xx-yy
  2197. ;; V sin(2A)cos(E)cos(E) 2xy
  2198. ;; K z(2.5zz-1.5)
  2199. ;; L K1(x(5zz-1)
  2200. ;; K1=sqrt(21*45/(224*8))
  2201. ;; M K1(y(5zz-1))
  2202. ;; N K2(Uz)
  2203. ;; K2=sqrt(3)*3/2
  2204. ;; O K2(Vz)
  2205. ;; P x(xx-3yy)
  2206. ;; Q y(3xx-yy)
  2207. ;;
  2208. ;; where:
  2209. ;; A: counter-clockwise angle of rotation from the front center
  2210. ;; E: the angle of elevation above the horizontal plane
  2211. ;;
  2212. ;; in our coordinate system (normalizing the vectors):
  2213. ;; xy: (* dist (cos E))
  2214. ;; (cos A): (/ y xy)
  2215. ;; (sin A): (/ -x xy)
  2216. ;; (cos E): (/ xy dist)
  2217. ;; (sin E): (/ z dist)
  2218. ;; so:
  2219. ;; W: (* signal 0.707)
  2220. ;; X: (* signal (/ y dist))
  2221. ;; Y: (* signal (/ -x dist))
  2222. ;; Z: (* signal (/ z dist))
  2223. ;;
  2224. ;; R: (* signal (- (* 1.5 z z 1/dist 1/dist) 0.5))
  2225. ;; S: (* signal 2 z (- x) 1/dist 1/dist)
  2226. ;; T: (* signal 2 z y 1/dist 1/dist)
  2227. ;; U: (* signal (- (* x x 1/dist 1/dist) (* y y 1/dist 1/dist)))
  2228. ;; V: (* signal 2 (- x) y 1/dist 1/dist)
  2229. ;;
  2230. ;; K: (* signal z (- (* 2.5 z z 1/dist 1/dist) 1.5))
  2231. ;; L: (* signal K1 x 1/dist (- (* 5 z z 1/dist 1/dist) 1))
  2232. ;; M: (* signal K1 y 1/dist (- (* 5 z z 1/dist 1/dist) 1))
  2233. ;; N: (* signal K2 U z 1/dist)
  2234. ;; O: (* signal K2 V z 1/dist)
  2235. ;; P: (* signal x 1/dist (- (* x x 1/dist 1/dist) (* 3 y y 1/dist 1/dist)))
  2236. ;; Q: (* signal y 1/dist (- (* 3 x x 1/dist 1/dist) (* y y 1/dist 1/dist)))
  2237. ;;
  2238. ;; see also: http://wiki.xiph.org/index.php/Ambisonics
  2239. ;; for mixed order systems
  2240. ;;
  2241. (define render-ambisonics
  2242. (let ((w-offset 0)
  2243. (x-offset 1)
  2244. (y-offset 2)
  2245. (ambisonics-k1 (sqrt 135/256)) ;(/ (* 21 45) 224 8)
  2246. (ambisonics-k2 (* (sqrt 3) 3 0.5)))
  2247. (lambda (x y z dist time)
  2248. (let ((att (if (> dist inside-radius)
  2249. (expt (/ inside-radius dist) direct-power)
  2250. (expt (/ dist inside-radius) (/ inside-direct-power))))
  2251. (ratt (if (> dist inside-radius)
  2252. (expt (/ inside-radius dist) reverb-power)
  2253. (expt (/ dist inside-radius) (/ inside-reverb-power))))
  2254. (u 0)
  2255. (v 0)
  2256. (lm 0)
  2257. (no 0))
  2258. ;; output encoding gains for point
  2259. ;; W: 0.707
  2260. (set! (channel-gains w-offset) (cons time (channel-gains w-offset)))
  2261. (let ((attW (if (> dist inside-radius)
  2262. (* point707 att)
  2263. (- 1 (* (- 1 point707) (expt (/ dist inside-radius) direct-power))))))
  2264. (set! (channel-gains w-offset) (cons attW (channel-gains w-offset))))
  2265. ;; X: (* (cos A) (cos E))
  2266. (set! (channel-gains x-offset) (cons time (channel-gains x-offset)))
  2267. (set! (channel-gains x-offset) (cons (* (if (zero? dist) 0 (/ y dist)) att) (channel-gains x-offset)))
  2268. ;; Y: (* (sin A) (cos E))
  2269. (set! (channel-gains y-offset) (cons time (channel-gains y-offset)))
  2270. (set! (channel-gains y-offset) (cons (* (if (zero? dist) 0 (/ (- x) dist)) att) (channel-gains y-offset)))
  2271. (when (>= ambisonics-v-order 1)
  2272. ;; Z: (sin E)
  2273. (set! (channel-gains z-offset) (cons time (channel-gains z-offset)))
  2274. (set! (channel-gains z-offset) (cons (* (if (zero? dist) 0 (/ z dist)) att) (channel-gains z-offset))))
  2275. (when (>= ambisonics-v-order 2)
  2276. ;; R
  2277. (set! (channel-gains r-offset) (cons time (channel-gains r-offset)))
  2278. (set! (channel-gains r-offset) (cons (* (if (zero? dist) 0 (- (* 1.5 z z (if (zero? dist) 1 (/ 1.0 dist dist))) 0.5)) att)
  2279. (channel-gains r-offset)))
  2280. ;; S
  2281. (set! (channel-gains s-offset) (cons time (channel-gains s-offset)))
  2282. (set! (channel-gains s-offset) (cons (* (if (zero? dist) 0 2) z (- x) (if (zero? dist) 1 (/ 1.0 dist dist)) att)
  2283. (channel-gains s-offset)))
  2284. ;; T
  2285. (set! (channel-gains t-offset) (cons time (channel-gains t-offset)))
  2286. (set! (channel-gains t-offset) (cons (* (if (zero? dist) 0 2) z y (if (zero? dist) 1 (/ 1.0 dist dist)) att)
  2287. (channel-gains t-offset))))
  2288. (when (>= ambisonics-h-order 2)
  2289. (set! u (* (if (zero? dist) 0 1) (- (* x x (if (zero? dist) 1 (/ 1.0 dist dist)))
  2290. (* y y (if (zero? dist) 1 (/ 1.0 dist dist)))) att))
  2291. (set! v (* (if (zero? dist) 0 2) (- x) y (if (zero? dist) 1 (/ 1.0 dist dist)) att))
  2292. ;; U
  2293. (set! (channel-gains u-offset) (cons time (channel-gains u-offset)))
  2294. (set! (channel-gains u-offset) (cons u (channel-gains u-offset)))
  2295. ;; V
  2296. (set! (channel-gains v-offset) (cons time (channel-gains v-offset)))
  2297. (set! (channel-gains v-offset) (cons v (channel-gains v-offset))))
  2298. (when (>= ambisonics-v-order 3)
  2299. (set! lm (* ambisonics-k1 (- (* 5 z z (if (zero? dist) 1 (/ 1.0 dist dist))) 1) att))
  2300. (set! no (* ambisonics-k2 z (if (zero? dist) 1 (/ dist)) att))
  2301. ;; K
  2302. (set! (channel-gains k-offset) (cons time (channel-gains k-offset)))
  2303. (set! (channel-gains k-offset) (cons (* (if (zero? dist) 0 1) (- (* 2.5 z z (if (zero? dist) 1 (/ 1.0 dist dist))) 1.5) att) (channel-gains k-offset)))
  2304. ;; L
  2305. (set! (channel-gains l-offset) (cons time (channel-gains l-offset)))
  2306. (set! (channel-gains l-offset) (cons (* (if (zero? dist) 0 (/ x dist)) lm) (channel-gains l-offset)))
  2307. ;; M
  2308. (set! (channel-gains m-offset) (cons time (channel-gains m-offset)))
  2309. (set! (channel-gains m-offset) (cons (* (if (zero? dist) 0 (/ y dist)) lm) (channel-gains m-offset)))
  2310. ;; N
  2311. (set! (channel-gains n-offset) (cons time (channel-gains n-offset)))
  2312. (set! (channel-gains n-offset) (cons (* (if (zero? dist) 0 no) u) (channel-gains n-offset)))
  2313. ;; O
  2314. (set! (channel-gains o-offset) (cons time (channel-gains o-offset)))
  2315. (set! (channel-gains o-offset) (cons (* (if (zero? dist) 0 no) v) (channel-gains o-offset))))
  2316. (when (>= ambisonics-h-order 3)
  2317. ;; P
  2318. (set! (channel-gains p-offset) (cons time (channel-gains p-offset)))
  2319. (set! (channel-gains p-offset) (let ((dist-p (- (* x x (if (zero? dist) 1 (/ 1.0 dist dist)))
  2320. (* 3 y y (if (zero? dist) 1 (/ 1.0 dist dist))))))
  2321. (cons (* (if (zero? dist) 0 (/ att dist)) x dist-p)
  2322. (channel-gains p-offset))))
  2323. ;; Q
  2324. (set! (channel-gains q-offset) (cons time (channel-gains q-offset)))
  2325. (set! (channel-gains q-offset) (let ((dist-q (- (* 3 x x (if (zero? dist) 1 (/ 1.0 dist dist)))
  2326. (* y y (if (zero? dist) 1 (/ 1.0 dist dist))))))
  2327. (cons (* (if (zero? dist) 0 (/ att dist)) y dist-q)
  2328. (channel-gains q-offset)))))
  2329. ;; push reverb gain into envelope
  2330. (when (= rev-channels 1)
  2331. ;; mono reverb output
  2332. (set! (channel-rev-gains 0) (cons time (channel-rev-gains 0)))
  2333. (set! (channel-rev-gains 0) (cons (if (>= dist inside-radius)
  2334. (expt dist (- reverb-power))
  2335. (- 1.0 (expt (/ dist inside-radius) (/ inside-reverb-power))))
  2336. (channel-rev-gains 0))))
  2337. (when (> rev-channels 1)
  2338. ;; multichannel reverb, send ambisonics components
  2339. ;; W: 0.707
  2340. (set! (channel-rev-gains w-offset) (cons time (channel-rev-gains w-offset)))
  2341. (let ((rattW (if (> dist inside-radius)
  2342. (* point707 ratt)
  2343. (- 1 (* (- 1 point707) (expt (/ dist inside-radius) reverb-power))))))
  2344. (set! (channel-rev-gains w-offset) (cons rattW (channel-rev-gains w-offset))))
  2345. ;; X: (* (cos A)(cos E))
  2346. (set! (channel-rev-gains x-offset) (cons time (channel-rev-gains x-offset)))
  2347. (set! (channel-rev-gains x-offset) (cons (* (if (zero? dist) 0 1) y (if (zero? dist) 1 (/ dist)) ratt)
  2348. (channel-rev-gains x-offset)))
  2349. ;; Y: (* (sin A)(cos E))
  2350. (set! (channel-rev-gains y-offset) (cons time (channel-rev-gains y-offset)))
  2351. (set! (channel-rev-gains y-offset) (cons (* (if (zero? dist) 0 1) (- x) (if (zero? dist) 1 (/ dist)) ratt)
  2352. (channel-rev-gains y-offset)))
  2353. (when (>= ambisonics-v-order 1)
  2354. ;; Z: (sin E)
  2355. (set! (channel-rev-gains z-offset) (cons time (channel-rev-gains z-offset)))
  2356. (set! (channel-rev-gains z-offset) (cons (* (if (zero? dist) 0 1) z (if (zero? dist) 1 (/ dist)) ratt)
  2357. (channel-rev-gains z-offset))))
  2358. (when (>= ambisonics-v-order 2)
  2359. ;; R
  2360. (set! (channel-rev-gains r-offset) (cons time (channel-rev-gains r-offset)))
  2361. (set! (channel-rev-gains r-offset) (cons (* (if (zero? dist) 0 (- (* 1.5 z z (if (zero? dist) 1 (/ 1.0 dist dist))) 0.5))
  2362. dlocsig-ambisonics-ho-rev-scaler ratt)
  2363. (channel-rev-gains r-offset)))
  2364. ;; S
  2365. (set! (channel-rev-gains s-offset) (cons time (channel-rev-gains s-offset)))
  2366. (set! (channel-rev-gains s-offset) (cons (* (if (zero? dist) 0 2) z (- x) (if (zero? dist) 1 (/ 1.0 dist dist))
  2367. dlocsig-ambisonics-ho-rev-scaler ratt)
  2368. (channel-rev-gains s-offset)))
  2369. ;; T
  2370. (set! (channel-rev-gains t-offset) (cons time (channel-rev-gains t-offset)))
  2371. (set! (channel-rev-gains t-offset) (cons (* (if (zero? dist) 0 2) z y (if (zero? dist) 1 (/ 1.0 dist dist))
  2372. dlocsig-ambisonics-ho-rev-scaler ratt)
  2373. (channel-rev-gains t-offset))))
  2374. (when (>= ambisonics-h-order 2)
  2375. ;; U
  2376. (set! (channel-rev-gains u-offset) (cons time (channel-rev-gains u-offset)))
  2377. (set! (channel-rev-gains u-offset) (let ((dist-u (* (if (zero? dist) 0
  2378. (- (* x x (if (zero? dist) 1 (/ 1.0 dist dist)))
  2379. (* y y (if (zero? dist) 1 (/ 1.0 dist dist)))))
  2380. dlocsig-ambisonics-ho-rev-scaler ratt)))
  2381. (cons dist-u (channel-rev-gains u-offset))))
  2382. ;; V
  2383. (set! (channel-rev-gains v-offset) (cons time (channel-rev-gains v-offset)))
  2384. (set! (channel-rev-gains v-offset) (let ((dist-v (* (if (zero? dist) 0 2)
  2385. (- x) y
  2386. (if (zero? dist) 1 (/ 1.0 dist dist))
  2387. dlocsig-ambisonics-ho-rev-scaler ratt)))
  2388. (cons dist-v (channel-rev-gains v-offset)))))
  2389. (when (>= ambisonics-v-order 3)
  2390. (set! lm (* ambisonics-k1 (- (* 5 z z (if (zero? dist) 1 (/ 1.0 dist dist))) 1)
  2391. dlocsig-ambisonics-ho-rev-scaler ratt))
  2392. (set! no (* ambisonics-k2 z (if (zero? dist) 1 (/ dist)) ratt))
  2393. ;; K
  2394. (set! (channel-rev-gains k-offset) (cons time (channel-rev-gains k-offset)))
  2395. (set! (channel-rev-gains k-offset) (let ((dist-k (* (if (zero? dist) 0 1)
  2396. (- (* 2.5 z z (if (zero? dist) 1 (/ 1.0 dist dist))) 1.5)
  2397. dlocsig-ambisonics-ho-rev-scaler ratt)))
  2398. (cons dist-k (channel-rev-gains k-offset))))
  2399. ;; L
  2400. (set! (channel-rev-gains l-offset) (cons time (channel-rev-gains l-offset)))
  2401. (set! (channel-rev-gains l-offset) (cons (* (if (zero? dist) 0 (/ x dist)) lm)
  2402. (channel-rev-gains l-offset)))
  2403. ;; M
  2404. (set! (channel-rev-gains m-offset) (cons time (channel-rev-gains m-offset)))
  2405. (set! (channel-rev-gains m-offset) (cons (* (if (zero? dist) 0 (/ y dist)) lm)
  2406. (channel-rev-gains m-offset)))
  2407. ;; N
  2408. (set! (channel-rev-gains n-offset) (cons time (channel-rev-gains n-offset)))
  2409. (set! (channel-rev-gains n-offset) (cons (* (if (zero? dist) 0 no) u)
  2410. (channel-rev-gains n-offset)))
  2411. ;; O
  2412. (set! (channel-rev-gains o-offset) (cons time (channel-rev-gains o-offset)))
  2413. (set! (channel-rev-gains o-offset) (cons (* (if (zero? dist) 0 no) v)
  2414. (channel-rev-gains o-offset))))
  2415. (when (>= ambisonics-h-order 3)
  2416. ;; P
  2417. (set! (channel-rev-gains p-offset) (cons time (channel-rev-gains p-offset)))
  2418. (set! (channel-rev-gains p-offset) (let ((dist-p (* (if (zero? dist) 0 (/ ratt dist))
  2419. dlocsig-ambisonics-ho-rev-scaler x
  2420. (- (* x x (if (zero? dist) 1 (/ 1.0 dist dist)))
  2421. (* 3 y y (if (zero? dist) 1 (/ 1.0 dist dist)))))))
  2422. (cons dist-p (channel-rev-gains p-offset))))
  2423. ;; Q
  2424. (set! (channel-rev-gains q-offset) (cons time (channel-rev-gains q-offset)))
  2425. (set! (channel-rev-gains q-offset) (let ((dist-q (* (if (zero? dist) 0 (/ ratt dist))
  2426. dlocsig-ambisonics-ho-rev-scaler y
  2427. (- (* 3 x x (if (zero? dist) 1 (/ 1.0 dist dist)))
  2428. (* y y (if (zero? dist) 1 (/ 1.0 dist dist)))))))
  2429. (cons dist-q (channel-rev-gains q-offset)))))
  2430. )))))
  2431. ;; Render a trajectory breakpoint to a room for decoded ambisonics
  2432. ;;
  2433. ;; for a given speaker located in 3d space in polar coordinates:
  2434. ;; az: azimut angle, increments clockwise
  2435. ;; el: elevation angle
  2436. ;;
  2437. ;; S: (+ W (* X (cos az) (cos el))
  2438. ;; (* Y (sin az) (cos el))
  2439. ;; (* Z (sin el)))
  2440. ;;
  2441. (define (fdecoded-ambisonics x y z dist time)
  2442. (let ((att (if (> dist inside-radius)
  2443. (expt (/ inside-radius dist) direct-power)
  2444. (expt (/ dist inside-radius) (/ inside-direct-power))))
  2445. (ratt (if (> dist inside-radius)
  2446. (expt (/ inside-radius dist) reverb-power)
  2447. (expt (/ dist inside-radius) (/ inside-reverb-power)))))
  2448. (let ((attW (if (> dist inside-radius)
  2449. (* point707 att)
  2450. (- 1 (* (- 1 point707) (expt (/ dist inside-radius) direct-power)))))
  2451. (rattW (if (> dist inside-radius)
  2452. (* point707 ratt)
  2453. (- 1 (* (- 1 point707) (expt (/ dist inside-radius) reverb-power))))))
  2454. ;; output decoded gains for point
  2455. (let ((len (speaker-config-number speakers))
  2456. (spkrs (speaker-config-coords speakers)))
  2457. (do ((i 0 (+ i 1)))
  2458. ((= i len))
  2459. (let ((signal (let ((s (spkrs i)))
  2460. (* dlocsig-ambisonics-scaler
  2461. (+
  2462. ;; W
  2463. (* attW point707)
  2464. ;; (* X (cos az) (cos el))
  2465. (* att (if (= dist 0) 0 (/ y dist)) (cadr s))
  2466. ;; (* Y (sin az) (cos el))
  2467. (* att (if (= dist 0) 0 (/ x dist)) (car s))
  2468. ;; (* Z (sin el)
  2469. (* att (if (= dist 0) 0 (/ z dist)) (third s)))))))
  2470. (set! (channel-gains i) (cons time (channel-gains i)))
  2471. (set! (channel-gains i) (cons signal (channel-gains i))))))
  2472. ;; push reverb gain into envelope
  2473. (if (= rev-channels 1)
  2474. (begin
  2475. ;; mono reverberation
  2476. (set! (channel-rev-gains 0) (cons time (channel-rev-gains 0)))
  2477. (set! (channel-rev-gains 0) (cons (if (>= dist inside-radius)
  2478. (expt dist (- reverb-power))
  2479. (- 1.0 (expt (/ dist inside-radius) (/ inside-reverb-power))))
  2480. (channel-rev-gains 0))))
  2481. ;; multichannel reverb
  2482. (do ((i 0 (+ i 1)))
  2483. ((= i rev-channels))
  2484. (let ((signal (let ((s ((speaker-config-coords speakers) i)))
  2485. (* dlocsig-ambisonics-scaler
  2486. (+
  2487. ;; W
  2488. (* rattW point707)
  2489. ;; (* X (cos az) (cos el))
  2490. (* ratt (if (zero? dist) 0 (/ y dist)) (cadr s))
  2491. ;; (* Y (sin az) (cos el))
  2492. (* ratt (if (zero? dist) 0 (/ x dist)) (car s))
  2493. ;; (* Z (sin el)
  2494. (* ratt (if (zero? dist) 0 (/ z dist)) (third s)))))))
  2495. (set! (channel-rev-gains i) (cons time (channel-rev-gains i)))
  2496. (set! (channel-rev-gains i) (cons signal (channel-rev-gains i)))))))))
  2497. ;; Loop through all virtual rooms for one breakpoint in the trajectory
  2498. (define (walk-all-rooms x y z time)
  2499. (let ((dist (distance x y z)))
  2500. ;; remember first and last distances
  2501. (if (not first-dist) ; set to #f (far) above
  2502. (set! first-dist dist))
  2503. (set! last-dist dist)
  2504. ;; remember maximum and minimum distances
  2505. (if (or (not (real? min-dist)) (< dist min-dist))
  2506. (set! min-dist dist))
  2507. (if (or (not (real? max-dist)) (> dist max-dist))
  2508. (set! max-dist dist))
  2509. ;; push delay for current point (for doppler)
  2510. (if (or (null? dly)
  2511. (> time (cadr dly)))
  2512. (begin
  2513. (set! dly (cons (dist->samples dist)
  2514. (cons time dly)))
  2515. ;; doppler should be easy, yeah right. We use "relativistic" correction
  2516. ;; as the sound object can be travelling close to the speed of sound.
  2517. ;; http://www.mathpages.com/rr/s2-04/2-04.htm,
  2518. ;; va = 0 (stationary listener)
  2519. ;; ve = moving object
  2520. ;; va = (* ve (/ 1 (+ 1 (/ ve c))) (sqrt (- 1 (* (/ ve c) (/ ve c)))))
  2521. (if prev-time
  2522. (let ((ratio (/ (- dist prev-dist)
  2523. (* duration (- time prev-time) dlocsig-speed-of-sound))))
  2524. (set! doppler (cons (* (/ 1.0 (+ 1 ratio)) (sqrt (- 1 (* ratio ratio))))
  2525. (cons (/ (+ prev-time time) 2) doppler)))))))
  2526. ;; do the rendering of the point
  2527. (cond ((= render-using amplitude-panning)
  2528. ;; amplitude panning
  2529. (famplitude-panning x y z dist time))
  2530. ((= render-using ambisonics)
  2531. ;; ambisonics b format
  2532. (render-ambisonics x y z dist time))
  2533. ((= render-using decoded-ambisonics)
  2534. ;; ambisonics decoded
  2535. (fdecoded-ambisonics x y z dist time)))
  2536. (let ((room 1))
  2537. ;; remember current time and distance for next point
  2538. (set! prev-time time)
  2539. (set! prev-dist dist)
  2540. ;; return number of rooms processed (?)
  2541. room)))
  2542. ;; Check to see if a segment changes radial direction:
  2543. ;; a change in radial direction implies a change in
  2544. ;; doppler shift that has to be reflected as a new
  2545. ;; point in the rendered envelopes
  2546. (define (change-direction xa ya za ta xb yb zb tb)
  2547. (walk-all-rooms xa ya za ta)
  2548. (unless (and (= xa xb)
  2549. (= ya yb)
  2550. (= za zb)
  2551. (= ta tb))
  2552. (let ((vals (nearest-point xa ya za xb yb zb 0 0 0)))
  2553. (let ((xi (car vals))
  2554. (yi (cadr vals))
  2555. (zi (caddr vals)))
  2556. (if (and (if (< xa xb) (<= xa xi xb) (<= xb xi xa))
  2557. (if (< ya yb) (<= ya yi yb) (<= yb yi ya))
  2558. (if (< za zb) (<= za zi zb) (<= zb zi za)))
  2559. (walk-all-rooms xi yi zi
  2560. (+ tb (* (- ta tb)
  2561. (/ (distance (- xb xi) (- yb yi) (- zb zi))
  2562. (distance (- xb xa) (- yb ya) (- zb za)))))))))))
  2563. ;; Check to see if a segment intersects the inner sphere:
  2564. ;; points inside are rendered differently so we need to
  2565. ;; create additional envelope points in the boundaries
  2566. (define (intersects-inside-radius xa ya za ta xb yb zb tb)
  2567. (let* ((mag (distance (- xb xa) (- yb ya) (- zb za)))
  2568. (vx (/ (- xb xa) mag))
  2569. (vy (/ (- yb ya) mag))
  2570. (vz (/ (- zb za) mag))
  2571. (bsq (+ (* xa vx) (* ya vy) (* za vz)))
  2572. (disc (let ((u (- (+ (* xa xa) (* ya ya) (* za za))
  2573. (* inside-radius inside-radius))))
  2574. (- (* bsq bsq) u)))
  2575. (hit (>= disc 0.0)))
  2576. (if (not hit)
  2577. (change-direction xa ya za ta xb yb zb tb)
  2578. ;; ray defined by two points hits sphere
  2579. (let ((root (sqrt disc)))
  2580. (let ((rin (- (+ bsq root)))
  2581. (rout (- root bsq))
  2582. (xi #f) (yi #f) (zi #f) (ti #f) (xo #f) (yo #f) (zo #f) (to #f))
  2583. (if (> mag rin 0) ;(and (> rin 0) (< rin mag))
  2584. ;; intersects entering sphere
  2585. (begin
  2586. (set! xi (+ xa (* vx rin)))
  2587. (set! yi (+ ya (* vy rin)))
  2588. (set! zi (+ za (* vz rin)))
  2589. (set! ti (+ tb (* (- ta tb)
  2590. (/ (distance (- xb xi) (- yb yi) (- zb zi))
  2591. (distance (- xb xa) (- yb ya) (- zb za))))))))
  2592. (if (and (> rout 0) (< (abs rout) mag))
  2593. ;; intersects leaving sphere
  2594. (begin
  2595. (set! xo (+ xa (* vx rout)))
  2596. (set! yo (+ ya (* vy rout)))
  2597. (set! zo (+ za (* vz rout)))
  2598. (set! to (+ tb (* (- ta tb)
  2599. (/ (distance (- xb xo) (- yb yo) (- zb zo))
  2600. (distance (- xb xa) (- yb ya) (- zb za))))))))
  2601. (if xi
  2602. (begin
  2603. (change-direction xa ya za ta xi yi zi ti)
  2604. (if xo
  2605. (begin
  2606. (change-direction xi yi zi ti xo yo zo to)
  2607. (change-direction xo yo zo to xb yb zb tb))
  2608. (change-direction xi yi zi ti xb yb zb tb)))
  2609. (if xo
  2610. (begin
  2611. (change-direction xa ya za ta xo yo zo to)
  2612. (change-direction xo yo zo to xb yb zb tb))
  2613. (change-direction xa ya za ta xb yb zb tb))))))))
  2614. ;; Recursively split segment if longer than minimum rendering distance:
  2615. ;; otherwise long line segments that have changes in distance render
  2616. ;; the amplitude envelope as a linear function that does not reflect
  2617. ;; the chosen power function (1/d^n)
  2618. (define (fminimum-segment-length xa ya za ta xb yb zb tb)
  2619. (let ((dist (distance (- xb xa) (- yb ya) (- zb za))))
  2620. (if (< dist minimum-segment-length)
  2621. (intersects-inside-radius xa ya za ta xb yb zb tb)
  2622. ;; interpolate a new point half way thorugh the segment
  2623. (let* ((xi (/ (+ xa xb) 2))
  2624. (yi (/ (+ ya yb) 2))
  2625. (zi (/ (+ za zb) 2))
  2626. (ti (+ tb (* (- ta tb)
  2627. (/ (distance (- xb xi) (- yb yi) (- zb zi))
  2628. (distance (- xb xa) (- yb ya) (- zb za)))))))
  2629. (fminimum-segment-length xa ya za ta xi yi zi ti)
  2630. (fminimum-segment-length xi yi zi ti xb yb zb tb)))))
  2631. ;; returns the new duration of a sound after using an envelope for time-varying sampling-rate conversion
  2632. ;; (from Bill's dsp.scm)
  2633. (define (src-duration e)
  2634. (let ((len (- (length e) 2)))
  2635. (do ((all-x (- (e len) (e 0))) ; last x - first x
  2636. (dur 0.0)
  2637. (i 0 (+ i 2)))
  2638. ((>= i len) dur)
  2639. (let ((area (let ((x0 (e i))
  2640. (x1 (e (+ i 2)))
  2641. (y0 (e (+ i 1))) ; 1/x x points
  2642. (y1 (e (+ i 3))))
  2643. (if (< (abs (real-part (- y0 y1))) .0001)
  2644. (/ (- x1 x0) (* y0 all-x))
  2645. (/ (* (- (log y1) (log y0))
  2646. (- x1 x0))
  2647. (* (- y1 y0) all-x))))))
  2648. (set! dur (+ dur (abs (real-part area))))))))
  2649. ;; Loop for each pair of points in the position envelope and render them
  2650. (if (and (pair? xpoints)
  2651. (null? (cdr xpoints)))
  2652. ;; static source (we should check if this is inside the inner radius?)
  2653. (walk-all-rooms (car xpoints) (car ypoints) (car zpoints) (car tpoints))
  2654. ;; moving source
  2655. (do ((len (- (min (length xpoints) (length ypoints) (length zpoints) (length tpoints)) 1))
  2656. (i 0 (+ i 1)))
  2657. ((>= i len))
  2658. (let ((xa (xpoints i))
  2659. (ya (ypoints i))
  2660. (za (zpoints i))
  2661. (ta (tpoints i))
  2662. (xb (xpoints (+ i 1)))
  2663. (yb (ypoints (+ i 1)))
  2664. (zb (zpoints (+ i 1)))
  2665. (tb (tpoints (+ i 1))))
  2666. (fminimum-segment-length xa ya za ta xb yb zb tb)
  2667. (if (= i len)
  2668. (walk-all-rooms xb yb zb tb)))))
  2669. ;; create delay lines for output channels that need them
  2670. (if speakers
  2671. (let ((delays (speaker-config-delays speakers)))
  2672. (do ((len (length delays))
  2673. (channel 0 (+ 1 channel)))
  2674. ((= channel len))
  2675. (let ((delayo (delays channel)))
  2676. (set! (out-delays channel) (and (not (= delayo 0.0))
  2677. (make-delay (time->samples delayo))))
  2678. (set! max-out-delay (max max-out-delay delayo))))))
  2679. ;; end of the run according to the duration of the note
  2680. ;; (set! end (time->samples duration))
  2681. ;; start and end of the loop in samples
  2682. (let (;; delay from the minimum distance to the listener
  2683. (min-delay (dist->samples min-dist))
  2684. ;; duration of sound at listener's position after doppler src
  2685. ;; this does not work quite right but the error leads to a longer
  2686. ;; run with zeroed samples at the end so it should be fine
  2687. (real-dur (* duration (if (null? doppler) 1.0 (src-duration (reverse doppler)))))
  2688. ;; minimum distance for unity gain calculation
  2689. (min-dist-unity (max min-dist inside-radius))
  2690. (run-beg (time->samples start-time)))
  2691. (let ((run-end (floor (- (+ (time->samples (+ start-time (max duration real-dur)))
  2692. (dist->samples last-dist)
  2693. (time->samples max-out-delay))
  2694. (if initial-delay 0.0 min-delay))))
  2695. ;; sample at which signal first arrives to the listener
  2696. (start (+ run-beg (dist->samples (- first-dist (if initial-delay 0.0 min-dist)))))
  2697. ;; unity-gain gain scalers
  2698. (unity-gain (* scaler
  2699. (if (number? unity-gain-dist)
  2700. (expt unity-gain-dist direct-power)
  2701. (if unity-gain-dist
  2702. 1.0
  2703. (expt min-dist-unity direct-power)))))
  2704. (unity-rev-gain (* scaler
  2705. (if (number? unity-gain-dist)
  2706. (expt unity-gain-dist reverb-power)
  2707. (if unity-gain-dist ; defaults to #f above
  2708. 1.0
  2709. (expt min-dist-unity reverb-power)))))
  2710. ;; unity-gain ambisonics gain scalers
  2711. (amb-unity-gain (* scaler
  2712. (if (number? unity-gain-dist)
  2713. (expt unity-gain-dist direct-power)
  2714. (if unity-gain-dist
  2715. 1.0
  2716. (expt min-dist-unity direct-power)))))
  2717. (amb-unity-rev-gain (* scaler
  2718. (if (number? unity-gain-dist)
  2719. (expt unity-gain-dist reverb-power)
  2720. (if unity-gain-dist ; defaults to #f above
  2721. 1.0
  2722. (expt min-dist-unity reverb-power))))))
  2723. ;; XXX hack!! this should be intercepted in the calling code, no 0 duration please...
  2724. (if (<= real-dur 0.0)
  2725. (begin
  2726. (format () ";;; error: resetting real duration to 0.1 (was ~A)~%" real-dur)
  2727. (set! real-dur 0.1)))
  2728. (let ((gen (make-move-sound
  2729. (list
  2730. ;; :start
  2731. start
  2732. ;; :end
  2733. (time->samples (+ start-time (max duration real-dur)))
  2734. ;; :out-channels
  2735. (if speakers (speaker-config-number speakers) out-channels)
  2736. ;; :rev-channels
  2737. rev-channels
  2738. ;; :path
  2739. (make-delay delay-hack :max-size (max 1 (+ (ceiling (dist->samples max-dist)) delay-hack)))
  2740. ;; :delay
  2741. (make-env (reverse dly)
  2742. :offset (if initial-delay 0.0 (- min-delay))
  2743. :duration real-dur)
  2744. ;; :rev
  2745. (make-env (if (number? reverb-amount) ; as opposed to an envelope I guess
  2746. (list 0 reverb-amount 1 reverb-amount)
  2747. reverb-amount)
  2748. :duration real-dur)
  2749. ;; :out-delays
  2750. out-delays
  2751. ;; :gains
  2752. (do ((v (make-vector out-channels))
  2753. (i 0 (+ i 1)))
  2754. ((= i out-channels) v)
  2755. (set! (v i) (make-env (reverse (channel-gains i))
  2756. :scaler (if (= render-using ambisonics) amb-unity-gain unity-gain)
  2757. :duration real-dur)))
  2758. ;; :rev-gains
  2759. (and (> rev-channels 0)
  2760. (do ((v (make-vector rev-channels))
  2761. (i 0 (+ i 1)))
  2762. ((= i rev-channels) v)
  2763. (set! (v i) (make-env (reverse (channel-rev-gains i))
  2764. :scaler (if (= render-using ambisonics) amb-unity-rev-gain unity-rev-gain)
  2765. :duration real-dur))))
  2766. ;; :out-map
  2767. (if speakers
  2768. (speaker-config-map speakers)
  2769. (do ((v (make-vector out-channels))
  2770. (i 0 (+ i 1)))
  2771. ((= i out-channels) v)
  2772. (set! (v i) i))))
  2773. *output*
  2774. *reverb*)))
  2775. (list gen
  2776. ;; return start and end samples for the run loop
  2777. run-beg
  2778. run-end))))))
  2779. ;; (with-sound(:channels 6 :play #f :statistics #t) (sinewave 0 10 440 0.5 :path (make-path '((-10 10) (0.5 0.5) (10 10)) :error 0.001)))
  2780. ;;
  2781. ;; (with-sound(:statistics #t :channels 4 :reverb-channels 4 :reverb freeverb :decay-time 3)
  2782. ;; (move 0 "/usr/ccrma/snd/nando/sounds/kitchen/bowl/small-medium-large-1.snd"
  2783. ;; :paths (list (make-spiral-path :start-angle 0 :turns 2.5)
  2784. ;; (make-spiral-path :start-angle 180 :turns 3.5))))
  2785. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  2786. ;;; Run macro to localize samples
  2787. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  2788. (define dlocsig move-sound)
  2789. #|
  2790. ;; (define hi (make-path '((-10 10) (0.5 0.5) (10 10)) :3d #f :error 0.001))
  2791. ;; (make-dlocsig 0 1.0 :out-channels 2 :rev-channels 0 :path (make-path '((-10 10) (0.5 0.5) (10 10)) :3d #f))
  2792. (if (provided? 'snd)
  2793. (require snd-ws.scm)
  2794. (require sndlib-ws.scm))
  2795. (define* (sinewave start-time duration freq amp
  2796. (amp-env '(0 1 1 1))
  2797. (path (make-path :path '(-10 10 0 5 10 10))))
  2798. (let* ((vals (make-dlocsig :start-time start-time
  2799. :duration duration
  2800. :path path))
  2801. (dloc (car vals))
  2802. (beg (cadr vals))
  2803. (end (caddr vals)))
  2804. (let ((osc (make-oscil :frequency freq))
  2805. (aenv (make-env :envelope amp-env :scaler amp :duration duration)))
  2806. (do ((i beg (+ i 1)))
  2807. ((= i end))
  2808. (dlocsig dloc i (* (env aenv) (oscil osc)))))))
  2809. (with-sound (:channels 2) (sinewave 0 1.0 440 .5 :path (make-path '((-10 10) (0.5 0.5) (10 10)) :3d #f)))
  2810. |#