diff --git a/test/why_does_that_sound_good/algo/chord_test.cljc b/test/why_does_that_sound_good/algo/chord_test.cljc index afdf138..c575613 100644 --- a/test/why_does_that_sound_good/algo/chord_test.cljc +++ b/test/why_does_that_sound_good/algo/chord_test.cljc @@ -1,14 +1,38 @@ (ns why-does-that-sound-good.algo.chord-test - (:require [clojure.test :refer [deftest is are]] - [why-does-that-sound-good.algo.chord :as chord])) + (:require + [clojure.test :refer [deftest are]] + [why-does-that-sound-good.pitch :as pitch] + [why-does-that-sound-good.algo.chord :as chord])) (deftest find-closest-octave-test - (is (= 4 (chord/find-closest-octave :C 60))) - (is (= 3 (chord/find-closest-octave :B 60)))) + (are [pitch closest-note expected-closest-octave] (= expected-closest-octave (chord/find-closest-octave pitch closest-note)) + :C (pitch/note :C4) 4 + :B (pitch/note :C4) 3)) (deftest get-relative-chord-notes-test - (are [expected-notes original-notes chord-pitches] (= expected-notes (chord/get-relative-chord-notes original-notes chord-pitches)) - '(60 64 67) [60 64 67] #{:C :E :G} - '(60 64 67 71) [60 64 67] #{:C :E :G :B} - '(60 64 67) [60 64 67 71] #{:C :E :G} - '(60 64 67 72) [60 64 67 72] #{:C :E :G})) + (are [original-notes chord-pitches expected-notes] (= expected-notes (chord/get-relative-chord-notes original-notes chord-pitches)) + [60 64 67] #{:C :E :G} '(60 64 67) + [60 64 67] #{:C :E :G :B} '(60 64 67 71) + [60 64 67 71] #{:C :E :G} '(60 64 67) + [60 64 67 72] #{:C :E :G} '(60 64 67 72))) + +(deftest block->chords-test + (are [block expected-chords] (= expected-chords (chord/block->chords block :find-closest? true)) + {:id 1 :notes #{60 64 67}} '({:root :C + :chord-type :maj + :chord-pitches #{:C :G :E} + :similarity 1 + :original-block-id 1 + :lowest-note-root? 1 + :chord-pitches->readable-intervals {:C :1 :G :5 :E :M3} + :chord-notes (60 64 67)} + {:root :E + :chord-type :m+5 + :chord-pitches #{:E :G :C} + :similarity 1 + :original-block-id 1 + :lowest-note-root? 0 + :chord-pitches->readable-intervals {:E :1 :G :m3 :C :+5} + :chord-notes (60 64 67)}) + + {:id 1 :notes #{}} nil)) diff --git a/test/why_does_that_sound_good/algo/scale_test.cljc b/test/why_does_that_sound_good/algo/scale_test.cljc index 4b1f590..dc12561 100644 --- a/test/why_does_that_sound_good/algo/scale_test.cljc +++ b/test/why_does_that_sound_good/algo/scale_test.cljc @@ -1,22 +1,21 @@ (ns why-does-that-sound-good.algo.scale-test - (:require [clojure.test :refer [deftest testing is are]] - [why-does-that-sound-good.algo.scale :as scale] - [why-does-that-sound-good.pitch :as pitch] - [why-does-that-sound-good.algo.chord :as chord])) + (:require + [clojure.test :refer [deftest testing is are]] + [why-does-that-sound-good.algo.scale :as scale])) (deftest steps->intervals-test - (are [expected-intervals input-steps] (= expected-intervals (scale/steps->intervals input-steps)) - '(0) () - '(0 1 3 6) '(1 2 3) - '(0 2 4 5 7 9 11 12) '(2 2 1 2 2 2 1))) + (are [input-steps expected-intervals] (= expected-intervals (scale/steps->intervals input-steps)) + () '(0) + '(1 2 3) '(0 1 3 6) + '(2 2 1 2 2 2 1) '(0 2 4 5 7 9 11 12))) (deftest scale->pitches-test - (are [expected-pitches root-pitch scale-type] (= expected-pitches (scale/scale->pitches root-pitch scale-type)) - '(:C :D :E :F :G :A :B) :C :major - '(:C :D :Eb :F :G :Ab :Bb) :C :minor - '(:C# :Eb :F :F# :Ab :Bb :C) :C# :major + (are [root-pitch scale-type expected-pitches] (= expected-pitches (scale/scale->pitches root-pitch scale-type)) + :C :major '(:C :D :E :F :G :A :B) + :C :minor '(:C :D :Eb :F :G :Ab :Bb) + :C# :major '(:C# :Eb :F :F# :Ab :Bb :C) ;; TODO: convert accidentals accordingly - '(:C# :Eb :F :F# :Ab :Bb :C) :Db :major)) + :Db :major '(:C# :Eb :F :F# :Ab :Bb :C))) (deftest scale-pitches->intervals-test ;; Intervals all the way to up a 13th @@ -96,19 +95,3 @@ :chord-notes (60 65 67)}) (scale/scale-pitch->diatonic-chords (get scale/ALL-SCALES {:root :C :scale-type :major}) :C)))) - -(defn chord->example-notes [root chord-type] - (->> {:root root :chord-type chord-type} - chord/ALL-CHORDS - (map #(pitch/construct-note % 4)))) - -(def c-major-blocks - (map-indexed (fn [i [root chord-type]] - {:id i :notes (chord->example-notes root chord-type)}) - [[:C :maj] - [:D :min] - [:E :min] - [:F :maj] - [:G :maj] - [:A :min] - [:B :dim]])) diff --git a/test/why_does_that_sound_good/test_utils.cljc b/test/why_does_that_sound_good/test_utils.cljc new file mode 100644 index 0000000..30b31dc --- /dev/null +++ b/test/why_does_that_sound_good/test_utils.cljc @@ -0,0 +1,20 @@ +(ns why-does-that-sound-good.test-utils + (:require + [why-does-that-sound-good.algo.chord :as chord] + [why-does-that-sound-good.pitch :as pitch])) + +(defn chord->example-notes [root chord-type] + (->> {:root root :chord-type chord-type} + chord/ALL-CHORDS + (map #(pitch/construct-note % 4)))) + +(def c-major-blocks + (map-indexed (fn [i [root chord-type]] + {:id i :notes (chord->example-notes root chord-type)}) + [[:C :maj] + [:D :min] + [:E :min] + [:F :maj] + [:G :maj] + [:A :min] + [:B :dim]])) diff --git a/test/why_does_that_sound_good/utils_test.cljc b/test/why_does_that_sound_good/utils_test.cljc index b24a2fa..a86a0f2 100644 --- a/test/why_does_that_sound_good/utils_test.cljc +++ b/test/why_does_that_sound_good/utils_test.cljc @@ -20,39 +20,39 @@ (is (= #{:C :E :G} (utils/block->pitches {:id 1 :notes #{60 64 67} :selected-suggestion {:root :C :chord-type :major :chord-notes '(60 64 67)}}))))) (deftest in?-test - (are [expected coll el] (= expected (utils/in? coll el)) - nil [] 1 - true [1 2 3] 1 - nil [1 2 3] 4)) + (are [coll el expected] (= expected (utils/in? coll el)) + [] 1 nil + [1 2 3] 1 true + [1 2 3] 4 nil)) (deftest get-cyclic-distance-test - (are [expected-distance start end total-length] (= expected-distance (utils/get-cyclic-distance start end total-length)) - 0 1 1 10 - 1 2 1 10 ;; Going backwards in the cycle is shorter - 2 3 1 10 - 3 4 1 10 - 4 5 1 10 - 5 6 1 10 ;; Furthest distance - 4 7 1 10 ;; Going forwards and wrapping around the cycle is shorter now - 3 8 1 10 - 2 9 1 10 - 1 10 1 10)) + (are [start end total-length expected-distance] (= expected-distance (utils/get-cyclic-distance start end total-length)) + 1 1 10 0 + 2 1 10 1 ;; Going backwards in the cycle is shorter + 3 1 10 2 + 4 1 10 3 + 5 1 10 4 + 6 1 10 5 ;; Furthest distance + 7 1 10 4 ;; Going forwards and wrapping around the cycle is shorter now + 8 1 10 3 + 9 1 10 2 + 10 1 10 1)) (deftest get-pitch-distance - (are [expected-distance start-pitch end-pitch] (= expected-distance (utils/get-pitch-distance start-pitch end-pitch)) - 0 :C :C - 1 :C# :C ;; Going backwards in the cycle is shorter - 1 :Db :C ;; Either accidental representation works - 2 :D :C - 3 :D# :C - 4 :E :C - 5 :F :C - 6 :F# :C ;; Furthest distance - 5 :G :C - 4 :G# :C ;; Going forwards and wrapping around to next C is shorter now - 3 :A :C - 2 :A# :C - 1 :B :C)) + (are [start-pitch end-pitch expected-distance] (= expected-distance (utils/get-pitch-distance start-pitch end-pitch)) + :C :C 0 + :C# :C 1 ;; Going backwards in the cycle is shorter + :Db :C 1 ;; Either accidental representation works + :D :C 2 + :D# :C 3 + :E :C 4 + :F :C 5 + :F# :C 6 ;; Furthest distance + :G :C 5 + :G# :C 4 ;; Going forwards and wrapping around to next C is shorter now + :A :C 3 + :A# :C 2 + :B :C 1)) (deftest music-structure->str-test (testing "chord" @@ -64,21 +64,21 @@ (is (= "C major" (utils/music-structure->str {:root :C :scale-type :major} :space? true))))) (deftest jaccard-index-test - (are [expected-index set-1 set-2] (= expected-index (utils/jaccard-index set-1 set-2)) - 1.0 #{1 2 3} #{1 2 3} - 0.5 #{1 2 3 4} #{1 2} - 0.5 #{1 2} #{1 2 3 4} ;; order-independent - 0 #{} #{} - 0.0 #{1 2} #{3 4})) + (are [set-1 set-2 expected-index] (= expected-index (utils/jaccard-index set-1 set-2)) + #{1 2 3} #{1 2 3} 1.0 + #{1 2 3 4} #{1 2} 0.5 + #{1 2} #{1 2 3 4} 0.5 ;; order-independent + #{} #{} 0 + #{1 2} #{3 4} 0.0)) (deftest pitch-similarity-test - (are [expected-index input-pitches dest-pitches dest-pitches-root] (= expected-index (utils/pitch-similarity input-pitches dest-pitches dest-pitches-root)) - 1.0 #{:C :D :E} #{:C :D :E} :C - 0.75 #{:C :D :E :F} #{:C :D} :C ;; If chord/scale root pitch is in input-pitches, give more weight (base Jaccard Index would normally be 0.5) - 0 #{} #{} :C - 0.5 #{:C :D} #{:E :F} :C)) + (are [input-pitches dest-pitches dest-pitches-root expected-index] (= expected-index (utils/pitch-similarity input-pitches dest-pitches dest-pitches-root)) + #{:C :D :E} #{:C :D :E} :C 1.0 + #{:C :D :E :F} #{:C :D} :C 0.75 ;; If chord/scale root pitch is in input-pitches, give more weight (base Jaccard Index would normally be 0.5) + #{} #{} :C 0 + #{:C :D} #{:E :F} :C 0.5)) (deftest upsert-in-test - (are [expected m ks v] (= expected (utils/upsert-in m ks v)) - {:foo [1]} {} [:foo] 1 - {:foo [1 2]} {:foo [1]} [:foo] 2)) + (are [m ks v expected] (= expected (utils/upsert-in m ks v)) + {} [:foo] 1 {:foo [1]} + {:foo [1]} [:foo] 2 {:foo [1 2]}))