(set-scale ) in my code didn't work because it was reserved for racket.
Changed it to (set-scala ) and now everything seem to work fine. Yuck,
nasty bug.
I'll stop spamming y'all with this idiot file!
Joel
; scala.scm, rev. 3
; 21/12/2011
; joel at matthysmusic dot com
;-------------------------------------------------------------------
; LOAD SCALA FILES INTO fluxus
; the basic keynumber->frequency function is
; (scala-note [keynum])
; by default, the function is set up for equal temperament, so
; (scala-note 60)
; > 261.6255653006
;
; This means key number 60 = 261.62... Hz
; * (scala-note also accepts lists of notes)
; There are a number of preset scale options:
;
; equal - equal temperament (12 notes)
; just - just intonation (12 notes)
; mean - meantone temperament (12 notes)
; pythag - diatonic pythagorean scale (7 notes)
; partch - Harry Partch scale (43 notes)
;
; To see the available scales:
; (list-scales)
;
; To change scales, use:
; (set-scala "scale-name")
; You can also change the base frequency (diapason) and keynumber with
; (set-diapason) and (set-base-keynum)
;
; Here, I choose the Pythagorean scale, set the diapason to 200 Hz and set
; the keynum to 0:
; (set-scala "pythag")
; (set-diapason 200)
; (set-base-keynum 0)
; (scala-note 0)
; > 200
; To load a scala file, use
; (load-scala-file "scalafilename.scl" "scale-nickname")
; * You choose a nickname to keep track of the scale.
; * If you don't choose a nickname, the scale will be
; * nicknamed "scala"
;
; You can find out the description of the file with:
; (scala-description)
;
; Example:
; (load-scala-file "scala/scl/bohlen-eg.scl" "bohlen")
; (set-scala "bohlen")
; (set-diapason 100)
; (set-base-keynum 0)
; (scala-note '(0 2 3 5 6 8 9 11 12 14 15))
; > (100 109.05... ... 436.203)
;
; By default, microtuning is on, allowing quarter-tones, etc. For instance,
; in equal temperament, (scala-note 60.5) is a quarter step above middle C.
; In scala scales, the frequency is linear interpolated; that is,
; (scala-note 60.5) returns the frequency halfway between notes 60 and 61.
; To disable microtuning, use:
; (set-scala-microtonal #f)
; Now all fractional values are rounded to the nearest integer.
;
;--------------------------------------------------------------------------
; CHANGES
;
; 20 Dec 2011 - created file
; fixed error with optional parameters
; 21 Dec 2011 - rev 2 - changed set-diapason-key to set-base-keynum
; changed global var names, eg diapson -> *diapason*
; created table lookup methods to reduce cpu load
; rev 3 - linear interpolation allows microtuning
; bugfix: set-scale already defined in racket, changed to
; set-scala
;--------------------------------------------------------------------------
; TO DO
;
; eliminate duplicate scale definition if scala file reloaded
;--------------------------------------------------------------------------
(define *scala-size* 12)
(define *scala* #f)
(define *scala-description* "12 note equal tempered scale")
(define *diapason* 261.6255653006)
(define *diapason-key* 60)
(define (set-diapason n)
(begin
(set! *diapason* n)
(fill-scala-table (- *diapason-key* 60) (+ *diapason-key* 67))))
(define (set-base-keynum n)
(begin
(set! *diapason-key* n)
(fill-scala-table (- *diapason-key* 60) (+ *diapason-key* 67))))
(define *scala-table* '())
(define *scala-microtonal* #t)
(define (set-scala-microtonal input)
(set! *scala-microtonal* input))
(define *scala-list* '(("equal"
"12 note equal tempered scale"
12
#f)
("just"
"12 note just intoned scale"
12
(1 16/15 9/8 6/5 5/4 4/3 45/32 3/2 8/5 5/3 9/5 15/8 2))
("mean"
"12 note meantone scale"
12
(1 1.069984 1.118034 1.196279 1.25 1.337481 1.397542
1.495349 1.5625 1.671851 1.746928 1.869186 2))
("pythag"
"7 note Pure Pythagorean scale"
7
(1 9/8 81/64 4/3 3/2 27/16 243/128 2))
("partch"
"43 note Harry Partch scale"
43
(1 81/80 33/32 21/20 16/15 12/11
11/10 10/9 9/8 8/7 7/6 32/27 6/5 11/9 5/4 14/11
9/7 21/16 4/3 27/20 11/8 7/5 10/7 16/11 40/27 3/2
32/21 14/9 11/7 8/5 18/11 5/3 27/16 12/7 7/4 16/9
9/5 20/11 11/6 15/8 40/21 64/33 160/81 2))))
(define (scala-description) *scala-description*)
(define (set-scala name [table 0])
(begin
(cond ((number? table) (set-scala name *scala-list*))
((null? table) ;end of list, so it must be equal temp
(begin (set! *scala* #f)
(set! *diapason* 261.6255653006)
(set! *diapason-key* 60)
(set! *scala-description* "12 note equal tempered scale")))
((equal? name (caar table))
(begin (set! *scala-size* (list-ref (car table) 2))
(set! *scala* (list-ref (car table) 3))
(set! *scala-description* (list-ref (car table) 1))))
(else (set-scala name (cdr table))))
(fill-scala-table (- *diapason-key* 60) (+ *diapason-key* 67))))
(define (scala-lint val low-source high-source low-target high-target)
(let ((norm-val (/ (- val low-source) (- high-source low-source))))
(+ low-target (* norm-val (- high-target low-target)))))
(define (scala-microtonal input)
(let* ((low-key (inexact->exact (floor input)))
(high-key (inexact->exact (ceiling input)))
(low-freq (parse-scale low-key))
(high-freq (parse-scale high-key)))
(scala-lint input low-key high-key low-freq high-freq)))
(define (parse-scale input)
(let ((keynum (if *scala-microtonal* input
(round input))))
(if (not *scala*)
; equal temperament
(* *diapason* (expt 2 (/ (- keynum *diapason-key*) 12)))
; else custom scale
(if (integer? keynum)
(let ((scale-degree (modulo (- keynum *diapason-key*) *scala-size*))
(scale-octave (floor (/ (- keynum *diapason-key*) *scala-size*))))
(* *diapason*
(expt (list-ref *scala* (- (length *scala*) 1))
scale-octave)
(list-ref *scala* scale-degree)))
(scala-microtonal keynum)))))
(define (parse-scala-file filename)
(begin
(let ((output '()))
(call-with-input-file filename
(lambda (input-port)
(let loop ((x (read-line input-port)))
(if (not (eof-object? x))
(begin
(set! output (append output
(list x)))
(loop (read-line input-port))) #t))))
output)))
(define (remove-comment-lines input [result '()])
(cond ((null? input) result)
((equal? #\! (string-ref (car input) 0))
(remove-comment-lines (cdr input) result))
(else (remove-comment-lines (cdr input)
(append result
(list (car input)))))))
(define (log10 n) (/ (log n) (log 10)))
(define (cents->ratio c)
(expt 10 (* c (/ (log10 2) 1200))))
(define (scala-intervals input-file [result '(1)])
(if (null? input-file)
result
(let ((test (scala-numberize (string->list (car input-file)))))
(if (number? test)
(scala-intervals (cdr input-file)
(append result
(list test)))
(scala-intervals (cdr input-file) result)))))
; ok, this is ugly, but basically (scala-numberize) converts a list of
; characters into a number
(define (scala-numberize input [found-number #f] [found-period #f] [result '()])
(cond ((null? input) ; end of list
(cond ((not found-number) #f) ; no number found; therefore a comment
(found-period (cents->ratio ; per scala documentation, . = cents
(string->number (list->string result))))
(else (string->number (list->string result))))) ; ratio
(else
(let* ((current-char (car input))
(char-val (- (char->integer current-char) 48)))
(cond ((and (not found-number)
(= char-val -16)) ; leading spaces get skipped
(scala-numberize (cdr input) #f #f result))
((and (not found-number)
(or (< char-val -3) (> char-val 9))) #f)
; if we find non-numbers at the
; beginning of a line, we assume it's a comment
(else
(scala-numberize (cdr input)
(or found-number ; have we found a number?
(and (>= char-val 0) (<= char-val 9)))
(or found-period ; does it have a period in it?
(= char-val -2))
(if (and (>= char-val -3) ; is it a number?
(<= char-val 9)) ; then add it to list
(append result (list current-char))
; otherwise, don't add it
result))))))))
(define (load-scala-file filename [new-name "scala"])
(let ((scale-definition '())
(scala-file '()))
(begin
(set! scala-file (remove-comment-lines (parse-scala-file filename)))
(set! scale-definition (list new-name ; scale name
(car scala-file) ; scale description
(scala-numberize
(string->list (list-ref scala-file 1)))
; scale size
(scala-intervals (cddr scala-file))))
(set! *scala-list* (append (list scale-definition) *scala-list*))
(set-scale new-name))))
(define (scala-note input [result '()])
(let ((test (find-in-table input *scala-table*)))
(cond (test test)
((number? input) (parse-scale input))
((null? input) result)
(else (scala-note (cdr input)
(append result
(list (scala-note (car input)))))))))
(define (list-scales [count 0] [result '()])
(if (= count (length *scala-list*)) result
(list-scales (+ 1 count)
(append result
(list (list-ref (list-ref *scala-list* count) 0))))))
(define (fill-scala-table low high [current #f] [result '()])
(cond ((not current) (fill-scala-table low high low '()))
((> current high)
(set! *scala-table* result))
(else (fill-scala-table low high (+ current 1)
(append result
(list (list current
(parse-scale current))))))))
(define (find-in-table num table)
(if (null? table) #f
(let ((result (member num (car table))))
(if (and (list? result)
(= 2 (length result)))
(list-ref result 1)
(find-in-table num (cdr table))))))
; default keynum->frequency table (equal temperament)
(define *scala-table* '((0 8.17579891564375) (1 8.661957218027297)
(2 9.177023997419036) (3 9.722718241315079) (4 10.300861153527237)
(5 10.91338223228143) (6 11.562325709738635) (7 12.249857374429727)
(8 12.978271799373355) (9 13.75) (10 14.567617547440383)
(11 15.43385316425396) (12 16.3515978312875) (13 17.323914436054597)
(14 18.354047994838066)
(15 19.445436482630157)
(16 20.601722307054477)
(17 21.826764464562853)
(18 23.12465141947727)
(19 24.49971474885946)
(20 25.956543598746702)
(21 27.5)
(22 29.135235094880773)
(23 30.867706328507914)
(24 32.703195662575)
(25 34.647828872109194)
(26 36.70809598967613)
(27 38.890872965260314)
(28 41.20344461410895)
(29 43.653528929125706)
(30 46.24930283895454)
(31 48.99942949771892)
(32 51.913087197493404)
(33 55)
(34 58.27047018976155)
(35 61.73541265701583)
(36 65.40639132515)
(37 69.29565774421839)
(38 73.41619197935228)
(39 77.78174593052063)
(40 82.4068892282179)
(41 87.30705785825143)
(42 92.49860567790908)
(43 97.99885899543783)
(44 103.82617439498682)
(45 110)
(46 116.54094037952308)
(47 123.47082531403167)
(48 130.8127826503)
(49 138.59131548843678)
(50 146.83238395870455)
(51 155.56349186104126)
(52 164.8137784564358)
(53 174.61411571650285)
(54 184.99721135581817)
(55 195.99771799087566)
(56 207.65234878997364)
(57 220)
(58 233.08188075904616)
(59 246.94165062806334)
(60 261.6255653006)
(61 277.18263097687355)
(62 293.6647679174091)
(63 311.1269837220825)
(64 329.6275569128716)
(65 349.2282314330057)
(66 369.99442271163633)
(67 391.9954359817513)
(68 415.30469757994723)
(69 440)
(70 466.1637615180923)
(71 493.88330125612663)
(72 523.2511306012)
(73 554.3652619537471)
(74 587.3295358348182)
(75 622.253967444165)
(76 659.2551138257433)
(77 698.4564628660114)
(78 739.9888454232727)
(79 783.9908719635026)
(80 830.6093951598946)
(81 880)
(82 932.3275230361846)
(83 987.7666025122534)
(84 1046.5022612024)
(85 1108.7305239074942)
(86 1174.6590716696362)
(87 1244.50793488833)
(88 1318.5102276514865)
(89 1396.9129257320226)
(90 1479.9776908465453)
(91 1567.9817439270055)
(92 1661.218790319789)
(93 1760)
(94 1864.6550460723695)
(95 1975.5332050245065)
(96 2093.0045224048)
(97 2217.4610478149884)
(98 2349.3181433392724)
(99 2489.01586977666)
(100 2637.020455302973)
(101 2793.825851464045)
(102 2959.9553816930907)
(103 3135.963487854011)
(104 3322.437580639578)
(105 3520)
(106 3729.310092144739)
(107 3951.066410049013)
(108 4186.0090448096)
(109 4434.922095629976)
(110 4698.636286678547)
(111 4978.03173955332)
(112 5274.040910605945)
(113 5587.651702928092)
(114 5919.910763386181)
(115 6271.92697570802)
(116 6644.8751612791575)
(117 7040)
(118 7458.620184289476)
(119 7902.132820098028)
(120 8372.0180896192)
(121 8869.844191259952)
(122 9397.272573357093)
(123 9956.06347910664)
(124 10548.08182121189)
(125 11175.303405856184)
(126 11839.821526772363)
(127 12543.85395141604)))