-- | The Interval module implements diatonic intervals. module Music.Diatonic.Interval ( Interval( Unison,Min2nd,Maj2nd,Min3rd,Maj3rd,Perf4th, Perf5th,Min6th,Maj6th,Min7th,Maj7th ), compound, octave, min9th, maj9th, perf11th, min13th, maj13th, augment, diminish, steps, semitones ) where import Music.Diatonic.Quality import Music.Diatonic.Equivalence -- | Use these constructors to create 'Interval's. To alter them, use the 'diminish' or 'augment' functions. data Interval = Unison | Min2nd | Maj2nd | Min3rd | Maj3rd | Perf4th | Perf5th | Min6th | Maj6th | Min7th | Maj7th | Aug Interval | Dim Interval | Compound Interval deriving (Eq) instance Qual Interval where quality i | i `elem` [Maj2nd, Maj3rd, Maj6th, Maj7th] = Major quality i | i `elem` [Min2nd, Min3rd, Min6th, Min7th] = Minor quality i | i `elem` [Unison, Perf4th, Perf5th] = Perfect quality (Aug i) = Augmented quality (Dim i) = Diminished quality (Compound i) = quality i instance Show Interval where show i = showq i ++ shown where shown = show . (+ 1) . steps $ i showq (Compound i) = showq i showq (Aug i@(Aug _)) = "A" ++ showq i showq (Dim i@(Dim _)) = "d" ++ showq i showq (Aug i) = "A" ++ (tail . showq $ i) showq (Dim i) = "d" ++ (tail . showq $ i) showq i = case quality i of Major -> "M" Minor -> "m" Perfect -> "P" instance Equiv Interval where equiv i1 i2 = ((semitones i1 `mod` 12 == (semitones i2 `mod` 12)) && ((steps i1 `mod` 7) == (steps i2 `mod` 7))) -- | Augments an 'Interval' by a semitone. The interval type remains the same. augment :: Interval -> Interval augment Min2nd = Maj2nd ; augment Min3rd = Maj3rd augment Min6th = Maj6th ; augment Min7th = Maj7th augment (Compound i) = compound . augment $ i augment (Dim i) = i augment i = Aug i -- | Diminishes an 'Interval' by a semitone. The interval type remains the same. diminish :: Interval -> Interval diminish Maj2nd = Min2nd ; diminish Maj3rd = Min3rd diminish Maj6th = Min6th ; diminish Maj7th = Min7th diminish (Compound i) = compound . diminish $ i diminish (Aug i) = i diminish i = Dim i -- | Returns the number of scale steps in an 'Interval'. steps :: Interval -> Int steps Unison = 0 ; steps Min2nd = 1 ; steps Maj2nd = 1 ; steps Min3rd = 2 steps Maj3rd = 2 ; steps Perf4th = 3 ; steps Perf5th = 4 ; steps Min6th = 5 steps Maj6th = 5 ; steps Min7th = 6 ; steps Maj7th = 6 ; steps (Aug i) = steps i steps (Dim i) = steps i steps (Compound i) = 7 + steps i -- | Returns the number of semitones in an 'Interval'. semitones :: Interval -> Int semitones Unison = 0 ; semitones Min2nd = 1 ; semitones Maj2nd = 2 ; semitones Min3rd = 3 semitones Maj3rd = 4 ; semitones Perf4th = 5 ; semitones Perf5th = 7 ; semitones Min6th = 8 semitones Maj6th = 9 ; semitones Min7th = 10 ; semitones Maj7th = 11 ; semitones (Aug i) = semitones i + 1 semitones (Dim i) = semitones i - 1 semitones (Compound i) = 12 + semitones i -- | Creates compound interval (adds an 'octave') to the specified 'Interval' compound :: Interval -> Interval compound = Compound octave :: Interval octave = compound Unison min9th :: Interval min9th = compound Min2nd maj9th :: Interval maj9th = compound Maj2nd perf11th :: Interval perf11th = compound Perf4th min13th :: Interval min13th = compound Min6th maj13th :: Interval maj13th = compound Maj6th