Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Revert "Merge pull request #98 from forsakendaemon/master"

This reverts commit f58f1c2, reversing
changes made to 890035a.

Conflicts:
	src/overtone/music/tuning.clj
	src/overtone/music/tuning/scala.clj
	test/etc/12highschool.scl

On further inspection, this pull request needs further work and clean up to be ready for a full release and future maintanence.
  • Loading branch information...
commit 2d754ea98b0eb5c8a61a2f9191c9ebd9644c4e2d 1 parent df78f40
@samaaron samaaron authored
View
191 src/overtone/music/tuning.clj
@@ -2,8 +2,7 @@
^{:doc "Functions that define tuning systems from various musical traditions and theories."
:author "Jeff Rose"}
overtone.music.tuning
- (:use [overtone.music.pitch]
- [clojure.math.numeric-tower]))
+ (:use [overtone.music pitch]))
;; TODO: Not only should we pre-compute the frequency values for standard tunings,
;; but it would be cool to let people explore different tunings while creating
@@ -23,194 +22,6 @@
;; 12-tone equal temperament --> Western music
;; ratio = (Math/pow 2 (/ 1 12)) => 1.0594630943592953
-;; (perform '((:edo 12 100 440) 73 76 79))
-;; (perform '(:midi 60 69 81))
;; 24-tone equal temperament --> Arabic music
;; ratio = (Math/pow 2 (/ 1 24)) => 1.029302236643492
-;; (perform '((:arabic 100 440) 73 76 79))
-
-
-
-;; Helper Functions
-(defn- list-flatten-first
- [x]
- (first (flatten (list x))))
-
-(defn- get-or-fn
- [map key func]
- (if-let [result (map key)]
- result
- (func key)))
-
-(defn- map-or-fn
- [m keys func]
- (map #(get-or-fn m % func) keys))
-
-(defn- perfmap
- [note initial freq notemap]
- (let [pos (mod (- note initial) (count notemap))
- octave (quot (- note initial (- (count notemap) 1 )) (count notemap))]
- (* freq (nth notemap pos) (expt (ceil (reduce max notemap)) octave))))
-
-(defn- collapse-to-ntave
- [number ntave]
- (condp > number
- 1 (recur (* number ntave) ntave)
- ntave number
- (recur (/ number ntave) ntave)))
-
-(defn- note-set-from-generator
- [generator initpower finpower ntave]
- (let [tempset (for [exponent (range initpower finpower)] (expt generator exponent))]
- (sort (map #(collapse-to-ntave % ntave) tempset))))
-
-(defn- parsemodifiers
- "Parses standard modifiers b, #, es, eh, ih and is for note names.
- Returns shifts where 1 is equivalent to a semitone.
-
- Please note that this function fails spectacularly when asked to
- parse anything but standard Western and Arabic music. That is,
- anything that doesn't equate sharp and tone + flat, or halfsharp and
- semitone + halfflat."
- [modifiers]
- (let [matches (map first (concat (re-seq #"([ie][sh])" modifiers) (re-seq #"([b#])" modifiers)))]
- (+
- (- (count (filter #(= "b" %) matches)))
- (- (count (filter #(= "es" %) matches)))
- (* -0.5 (count (filter #(= "eh" %) matches)))
- (* 0.5 (count (filter #(= "ih" %) matches)))
- (count (filter #(= "is" %) matches))
- (count (filter #(= "#" %) matches)))))
-
-(def ^:private lilypondpattern (re-pattern "([a-gA-G])([#bB(is)(ih)(es)(eh)]*)([-0-9]+)"))
-
-;; Public Face - the tuning multimethods.
-
-(defmulti perfn
- "Multimethod that returns a function taking note numbers to
- frequencies in \\s^{-1}\\"
- list-flatten-first)
-
-(defmulti tunednotes
- "Multimethod that returns a function taking note keywords to note numbers.
-
- A note keyword is usually of the
- form :[notename][pitchmodifiers][ntave], for example, :A4, :cb6
- or :Bbb0, however this is entirely dependent on the kind of scale.
-
- Tunednotes functions should ideally return nonmatching symbols or
- numbers unmodified. Particularly numbers, which could be note
- numbers.
-
- When using keywords of the form :c[modifier]0, :c0 should be mapped
- to [initial]. This is purely arbitrary, but it makes me feel good in
- my happy place. Convention over configuration, bitchez."
- list-flatten-first)
-
-(defmulti reversenotes
- "Multimethod that returns a function taking note numbers to note
- symbols."
- list-flatten-first)
-
-(defn perform [[opts & notes]]
- "Takes a set of options and a list of note numbers/keywords, and runs
- the notes through the appropriate tuning system to give frequencies."
- (map (perfn opts) (map-or-fn (tunednotes opts) notes identity)))
-
-(defn canonical-note-names [argz]
- "Returns a function that takes note names to their canonical selves
- within the relevant tuning system."
- (fn [note]
- ((reversenotes argz) ((tunednotes argz) note))))
-
-
-;;Implementation of some tuning systems.
-
-(defmethod perfn :ed [[_ divisions multiplier initial freq]]
- "Divides a multiplier-tave (e.g. 2-tave = octave, 3-tave, &c.) into
- divisions divisions. Maps initial to a note with frequency freq."
- (fn [note]
- (* freq (Math/pow multiplier (/ (- note initial) divisions)))))
-
-(defmethod perfn :edo [[_ divisions initial freq]]
- "Equal divisions of the octave."
- (perfn (list :ed divisions 2 initial freq)))
-
-(defmethod perfn :midi [_]
- (perfn (list :edo 12 69 440)))
-
-(defmethod tunednotes :midi [_]
- "Returns a function that resolves notes to MIDI number format.
- Resolves upper and lower-case keywords and strings in MIDI note
- format. If given a string or keyword in a different format, throws an
- exception. Anything else is returned unmodified.
-
- Usage examples:
- ((tunednotes :midi) :F#7) ;=> 102
- ((tunednotes :midi) :db5) ;=> 73"
- (fn [n]
- (if (or (keyword? n) (string? n))
- (let [match (re-find (re-pattern "([a-gA-G])([#bB]*)([-0-9]+)") (name n))
- _ (when (nil? match)
- (throw (IllegalArgumentException.
- (str "Unable to resolve note: " n ". Does not appear to be in MIDI format i.e. C#4"))))
- [_ pitchclass modifiers octavestr] match
- shift (parsemodifiers modifiers)
- octave (Integer. octavestr)
- _ (when (< octave -1)
- (throw (IllegalArgumentException.
- (str "Unable to resolve note: " n ". Octave is out of range. Lowest octave value for midi is -1"))))]
- (+ (get {"c" 0, "d" 2, "e" 4, "f" 5, "g" 7, "a" 9, "b" 11} (clojure.string/lower-case pitchclass))
- (int (floor shift))
- (* 12 octave)
- 12))
- n)))
-
-(defmethod reversenotes :midi [_]
- (fn [note]
- (let [degree (rem note 12)
- octave (- (floor (/ note 12)) 1)
- _ (when (< octave -1)
- (throw (IllegalArgumentException.
- (str "Unable to resolve note: " note ". Octave is out of range. Lowest octave value for midi is -1"))))]
- (keyword (str (nth '("c" "c#" "d" "d#" "e" "f" "f#" "g" "g#" "a" "a#" "b") degree) octave)))))
-
-(defmethod perfn :default [_]
- (perfn :midi))
-
-(defmethod tunednotes :default [_]
- (tunednotes :midi))
-
-
-;; Some other tuning systems
-
-(defmethod perfn :arabic [[symb initial freq]]
- (perfn (list :edo 24 initial freq)))
-
-(defmethod tunednotes :arabic [[symb initial _]]
- (fn [n]
- (if (or (keyword? n) (string? n))
- (let [match (re-find lilypondpattern (name n))
- _ (when (nil? match)
- (throw (IllegalArgumentException.
- (str "Unable to resolve note: " n ". Does not appear to be in Arabic format i.e. C#4"))))
- [_ pitchclass modifiers octavestr] match
- shift (parsemodifiers modifiers)
- octave (Integer. octavestr)]
- (int (+ (* 2 (get {"c" 0, "d" 2, "e" 4, "f" 5, "g" 7, "a" 9, "b" 11} (clojure.string/lower-case pitchclass)))
- (* 2 shift)
- (* 24 octave)
- initial)))
- n)))
-
-(defmethod reversenotes :arabic [[symb initial _]]
- (fn [n]
- (let [note (- n initial)
- degree (rem note 24)
- octave (floor (/ note 24))]
- (keyword (str (nth '("c" "cih" "c#" "deh" "d" "dih" "d#" "eeh" "e" "eih" "f" "fih" "f#" "geh" "g" "gih" "g#" "aeh" "a" "aih" "a#" "beh" "b" "ceh") degree) octave)))))
-
-(defmethod perfn :qcmeantone [[symb initial freq]]
- (fn [note]
- (perfmap note initial freq (note-set-from-generator (expt 5 1/4) -5 7 2))))
View
43 src/overtone/music/tuning/edo_31.clj
@@ -1,43 +0,0 @@
-(ns overtone.music.tuning.edo-31
- (:use [overtone.music.tuning]
- [overtone.music.pitch]
- [clojure.java.io]
- [clojure.set]
- [clojure.math.numeric-tower]))
-
-;(defmethod tunednotes :edo-31 [symb]
-; (fn [note-name]
-; (let [symbol (.toLowerCase (name note-name)) ; TODO This should be (lower-case x)
-; note (first symbol)
-; modifier (rest symbol)]
-; (mod (+ (get {\c 0, \d 5, \e 10, \f 13, \g 18, \a 23, \b 28} note)
-; (* -2 (count (filter #(= \b %) modifier)))
-; (* 2 (count (filter #(= \# %) modifier)))) 31)))
-
-(defmethod reversenotes :edo-31 [[symb initial _]] ; TODO This function doesn't effing work.
- (fn [notenumber] (get {0 :c, 1 :dbb, 2 :c#, 3 :db, 4 :c##,
- 5 :d, 6 :ebb, 7 :d#, 8 :eb, 9 :d##,
- 10 :e, 11 :fb, 12 :e#,
- 13 :f, 14 :gbb, 15 :f#, 16 :gb, 17 :f##,
- 18 :g, 19 :abb, 20 :g#, 21 :ab, 22 :g##,
- 23 :a, 24 :bbb, 25 :a#, 26 :bb, 27 :a##,
- 28 :b, 29 :cb, 30 :b#} notenumber)))
-
-(defmethod perfn :edo-31 [[symb initial freq]]
- (perfn (list :edo 31 initial freq)))
-
-(defmethod tunednotes :edo-31 [[symb initial _]]
- (fn [n]
- (if (or (keyword? n) (string? n))
- (let [match (re-find lilypondpattern (name n))
- _ (when (nil? match)
- (throw (IllegalArgumentException.
- (str "Unable to resolve note: " n ". Does not appear to be in Quarter-Tone Meantone format i.e. C#4"))))
- [_ pitchclass modifiers octavestr] match
- shift (* 2 (floor (parsemodifiers modifiers)))
- octave (Integer. octavestr)]
- (+ (get {"c" 0, "d" 5, "e" 10, "f" 13, "g" 18, "a" 23, "b" 28} (clojure.string/lower-case pitchclass))
- (int (floor shift))
- (* 31 octave)
- 31))
- n)))
View
43 src/overtone/music/tuning/scala.clj
@@ -1,43 +0,0 @@
-(ns
- ^{:doc "Functions that allow use of the Scala scale definition format."
- :author "David \"DAemon\" Allen"}
- overtone.music.tuning.scala
- (:use [overtone.music.tuning]
- [overtone.music.pitch]
- [clojure.java.io]
- [clojure.set]
- [clojure.math.numeric-tower]))
-
-(defn- comment? [line]
- (= (first line) \!))
-
-(defn- parse-scala-line [line]
- (cond
- ;(comment? line) nil ;{:comment (rest line)}
- (re-find #"([0-9]+)/([0-9]+).*" line) (let [results (re-find #"([0-9]+)/([0-9]+)" line)] {:noteratio (/ (Integer/parseInt (nth results 1)) (Integer/parseInt (nth results 2)))})
- (re-find #"([0-9]+\.[0-9]+).*" line) (let [result (re-find #"([0-9]+\.[0-9]+).*" line)] {:noteratio (cents 1 (Float/parseFloat (nth result 1)))})
- (re-find #"([0-9]+)" line) (let [result (re-find #"([0-9]+)" line)] {:noteratio (Integer/parseInt (nth result 1))})
- :else (throw (Exception. (str "Failed to parse Scala file" line)))))
-
-(defn- to-set [s]
- (if (set? s) s #{s}))
-
-(defn- set-union [s1 s2]
- (union (to-set s1) (to-set s2)))
-
-(defn loadscale [path]
- (with-open [rdr (reader path)]
- (let [lines (filter (complement comment?) (doall (line-seq rdr)))
- description (first lines)
- number-of-notes (second lines)
- notes (rest (rest lines))]
- (reduce #(merge-with set-union %1 %2) {:description description :number-of-notes number-of-notes :noteratio 1} (map parse-scala-line notes)))))
-
-(defn note-set-from-scala [path]
- (let [notes (:noteratio (loadscale path))
- max (ceil (reduce max notes))]
- (sort (apply list (set (map #(collapse-to-ntave % max) notes))))))
-
-(defmethod perfn :scala [[symb path initial freq]]
- (fn [note]
- (perfmap note initial freq (note-set-from-scala path))))
View
17 test/etc/12highschool.scl
@@ -1,17 +0,0 @@
-! Example Scala file to use for testing.
-! See http://www.huygens-fokker.org/scala/scl_format.html for more information on Scala.
-First 12-note Highschool scale
-12
-!
-21/20
-9/8
-6/5
-5/4
-4/3
-7/5
-3/2
-8/5
-5/3
-7/4
-15/8
-2
View
59 test/overtone/tuning_test.clj
@@ -1,59 +0,0 @@
-(ns overtone.tuning-test
- (:require [overtone.util.log :as log])
- (:use overtone.music.tuning
- clojure.test
- overtone.music.tuning.edo-31))
-
-(deftest helper-test
- (let [testlist '(:1 :b "3" "d" ("e" "f" \g \h))
- testmap '{:1 "1", :b 2, "3" 3, :d "4" }]
-
- (is (= (list-flatten-first testlist) (list-flatten-first :1) :1))
- (is (= (get-or-fn testmap :b 0) 2))
- (is (= (get-or-fn testmap "a" clojure.string/capitalize) "A"))
- (is (= (map-or-fn testmap testlist identity) '("1" 2 3 "d" ("e" "f" \g \h))))))
-
-(deftest midi-test
- (is (= (perform '(:midi 60 69 81)) '(261.6255653005986 440.0 880.0)) "Sanity check for MIDI note numbers")
- (is (= ((tunednotes :midi) :F#7) 102) "sanity check for tuned notes function.")
- (is (= ((tunednotes :midi) :F##7) 103))
- (is (= ((tunednotes :midi) :F##bb#7) 102) "Demonstration of collapsing sharps and flats. Really tests parsemodifiers.")
- (is (= ((tunednotes :midi) :db5) 73))
- (is (= ((reversenotes :midi) 73) :c#5) "Sanity check for reverse notes function.")
- (is (= ((reversenotes :midi) 102) :f#7))
- (is (= ((reversenotes :midi) ((tunednotes :midi) :F#7)) :f#7) "This combination takes note names to their canonical versions.")
- (is (= ((reversenotes :midi) ((tunednotes :midi) :F##bb#7)) :f#7))
- (is (= ((canonical-note-names :midi) :F##bb#7)) :f#7) "Which is why there is a simplified version of it.")
-
-(deftest ed-test
- (let [perfunc (perfn '(:ed 10 10 0 100))]
- (is (< (#(- (reduce max %) (reduce min %))
- (list (/ (perfunc 101) (perfunc 100))
- (/ (perfunc 51) (perfunc 50))
- (/ (perfunc 28) (perfunc 27))
- (/ (perfunc 1) (perfunc 0)))) 0.0000000001) "Frequency values should scale properly, but are floats so should not be used for equality.")
- (is (= (perfunc 0) 100.0))
- (is (= (perfunc 10) 1000.0) "Note that equal divions doesn't imply an octave.")))
-
-(deftest edo-test
- (let [perfunc (perfn '(:edo 10 0 100))]
- (is (< (#(- (reduce max %) (reduce min %))
- (list (/ (perfunc 101) (perfunc 100))
- (/ (perfunc 51) (perfunc 50))
- (/ (perfunc 28) (perfunc 27))
- (/ (perfunc 1) (perfunc 0)))) 0.0000000001))
- (is (= (perfunc 0) 100.0))
- (is (= (perfunc 10) 200.0))))
-
-(deftest edo-12-test
- (is (= (perform '((:edo 12 100 440) 73 76 79)) '(92.49860567790861 110.0 130.8127826502993))))
-
-(deftest edo-31-test
- (let [perfunc (perfn '(:edo-31 0 100))]
- (is (< (#(- (reduce max %) (reduce min %))
- (list (/ (perfunc 101) (perfunc 100))
- (/ (perfunc 51) (perfunc 50))
- (/ (perfunc 28) (perfunc 27))
- (/ (perfunc 1) (perfunc 0)))) 0.0000000001))
- (is (= (perfunc 0) 100.0))
- (is (= (perfunc 31) 200.0)))) ; TODO Add test coverage for 31-edo reversenotes.
Please sign in to comment.
Something went wrong with that request. Please try again.