           intervals, etc."
      :author "Jeff Rose, Sam Aaron & Marius Kempe"}
   overtone.music.pitch
-  (:use [overtone.util old-contrib]
+  (:use [clojure.string :only [capitalize]]
+        [overtone.util old-contrib]
         [overtone.algo chance])
   (:require [clojure.string :as string]))
 

            :G# 8  :g# 8  :Ab 8  :ab 8  :AB 8  :aB 8
            :A  9  :a  9
            :A# 10 :a# 10 :Bb 10 :bb 10 :BB 10 :bB 10
            :B  11 :b  11 :Cb 11 :cb 11 :CB 11 :cB 11
})

(def REVERSE-NOTES
  (into {} (map (fn [[k v]] [v k]) NOTES)))

(def MIDI-NOTE-RE-STR "([a-gA-G][#bB]?)([-0-9]+)" )
(def MIDI-NOTE-RE (re-pattern MIDI-NOTE-RE-STR))
(def ONLY-MIDI-NOTE-RE (re-pattern (str "\\A" MIDI-NOTE-RE-STR "\\Z")))


(defn note
  "Resolves note to MIDI number format. Resolves upper and lower-case keywords

   (integer? n) (if (>= n 0)
                    n
                    (throw (IllegalArgumentException.
                            (str "Unable to resolve note: "
                                 n
                                 ". Value is out of range. Lowest value is 0"))))
   (keyword? n) (note (name n))
   (string? n) (let [match (re-find ONLY-MIDI-NOTE-RE n)
                     _ (when (nil? match)
                         (throw (IllegalArgumentException.
                                 (str "Unable to resolve note: "
                                      n
                                      ". Does not appear to be in MIDI format i.e. C#4"))))
                     note-match (parse-note-match match)
                     _ (when (< (:octave note-match) -1)
                         (throw (IllegalArgumentException.
                                 (str "Unable to resolve note: "
                                      n
                                      ". Octave is out of range. Lowest octave value is -1"))))]
                 (:midi-note note-match))
   :else (throw (IllegalArgumentException. (str "Unable to resolve note: " n ". Wasn't a recognised format (either an integer, keyword, string or nil)")))))

(defn match-note
  "Returns the first midi-note formatted substring in s. If passed optional prev
   and pos strings will use them to generate positive look ahead and behind
   matchers. "
  ([s] (match-note s "" ""))
  ([s prev-str post-str]
     (let [look-behind (if prev-str (str "(?<=" prev-str ")") "")
           look-ahead (if post-str (str "(?=" post-str ")") "")
           match (re-find (re-pattern (str look-behind MIDI-NOTE-RE-STR look-ahead)) s)]
       (when match
         (parse-note-match match)))))



;; * Each note in a scale acts as either a generator or a collector of other notes,
;; depending on their relations in time within a sequence.
