Created
January 25, 2015 16:54
-
-
Save whacked/2c6a74e65505e7d2c80d to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(defn collect-into-consecutive | |
"collect indexes into sets of N consecutive indexes, | |
discarding all other indexes. | |
N defaults to 6 (for guitar tabs)" | |
([index-list] | |
(collect-into-consecutive index-list 6)) | |
([index-list required-length] | |
(loop [input (sort index-list) | |
buf [] | |
rtn []] | |
(let [next-rtn (if (= required-length (count buf)) | |
(conj rtn buf) | |
rtn)] | |
(if (empty? input) | |
next-rtn | |
(let [last-val (last buf) | |
cur-val (first input)] | |
(recur (rest input) | |
(if (or (nil? last-val) | |
(= required-length (count buf)) | |
(not= 1 (- cur-val last-val))) | |
[cur-val] | |
(conj buf cur-val)) | |
next-rtn))))))) | |
;; http://stackoverflow.com/questions/21191045/get-string-indices-from-the-result-of-re-seq | |
(defn re-seq-pos [pattern string] | |
(let [m (re-matcher pattern string)] | |
((fn step [] | |
(when (. m find) | |
(cons {:start (. m start) :end (. m end) :group (. m group)} | |
(lazy-seq (step)))))))) | |
(defn parse-guitar-tab-line | |
"reads a single well-formed line from the guitar tab | |
and returns a seq of seq, where each inner seq takes the form of | |
[index fret-value] | |
index = at what index in time the pluck should occur | |
fret-value = being which fret to pluck; nil if it should be rest | |
" | |
[line] | |
(sort | |
(seq | |
(let [ ;; note: drop-while predicate needs a char (\-), not a string ("-")! | |
tab-string (apply str (drop-while #(not= % \-) line))] | |
(into | |
(zipmap (range (count tab-string)) (repeatedly (constantly nil))) | |
(map | |
(fn [match-group] | |
[(:start match-group) (Integer/parseInt (:group match-group))]) | |
(re-seq-pos #"\d+" tab-string))))))) | |
(def everybody-hurts | |
" | |
;; Guitar Tab for Everybody Hurts by REM | |
;; | |
;; D G | |
;; E:5]--------2-----------2------------3-----------3-----[ | |
;; B:4]------3---2-------3---3--------0---0-------0---0---[ | |
;; G:3]----2-------2---2-------2----0-------0---0-------0-[ | |
;; D:2]--0-----------0------------------------------------[ | |
;; A:1]---------------------------------------------------[ | |
;; E:0]---------------------------3-----------3-----------[ | |
") | |
(defn play-tab | |
[guitar-tab] | |
(let [pluck-map-list (let [index-mapped (filter | |
;; a tab line must contain "-" | |
(fn [[_ s]] (.contains s "-")) | |
(into {} (map-indexed vector (s/split-lines guitar-tab)))) | |
index-group-list (collect-into-consecutive (keys index-mapped)) | |
] | |
;; from the 6-line groups, get lines from the original index-line maps | |
(let [sorted-grouped-line-set-list (map #(vals (sort (select-keys (into {} index-mapped) %))) | |
;; these will be grouped into sets of 6 lines, with indexes | |
(sort index-group-list))] | |
;; map over each 6-line-set... | |
(->> sorted-grouped-line-set-list | |
;; map over each line within the set... | |
(map (fn [line-set] | |
(apply merge-with concat | |
(map-indexed | |
(fn [string-index tab-line] | |
(into {} | |
(remove nil? | |
(->> tab-line | |
(parse-guitar-tab-line) | |
(map (fn [[index fret-value]] | |
(if fret-value | |
[index [string-index fret-value]]))))))) | |
(reverse line-set)))))))) | |
play! (partial guitar-pick-note-sequence' 100) | |
] | |
(play! | |
(apply | |
concat | |
(->> pluck-map-list | |
(map | |
(fn [pluck-map] | |
(let [max-beat (apply max (keys pluck-map))] | |
(map seq (remove nil? (map pluck-map (range max-beat)))) | |
)))))))) | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment