{-# LANGUAGE OverloadedStrings #-}

module Sound.Tidal.ScalesTest where

import TestUtils
import Test.Microspec

import Prelude hiding ((<*), (*>))

import Sound.Tidal.Scales
import Sound.Tidal.Pattern

run :: Microspec ()
run =
  describe "Sound.Tidal.Scales" $ do
    describe "scale" $ do
        describe "5 note scales" $ do
            let twoOctavesOf5NoteScale = "0 1 2 3 4 5 6 7 8 9"
            it "can transform notes correctly over 2 octaves - minPent" $ do
                compareP (Arc 0 1)
                    (Sound.Tidal.Scales.scale "minPent" twoOctavesOf5NoteScale)
                    ("0 3 5 7 10 12 15 17 19 22"::Pattern Int)
            it "can transform notes correctly over 2 octaves - majPent" $ do
                compareP (Arc 0 1)
                    (Sound.Tidal.Scales.scale "majPent" twoOctavesOf5NoteScale)
                    ("0 2 4 7 9 12 14 16 19 21"::Pattern Int)
            it "can transform notes correctly over 2 octaves - ritusen" $ do
                compareP (Arc 0 1)
                    (Sound.Tidal.Scales.scale "ritusen" twoOctavesOf5NoteScale)
                    ("0 2 5 7 9 12 14 17 19 21"::Pattern Int)
            it "can transform notes correctly over 2 octaves - egyptian" $ do
                compareP (Arc 0 1)
                    (Sound.Tidal.Scales.scale "egyptian" twoOctavesOf5NoteScale)
                    ("0 2 5 7 10 12 14 17 19 22"::Pattern Int)
            it "can transform notes correctly over 2 octaves - kumai" $ do
                compareP (Arc 0 1)
                    (Sound.Tidal.Scales.scale "kumai" twoOctavesOf5NoteScale)
                    ("0 2 3 7 9 12 14 15 19 21"::Pattern Int)
            it "can transform notes correctly over 2 octaves - hirajoshi" $ do
                compareP (Arc 0 1)
                    (Sound.Tidal.Scales.scale "hirajoshi" twoOctavesOf5NoteScale)
                    ("0 2 3 7 8 12 14 15 19 20"::Pattern Int)
            it "can transform notes correctly over 2 octaves - iwato" $ do
                compareP (Arc 0 1)
                    (Sound.Tidal.Scales.scale "iwato" twoOctavesOf5NoteScale)
                    ("0 1 5 6 10 12 13 17 18 22"::Pattern Int)
            it "can transform notes correctly over 2 octaves - chinese" $ do
                compareP (Arc 0 1)
                    (Sound.Tidal.Scales.scale "chinese" twoOctavesOf5NoteScale)
                    ("0 4 6 7 11 12 16 18 19 23"::Pattern Int)
            it "can transform notes correctly over 2 octaves - indian" $ do
                compareP (Arc 0 1)
                    (Sound.Tidal.Scales.scale "indian" twoOctavesOf5NoteScale)
                    ("0 4 5 7 10 12 16 17 19 22"::Pattern Int)
            it "can transform notes correctly over 2 octaves - pelog" $ do
                compareP (Arc 0 1)
                    (Sound.Tidal.Scales.scale "pelog" twoOctavesOf5NoteScale)
                    ("0 1 3 7 8 12 13 15 19 20"::Pattern Int)
            it "can transform notes correctly over 2 octaves - prometheus" $ do
                compareP (Arc 0 1)
                    (Sound.Tidal.Scales.scale "prometheus" twoOctavesOf5NoteScale)
                    ("0 2 4 6 11 12 14 16 18 23"::Pattern Int)
            it "can transform notes correctly over 2 octaves - scriabin" $ do
                compareP (Arc 0 1)
                    (Sound.Tidal.Scales.scale "scriabin" twoOctavesOf5NoteScale)
                    ("0 1 4 7 9 12 13 16 19 21"::Pattern Int)
            it "can transform notes correctly over 2 octaves - gong" $ do
                compareP (Arc 0 1)
                    (Sound.Tidal.Scales.scale "gong" twoOctavesOf5NoteScale)
                    ("0 2 4 7 9 12 14 16 19 21"::Pattern Int)
            it "can transform notes correctly over 2 octaves - shang" $ do
                compareP (Arc 0 1)
                    (Sound.Tidal.Scales.scale "shang" twoOctavesOf5NoteScale)
                    ("0 2 5 7 10 12 14 17 19 22"::Pattern Int)
            it "can transform notes correctly over 2 octaves - jiao" $ do
                compareP (Arc 0 1)
                    (Sound.Tidal.Scales.scale "jiao" twoOctavesOf5NoteScale)
                    ("0 3 5 8 10 12 15 17 20 22"::Pattern Int)
            it "can transform notes correctly over 2 octaves - zhi" $ do
                compareP (Arc 0 1)
                    (Sound.Tidal.Scales.scale "zhi" twoOctavesOf5NoteScale)
                    ("0 2 5 7 9 12 14 17 19 21"::Pattern Int)
            it "can transform notes correctly over 2 octaves - yu" $ do
                compareP (Arc 0 1)
                    (Sound.Tidal.Scales.scale "yu" twoOctavesOf5NoteScale)
                    ("0 3 5 7 10 12 15 17 19 22"::Pattern Int)
        describe "6 note scales" $ do
            let twoOctavesOf6NoteScale = "0 1 2 3 4 5 6 7 8 9 10 11"
            it "can transform notes correctly over 2 octaves - whole" $ do
                compareP (Arc 0 1)
                    (Sound.Tidal.Scales.scale "whole" twoOctavesOf6NoteScale)
                    ("0 2 4 6 8 10 12 14 16 18 20 22"::Pattern Int)
            it "can transform notes correctly over 2 octaves - wholetone" $ do
                compareP (Arc 0 1)
                    (Sound.Tidal.Scales.scale "wholetone" twoOctavesOf6NoteScale)
                    (Sound.Tidal.Scales.scale "whole" twoOctavesOf6NoteScale :: Pattern Int)
            it "can transform notes correctly over 2 octaves - augmented" $ do
                compareP (Arc 0 1)
                    (Sound.Tidal.Scales.scale "augmented" twoOctavesOf6NoteScale)
                    ("0 3 4 7 8 11 12 15 16 19 20 23"::Pattern Int)
            it "can transform notes correctly over 2 octaves - augmented2" $ do
                compareP (Arc 0 1)
                    (Sound.Tidal.Scales.scale "augmented2" twoOctavesOf6NoteScale)
                    ("0 1 4 5 8 9 12 13 16 17 20 21"::Pattern Int)
            it "can transform notes correctly over 2 octaves - hexMajor7" $ do
                compareP (Arc 0 1)
                    (Sound.Tidal.Scales.scale "hexMajor7" twoOctavesOf6NoteScale)
                    ("0 2 4 7 9 11 12 14 16 19 21 23"::Pattern Int)
            it "can transform notes correctly over 2 octaves - hexPhrygian" $ do
                compareP (Arc 0 1)
                    (Sound.Tidal.Scales.scale "hexPhrygian" twoOctavesOf6NoteScale)
                    ("0 1 3 5 8 10 12 13 15 17 20 22"::Pattern Int)
            it "can transform notes correctly over 2 octaves - hexDorian" $ do
                compareP (Arc 0 1)
                    (Sound.Tidal.Scales.scale "hexDorian" twoOctavesOf6NoteScale)
                    ("0 2 3 5 7 10 12 14 15 17 19 22"::Pattern Int)
            it "can transform notes correctly over 2 octaves - hexSus" $ do
                compareP (Arc 0 1)
                    (Sound.Tidal.Scales.scale "hexSus" twoOctavesOf6NoteScale)
                    ("0 2 5 7 9 10 12 14 17 19 21 22"::Pattern Int)
            it "can transform notes correctly over 2 octaves - hexMajor6" $ do
                compareP (Arc 0 1)
                    (Sound.Tidal.Scales.scale "hexMajor6" twoOctavesOf6NoteScale)
                    ("0 2 4 5 7 9 12 14 16 17 19 21"::Pattern Int)
            it "can transform notes correctly over 2 octaves - hexAeolian" $ do
                compareP (Arc 0 1)
                    (Sound.Tidal.Scales.scale "hexAeolian" twoOctavesOf6NoteScale)
                    ("0 3 5 7 8 10 12 15 17 19 20 22"::Pattern Int)
        describe "7 note scales" $ do
            let twoOctavesOf7NoteScale = "0 1 2 3 4 5 6 7 8 9 10 11 12 13"
            it "can transform notes correctly over 2 octaves - major" $ do
                compareP (Arc 0 1)
                    (Sound.Tidal.Scales.scale "major" twoOctavesOf7NoteScale)
                    ("0 2 4 5 7 9 11 12 14 16 17 19 21 23"::Pattern Int)
            it "can transform notes correctly over 2 octaves - ionian" $ do
                compareP (Arc 0 1)
                    (Sound.Tidal.Scales.scale "ionian" twoOctavesOf7NoteScale)
                    (Sound.Tidal.Scales.scale "major" twoOctavesOf7NoteScale :: Pattern Int)
            it "can transform notes correctly over 2 octaves - dorian" $ do
                compareP (Arc 0 1)
                    (Sound.Tidal.Scales.scale "dorian" twoOctavesOf7NoteScale)
                    ("0 2 3 5 7 9 10 12 14 15 17 19 21 22"::Pattern Int)
            it "can transform notes correctly over 2 octaves - aeolian" $ do
                compareP (Arc 0 1)
                    (Sound.Tidal.Scales.scale "aeolian" twoOctavesOf7NoteScale)
                    ("0 2 3 5 7 8 10 12 14 15 17 19 20 22"::Pattern Int)
            it "can transform notes correctly over 2 octaves - aeolian" $ do
                compareP (Arc 0 1)
                    (Sound.Tidal.Scales.scale "minor" twoOctavesOf7NoteScale)
                    (Sound.Tidal.Scales.scale "aeolian" twoOctavesOf7NoteScale::Pattern Int)
            it "can transform notes correctly over 2 octaves - minor" $ do
                compareP (Arc 0 1)
                    (Sound.Tidal.Scales.scale "minor" twoOctavesOf7NoteScale)
                    (Sound.Tidal.Scales.scale "aeolian" twoOctavesOf7NoteScale::Pattern Int)
            it "can transform notes correctly over 2 octaves - locrian" $ do
                compareP (Arc 0 1)
                    (Sound.Tidal.Scales.scale "locrian" twoOctavesOf7NoteScale)
                    ("0 1 3 5 6 8 10 12 13 15 17 18 20 22"::Pattern Int)
            it "can transform notes correctly over 2 octaves - harmonicMinor" $ do
                compareP (Arc 0 1)
                    (Sound.Tidal.Scales.scale "harmonicMinor" twoOctavesOf7NoteScale)
                    ("0 2 3 5 7 8 11 12 14 15 17 19 20 23"::Pattern Int)
            it "can transform notes correctly over 2 octaves - harmonicMajor" $ do
                compareP (Arc 0 1)
                    (Sound.Tidal.Scales.scale "harmonicMajor" twoOctavesOf7NoteScale)
                    ("0 2 4 5 7 8 11 12 14 16 17 19 20 23"::Pattern Int)
            it "can transform notes correctly over 2 octaves - melodicMinor" $ do
                compareP (Arc 0 1)
                    (Sound.Tidal.Scales.scale "melodicMinor" twoOctavesOf7NoteScale)
                    ("0 2 3 5 7 9 11 12 14 15 17 19 21 23"::Pattern Int)
            it "can transform notes correctly over 2 octaves - melodicMinorDesc" $ do
                compareP (Arc 0 1)
                    (Sound.Tidal.Scales.scale "melodicMinorDesc" twoOctavesOf7NoteScale)
                    (Sound.Tidal.Scales.scale "minor" twoOctavesOf7NoteScale::Pattern Int)
            it "can transform notes correctly over 2 octaves - melodicMajor" $ do
                compareP (Arc 0 1)
                    (Sound.Tidal.Scales.scale "melodicMajor" twoOctavesOf7NoteScale)
                    ("0 2 4 5 7 8 10 12 14 16 17 19 20 22"::Pattern Int)
            it "can transform notes correctly over 2 octaves - bartok" $ do
                compareP (Arc 0 1)
                    (Sound.Tidal.Scales.scale "bartok" twoOctavesOf7NoteScale)
                    (Sound.Tidal.Scales.scale "melodicMajor" twoOctavesOf7NoteScale::Pattern Int)
            it "can transform notes correctly over 2 octaves - hindu" $ do
                compareP (Arc 0 1)
                    (Sound.Tidal.Scales.scale "hindu" twoOctavesOf7NoteScale)
                    (Sound.Tidal.Scales.scale "melodicMajor" twoOctavesOf7NoteScale::Pattern Int)
            it "can transform notes correctly over 2 octaves - todi" $ do
                compareP (Arc 0 1)
                    (Sound.Tidal.Scales.scale "todi" twoOctavesOf7NoteScale)
                    ("0 1 3 6 7 8 11 12 13 15 18 19 20 23"::Pattern Int)
            it "can transform notes correctly over 2 octaves - purvi" $ do
                compareP (Arc 0 1)
                    (Sound.Tidal.Scales.scale "purvi" twoOctavesOf7NoteScale)
                    ("0 1 4 6 7 8 11 12 13 16 18 19 20 23"::Pattern Int)
            it "can transform notes correctly over 2 octaves - marva" $ do
                compareP (Arc 0 1)
                    (Sound.Tidal.Scales.scale "marva" twoOctavesOf7NoteScale)
                    ("0 1 4 6 7 9 11 12 13 16 18 19 21 23"::Pattern Int)
            it "can transform notes correctly over 2 octaves - bhairav" $ do
                compareP (Arc 0 1)
                    (Sound.Tidal.Scales.scale "bhairav" twoOctavesOf7NoteScale)
                    ("0 1 4 5 7 8 11 12 13 16 17 19 20 23"::Pattern Int)
            it "can transform notes correctly over 2 octaves - ahirbhairav" $ do
                compareP (Arc 0 1)
                    (Sound.Tidal.Scales.scale "ahirbhairav" twoOctavesOf7NoteScale)
                    ("0 1 4 5 7 9 10 12 13 16 17 19 21 22"::Pattern Int)
            it "can transform notes correctly over 2 octaves - superLocrian" $ do
                compareP (Arc 0 1)
                    (Sound.Tidal.Scales.scale "superLocrian" twoOctavesOf7NoteScale)
                    ("0 1 3 4 6 8 10 12 13 15 16 18 20 22"::Pattern Int)
            it "can transform notes correctly over 2 octaves - romanianMinor" $ do
                compareP (Arc 0 1)
                    (Sound.Tidal.Scales.scale "romanianMinor" twoOctavesOf7NoteScale)
                    ("0 2 3 6 7 9 10 12 14 15 18 19 21 22"::Pattern Int)
            it "can transform notes correctly over 2 octaves - hungarianMinor" $ do
                compareP (Arc 0 1)
                    (Sound.Tidal.Scales.scale "hungarianMinor" twoOctavesOf7NoteScale)
                    ("0 2 3 6 7 8 11 12 14 15 18 19 20 23"::Pattern Int)
            it "can transform notes correctly over 2 octaves - neapolitanMinor" $ do
                compareP (Arc 0 1)
                    (Sound.Tidal.Scales.scale "neapolitanMinor" twoOctavesOf7NoteScale)
                    ("0 1 3 5 7 8 11 12 13 15 17 19 20 23"::Pattern Int)
            it "can transform notes correctly over 2 octaves - enigmatic" $ do
                compareP (Arc 0 1)
                    (Sound.Tidal.Scales.scale "enigmatic" twoOctavesOf7NoteScale)
                    ("0 1 4 6 8 10 11 12 13 16 18 20 22 23"::Pattern Int)
            it "can transform notes correctly over 2 octaves - spanish" $ do
                compareP (Arc 0 1)
                    (Sound.Tidal.Scales.scale "spanish" twoOctavesOf7NoteScale)
                    ("0 1 4 5 7 8 10 12 13 16 17 19 20 22"::Pattern Int)
            it "can transform notes correctly over 2 octaves - leadingWhole" $ do
                compareP (Arc 0 1)
                    (Sound.Tidal.Scales.scale "leadingWhole" twoOctavesOf7NoteScale)
                    ("0 2 4 6 8 10 11 12 14 16 18 20 22 23"::Pattern Int)
            it "can transform notes correctly over 2 octaves - lydianMinor" $ do
                compareP (Arc 0 1)
                    (Sound.Tidal.Scales.scale "lydianMinor" twoOctavesOf7NoteScale)
                    ("0 2 4 6 7 8 10 12 14 16 18 19 20 22"::Pattern Int)
            it "can transform notes correctly over 2 octaves - neapolitanMajor" $ do
                compareP (Arc 0 1)
                    (Sound.Tidal.Scales.scale "neapolitanMajor" twoOctavesOf7NoteScale)
                    ("0 1 3 5 7 9 11 12 13 15 17 19 21 23"::Pattern Int)
            it "can transform notes correctly over 2 octaves - locrianMajor" $ do
                compareP (Arc 0 1)
                    (Sound.Tidal.Scales.scale "locrianMajor" twoOctavesOf7NoteScale)
                    ("0 2 4 5 6 8 10 12 14 16 17 18 20 22"::Pattern Int)
        describe "8 note scales" $ do
            let twoOctavesOf8NoteScale = "0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15"
            it "can transform notes correctly over 2 octaves - diminished" $ do
                compareP (Arc 0 1)
                    (Sound.Tidal.Scales.scale "diminished" twoOctavesOf8NoteScale)
                    ("0 1 3 4 6 7 9 10 12 13 15 16 18 19 21 22"::Pattern Int)
            it "can transform notes correctly over 2 octaves - octatonic" $ do
                compareP (Arc 0 1)
                    (Sound.Tidal.Scales.scale "octatonic" twoOctavesOf8NoteScale)
                    (Sound.Tidal.Scales.scale "diminished" twoOctavesOf8NoteScale::Pattern Int)
            it "can transform notes correctly over 2 octaves - diminished2" $ do
                compareP (Arc 0 1)
                    (Sound.Tidal.Scales.scale "diminished2" twoOctavesOf8NoteScale)
                    ("0 2 3 5 6 8 9 11 12 14 15 17 18 20 21 23"::Pattern Int)
            it "can transform notes correctly over 2 octaves - octatonic2" $ do
                compareP (Arc 0 1)
                    (Sound.Tidal.Scales.scale "octatonic2" twoOctavesOf8NoteScale)
                    (Sound.Tidal.Scales.scale "diminished2" twoOctavesOf8NoteScale::Pattern Int)
        describe "modes of limited transposition" $ do
            let twoOctavesOf6NoteScale = "0 1 2 3 4 5 6 7 8 9 10 11"
            let twoOctavesOf8NoteScale = "0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15"
            let twoOctavesOf9NoteScale = "0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17"
            let twoOctavesOf10NoteScale = "0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19"
            it "can transform notes correctly over 2 octaves - messiaen1" $ do
                compareP (Arc 0 1)
                    (Sound.Tidal.Scales.scale "messiaen1" twoOctavesOf6NoteScale)
                    (Sound.Tidal.Scales.scale "wholetone" twoOctavesOf6NoteScale::Pattern Int)
            it "can transform notes correctly over 2 octaves - messiaen2" $ do
                compareP (Arc 0 1)
                    (Sound.Tidal.Scales.scale "messiaen2" twoOctavesOf8NoteScale)
                    (Sound.Tidal.Scales.scale "diminished" twoOctavesOf8NoteScale::Pattern Int)
            it "can transform notes correctly over 2 octaves - messiaen3" $ do
                -- tone, semitone, semitone, tone, semitone, semitone, tone, semitone, semitone
                compareP (Arc 0 1)
                    (Sound.Tidal.Scales.scale "messiaen3" twoOctavesOf9NoteScale)
                    ("0 2 3 4 6 7 8 10 11 12 14 15 16 18 19 20 22 23"::Pattern Int)
            it "can transform notes correctly over 2 octaves - messiaen4" $ do
                -- semitone, semitone, minor third, semitone, semitone, semitone, minor third, semitone
                compareP (Arc 0 1)
                    (Sound.Tidal.Scales.scale "messiaen4" twoOctavesOf8NoteScale)
                    ("0 1 2 5 6 7 8 11 12 13 14 17 18 19 20 23"::Pattern Int)
            it "can transform notes correctly over 2 octaves - messiaen5" $ do
                -- semitone, major third, semitone, semitone, major third, semitone
                compareP (Arc 0 1)
                    (Sound.Tidal.Scales.scale "messiaen5" twoOctavesOf6NoteScale)
                    ("0 1 5 6 7 11 12 13 17 18 19 23"::Pattern Int)
            it "can transform notes correctly over 2 octaves - messiaen6" $ do
                -- tone, tone, semitone, semitone, tone, tone, semitone, semitone
                compareP (Arc 0 1)
                    (Sound.Tidal.Scales.scale "messiaen6" twoOctavesOf8NoteScale)
                    ("0 2 4 5 6 8 10 11 12 14 16 17 18 20 22 23"::Pattern Int)
            it "can transform notes correctly over 2 octaves - messiaen7" $ do
                -- semitone, semitone, semitone, tone, semitone, semitone, semitone, semitone, tone, semitone
                compareP (Arc 0 1)
                    (Sound.Tidal.Scales.scale "messiaen7" twoOctavesOf10NoteScale)
                    ("0 1 2 3 5 6 7 8 9 11 12 13 14 15 17 18 19 20 21 23"::Pattern Int)
        describe "12 note scales" $ do
            let twoOctavesOf12NoteScale = "0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23"
            it "can transform notes correctly over 2 octaves - chromatic" $ do
                compareP (Arc 0 1)
                    (Sound.Tidal.Scales.scale "chromatic" twoOctavesOf12NoteScale)
                    (twoOctavesOf12NoteScale::Pattern Int)
        describe "edge cases" $ do
            it "responds to unknown scales by mapping to octaves" $ do
                compareP (Arc 0 1)
                    (Sound.Tidal.Scales.scale "ergaerv" "0 1 2 3 4")
                    ("0 12 24 36 48"::Pattern Int)
            it "correctly maps negative numbers" $ do
                compareP (Arc 0 1)
                    (Sound.Tidal.Scales.scale "major" "0 -1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13")
                    ("0 -1 -3 -5 -7 -8 -10 -12 -13 -15 -17 -19 -20 -22 "::Pattern Int)
           