note.scm 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  1. (require)
  2. (export scientificnote->integer
  3. ;; integer->scientificnote
  4. integer->lilynote
  5. ;; lilynote->integer
  6. scientificnote->lilynote
  7. )
  8. ;; representation 1: integers
  9. ;; This could also be called AbsPitch, as in
  10. ;; https://github.com/Euterpea/EuterpeaLite/blob/master/EuterpeaLite/Music.lhs
  11. ;; representation 2: scientificnote (symbols) c4
  12. ;; https://en.wikipedia.org/wiki/Scientific_pitch_notation
  13. '(define (integer->scientificnote i)
  14. )
  15. (define (scientificnote-parse-base str)
  16. (if (string-empty? str)
  17. 0
  18. (let ((n (string->number str)))
  19. (if (and n
  20. (integer? n)
  21. (>= n 0))
  22. n
  23. (error "invalid scientific note base:" str)))))
  24. (define scientificnote-subs
  25. '(C CS D DS E F FS G GS A AS B))
  26. (define lilynote-subs-vector
  27. (list->vector (map (lambda (sym)
  28. (string-lc (symbol->string sym)))
  29. scientificnote-subs)))
  30. (define scientificnote-sub-alis
  31. (map cons
  32. scientificnote-subs
  33. (iota 12)))
  34. (define (scientificnote-parse-sub ch)
  35. (cond ((assq (string->symbol ch) scientificnote-sub-alis)
  36. => cdr)
  37. (else
  38. (error "invalid scientificnote sub:" ch))))
  39. (define (scientificnote->integer sym)
  40. (let* ((s (symbol->string sym))
  41. (len (string-length s)))
  42. (if (>= len 1)
  43. (let lp ((i 0))
  44. (if (< i len)
  45. (let ((c (string-ref s i)))
  46. (if (char-digit? c)
  47. (+ (scientificnote-parse-sub (substring s 0 i))
  48. (* 12
  49. (scientificnote-parse-base (substring s i len)))
  50. -48)
  51. (lp (inc i))))
  52. (+ (scientificnote-parse-sub (substring s 0 i)) (* 12 4) -48)
  53. ;; or:
  54. ;; (error "scientificnote without octave not accepted for not"
  55. ;; sym)
  56. ))
  57. (error "invalid scientificnote:" sym))))
  58. (TEST
  59. > (scientificnote->integer 'C3)
  60. -12
  61. > (scientificnote->integer 'C4)
  62. 0
  63. > (scientificnote->integer 'C5)
  64. 12
  65. > (scientificnote->integer 'C3)
  66. -12
  67. > (scientificnote->integer 'CS3)
  68. -11)
  69. ;; representation 3: lily note string
  70. (define (integer->quotient+remainder i d)
  71. (values (quotient i d)
  72. (remainder i d)))
  73. (define (quotient+remainer->integer q r d)
  74. (+ (* q d) r))
  75. (define (flub i d)
  76. "the whole part of the division of i by d, but in a way that it fits
  77. modulo--?"
  78. (if (negative? i)
  79. (dec (quotient (inc i) d))
  80. (quotient i d)))
  81. (TEST
  82. > (flub 12 12)
  83. 1
  84. > (flub 11 12)
  85. 0
  86. > (flub 10 12)
  87. 0
  88. > (flub 0 12)
  89. 0
  90. > (flub -1 12)
  91. -1
  92. > (flub -10 12)
  93. -1
  94. > (flub -11 12)
  95. -1
  96. > (flub -12 12)
  97. -1
  98. > (flub -13 12)
  99. -2)
  100. (define (integer->flub+modulo i d)
  101. (values (flub i d)
  102. (modulo i d)))
  103. (define (flub+modulo->integer q r d)
  104. (+ (* q d) r))
  105. (define (lilynote-base-format i)
  106. (cond ((= i 4) "")
  107. ((< i 4) (make-string (- 4 i) #\,))
  108. (else (make-string (- i 4) #\'))))
  109. (define (integer->lilynote i)
  110. (string-append
  111. (vector-ref lilynote-subs-vector (modulo i 12))
  112. (let ((f (flub i 12)))
  113. (if (or (= i -1) (= i -12)) ;; ridiculous
  114. ""
  115. (lilynote-base-format (+ 5 f))))))
  116. (TEST
  117. > (integer->lilynote 1)
  118. "cs'"
  119. > (integer->lilynote 0)
  120. "c'"
  121. > (integer->lilynote -1)
  122. "b"
  123. > (integer->lilynote -2)
  124. "as"
  125. > (integer->lilynote -12)
  126. "c"
  127. > (integer->lilynote -13)
  128. "b,"
  129. > (map integer->lilynote (iota 16 -37))
  130. ("b,,,"
  131. "c,,"
  132. "cs,,"
  133. "d,,"
  134. "ds,,"
  135. "e,,"
  136. "f,,"
  137. "fs,,"
  138. "g,,"
  139. "gs,,"
  140. "a,,"
  141. "as,,"
  142. "b,,"
  143. "c,"
  144. "cs,"
  145. "d,")
  146. > (map integer->lilynote (iota 20 -3))
  147. ("a"
  148. "as"
  149. "b"
  150. "c'"
  151. "cs'"
  152. "d'"
  153. "ds'"
  154. "e'"
  155. "f'"
  156. "fs'"
  157. "g'"
  158. "gs'"
  159. "a'"
  160. "as'"
  161. "b'"
  162. "c''"
  163. "cs''"
  164. "d''"
  165. "ds''"
  166. "e''"))
  167. ;; (define (lilynote->integer str)
  168. ;; )
  169. (define scientificnote->lilynote
  170. (=>* scientificnote->integer integer->lilynote))
  171. (TEST
  172. > (scientificnote->lilynote 'C3)
  173. "c"
  174. > (scientificnote->lilynote 'C4)
  175. "c'")