packages feed

music-pitch 1.7.2 → 1.8

raw patch · 19 files changed

+1582/−987 lines, 19 filesdep +data-intervaldep +lensdep +positivedep −randomdep −semigroupoidsdep −timedep ~music-pitch-literalPVP ok

version bump matches the API change (PVP)

Dependencies added: data-interval, lens, positive

Dependencies removed: random, semigroupoids, time

Dependency ranges changed: music-pitch-literal

API changes (from Hackage documentation)

- Music.Pitch.Clef: type OctaveAdjustment = Integer
- Music.Pitch.Common.Interval: Augmented :: Int -> Quality
- Music.Pitch.Common.Interval: Diminished :: Int -> Quality
- Music.Pitch.Common.Interval: Interval :: (Int, Int) -> Interval
- Music.Pitch.Common.Interval: Major :: Quality
- Music.Pitch.Common.Interval: Minor :: Quality
- Music.Pitch.Common.Interval: Perfect :: Quality
- Music.Pitch.Common.Interval: basis_A1 :: Interval
- Music.Pitch.Common.Interval: basis_P1 :: Interval
- Music.Pitch.Common.Interval: basis_P5 :: Interval
- Music.Pitch.Common.Interval: basis_P8 :: Interval
- Music.Pitch.Common.Interval: basis_d2 :: Interval
- Music.Pitch.Common.Interval: class HasNumber a
- Music.Pitch.Common.Interval: class HasQuality a
- Music.Pitch.Common.Interval: data Number
- Music.Pitch.Common.Interval: data Quality
- Music.Pitch.Common.Interval: duodecim :: Number
- Music.Pitch.Common.Interval: fifteenth :: Number
- Music.Pitch.Common.Interval: fifth :: Number
- Music.Pitch.Common.Interval: fourteenth :: Number
- Music.Pitch.Common.Interval: fourth :: Number
- Music.Pitch.Common.Interval: getInterval :: Interval -> (Int, Int)
- Music.Pitch.Common.Interval: instance Augmentable Quality
- Music.Pitch.Common.Interval: instance Enum Number
- Music.Pitch.Common.Interval: instance Eq Number
- Music.Pitch.Common.Interval: instance Eq Quality
- Music.Pitch.Common.Interval: instance HasNumber Number
- Music.Pitch.Common.Interval: instance HasQuality Quality
- Music.Pitch.Common.Interval: instance Integral Number
- Music.Pitch.Common.Interval: instance Num Number
- Music.Pitch.Common.Interval: instance Ord Number
- Music.Pitch.Common.Interval: instance Ord Quality
- Music.Pitch.Common.Interval: instance Real Number
- Music.Pitch.Common.Interval: instance Show Number
- Music.Pitch.Common.Interval: instance Show Quality
- Music.Pitch.Common.Interval: intervalDiff :: Interval -> Int
- Music.Pitch.Common.Interval: invertQuality :: Quality -> Quality
- Music.Pitch.Common.Interval: isAugmented :: HasQuality a => a -> Bool
- Music.Pitch.Common.Interval: isDiminished :: HasQuality a => a -> Bool
- Music.Pitch.Common.Interval: isMajor :: HasQuality a => a -> Bool
- Music.Pitch.Common.Interval: isMinor :: HasQuality a => a -> Bool
- Music.Pitch.Common.Interval: isPerfect :: HasQuality a => a -> Bool
- Music.Pitch.Common.Interval: mkInterval :: Quality -> Number -> Interval
- Music.Pitch.Common.Interval: mkInterval' :: Int -> Int -> Interval
- Music.Pitch.Common.Interval: newtype Interval
- Music.Pitch.Common.Interval: ninth :: Number
- Music.Pitch.Common.Interval: number :: HasNumber a => a -> Number
- Music.Pitch.Common.Interval: octave :: Number
- Music.Pitch.Common.Interval: prime :: Number
- Music.Pitch.Common.Interval: quality :: HasQuality a => a -> Quality
- Music.Pitch.Common.Interval: second :: Number
- Music.Pitch.Common.Interval: seventh :: Number
- Music.Pitch.Common.Interval: sixth :: Number
- Music.Pitch.Common.Interval: tenth :: Number
- Music.Pitch.Common.Interval: third :: Number
- Music.Pitch.Common.Interval: thirteenth :: Number
- Music.Pitch.Common.Interval: twelfth :: Number
- Music.Pitch.Common.Interval: unison :: Number
- Music.Pitch.Common.Pitch: Pitch :: Interval -> Pitch
- Music.Pitch.Common.Pitch: getPitch :: Pitch -> Interval
- Music.Pitch.Common.Pitch: isStandard :: Accidental -> Bool
- Music.Pitch.Common.Pitch: newtype Pitch
+ Music.Pitch.Ambitus: Ambitus :: (Interval a) -> Ambitus a
+ Music.Pitch.Ambitus: ambitus :: (Num a, Ord a) => Iso' (a, a) (Ambitus a)
+ Music.Pitch.Ambitus: getAmbitus :: Ambitus a -> (Interval a)
+ Music.Pitch.Ambitus: instance (Show a, Num a, Ord a) => Show (Ambitus a)
+ Music.Pitch.Ambitus: instance Rewrapped (Ambitus a) (Ambitus b)
+ Music.Pitch.Ambitus: instance Wrapped (Ambitus a)
+ Music.Pitch.Ambitus: newtype Ambitus a
+ Music.Pitch.Clef: altoClef :: Clef
+ Music.Pitch.Clef: baritoneClef :: Clef
+ Music.Pitch.Clef: bassClef :: Clef
+ Music.Pitch.Clef: isHistoricalClef :: Clef -> Bool
+ Music.Pitch.Clef: isModernClef :: Clef -> Bool
+ Music.Pitch.Clef: isVoiceClef :: Clef -> Bool
+ Music.Pitch.Clef: mezzoSopranoClef :: Clef
+ Music.Pitch.Clef: sopranoClef :: Clef
+ Music.Pitch.Clef: tenorClef :: Clef
+ Music.Pitch.Clef: trebleClef :: Clef
+ Music.Pitch.Clef: type ClefOctave = Integer
+ Music.Pitch.Common.Chromatic: ChromaticSteps :: Integer -> ChromaticSteps
+ Music.Pitch.Common.Chromatic: getChromaticSteps :: ChromaticSteps -> Integer
+ Music.Pitch.Common.Chromatic: instance Enum ChromaticSteps
+ Music.Pitch.Common.Chromatic: instance Eq ChromaticSteps
+ Music.Pitch.Common.Chromatic: instance Integral ChromaticSteps
+ Music.Pitch.Common.Chromatic: instance Num ChromaticSteps
+ Music.Pitch.Common.Chromatic: instance Ord ChromaticSteps
+ Music.Pitch.Common.Chromatic: instance Real ChromaticSteps
+ Music.Pitch.Common.Chromatic: instance Show ChromaticSteps
+ Music.Pitch.Common.Chromatic: newtype ChromaticSteps
+ Music.Pitch.Common.Diatonic: DiatonicSteps :: Integer -> DiatonicSteps
+ Music.Pitch.Common.Diatonic: getDiatonicSteps :: DiatonicSteps -> Integer
+ Music.Pitch.Common.Diatonic: instance Enum DiatonicSteps
+ Music.Pitch.Common.Diatonic: instance Eq DiatonicSteps
+ Music.Pitch.Common.Diatonic: instance Integral DiatonicSteps
+ Music.Pitch.Common.Diatonic: instance Num DiatonicSteps
+ Music.Pitch.Common.Diatonic: instance Ord DiatonicSteps
+ Music.Pitch.Common.Diatonic: instance Real DiatonicSteps
+ Music.Pitch.Common.Diatonic: instance Show DiatonicSteps
+ Music.Pitch.Common.Diatonic: newtype DiatonicSteps
+ Music.Pitch.Common.Interval: _alteration :: Lens' Interval ChromaticSteps
+ Music.Pitch.Common.Interval: _number :: Lens' Interval Number
+ Music.Pitch.Common.Interval: _quality :: Lens' Interval Quality
+ Music.Pitch.Common.Interval: _steps :: Lens' Interval DiatonicSteps
+ Music.Pitch.Common.Interval: data Interval
+ Music.Pitch.Common.Interval: interval :: Iso' (Quality, Number) Interval
+ Music.Pitch.Common.Interval: interval' :: Iso' (ChromaticSteps, DiatonicSteps) Interval
+ Music.Pitch.Common.Names: Dutch :: Language
+ Music.Pitch.Common.Names: English :: Language
+ Music.Pitch.Common.Names: French :: Language
+ Music.Pitch.Common.Names: German :: Language
+ Music.Pitch.Common.Names: Italian :: Language
+ Music.Pitch.Common.Names: Japanese :: Language
+ Music.Pitch.Common.Names: MajorMode :: Mode
+ Music.Pitch.Common.Names: MinorMode :: Mode
+ Music.Pitch.Common.Names: NewSwedish :: Language
+ Music.Pitch.Common.Names: Portuguese :: Language
+ Music.Pitch.Common.Names: Romanian :: Language
+ Music.Pitch.Common.Names: Russian :: Language
+ Music.Pitch.Common.Names: Spanish :: Language
+ Music.Pitch.Common.Names: Swedish :: Language
+ Music.Pitch.Common.Names: data Language
+ Music.Pitch.Common.Names: data Mode
+ Music.Pitch.Common.Names: instance Eq Language
+ Music.Pitch.Common.Names: instance Eq Mode
+ Music.Pitch.Common.Names: instance Ord Language
+ Music.Pitch.Common.Names: instance Ord Mode
+ Music.Pitch.Common.Names: instance Show Language
+ Music.Pitch.Common.Names: instance Show Mode
+ Music.Pitch.Common.Names: showKey :: Language -> Pitch -> Mode -> String
+ Music.Pitch.Common.Names: showMode :: Language -> Mode -> String
+ Music.Pitch.Common.Names: showPitch :: Language -> Pitch -> String
+ Music.Pitch.Common.Names: showSep :: Language -> String
+ Music.Pitch.Common.Number: Number :: Int -> Number
+ Music.Pitch.Common.Number: class HasNumber a
+ Music.Pitch.Common.Number: diatonicSteps :: Iso' Number DiatonicSteps
+ Music.Pitch.Common.Number: duodecim :: Number
+ Music.Pitch.Common.Number: eleventh :: Number
+ Music.Pitch.Common.Number: fifteenth :: Number
+ Music.Pitch.Common.Number: fifth :: Number
+ Music.Pitch.Common.Number: fourteenth :: Number
+ Music.Pitch.Common.Number: fourth :: Number
+ Music.Pitch.Common.Number: getNumber :: Number -> Int
+ Music.Pitch.Common.Number: instance Enum Number
+ Music.Pitch.Common.Number: instance Eq Number
+ Music.Pitch.Common.Number: instance HasNumber Number
+ Music.Pitch.Common.Number: instance Integral Number
+ Music.Pitch.Common.Number: instance Num Number
+ Music.Pitch.Common.Number: instance Ord Number
+ Music.Pitch.Common.Number: instance Real Number
+ Music.Pitch.Common.Number: instance Show Number
+ Music.Pitch.Common.Number: newtype Number
+ Music.Pitch.Common.Number: ninth :: Number
+ Music.Pitch.Common.Number: number :: HasNumber a => a -> Number
+ Music.Pitch.Common.Number: octave :: Number
+ Music.Pitch.Common.Number: prime :: Number
+ Music.Pitch.Common.Number: second :: Number
+ Music.Pitch.Common.Number: seventh :: Number
+ Music.Pitch.Common.Number: sixth :: Number
+ Music.Pitch.Common.Number: tenth :: Number
+ Music.Pitch.Common.Number: third :: Number
+ Music.Pitch.Common.Number: thirteenth :: Number
+ Music.Pitch.Common.Number: twelfth :: Number
+ Music.Pitch.Common.Number: unison :: Number
+ Music.Pitch.Common.Pitch: data Pitch
+ Music.Pitch.Common.Pitch: downChromaticP :: Pitch -> ChromaticSteps -> Pitch -> Pitch
+ Music.Pitch.Common.Pitch: downDiatonicP :: Pitch -> DiatonicSteps -> Pitch -> Pitch
+ Music.Pitch.Common.Pitch: invertChromaticallyP :: Pitch -> Pitch -> Pitch
+ Music.Pitch.Common.Pitch: invertDiatonicallyP :: Pitch -> Pitch -> Pitch
+ Music.Pitch.Common.Pitch: isStandardAccidental :: Accidental -> Bool
+ Music.Pitch.Common.Pitch: upChromaticP :: Pitch -> ChromaticSteps -> Pitch -> Pitch
+ Music.Pitch.Common.Pitch: upDiatonicP :: Pitch -> DiatonicSteps -> Pitch -> Pitch
+ Music.Pitch.Common.Quality: Augmented :: Integer -> Quality
+ Music.Pitch.Common.Quality: Diminished :: Integer -> Quality
+ Music.Pitch.Common.Quality: Major :: Quality
+ Music.Pitch.Common.Quality: MajorMinorType :: QualityType
+ Music.Pitch.Common.Quality: Minor :: Quality
+ Music.Pitch.Common.Quality: Perfect :: Quality
+ Music.Pitch.Common.Quality: PerfectType :: QualityType
+ Music.Pitch.Common.Quality: class HasQuality a
+ Music.Pitch.Common.Quality: data Quality
+ Music.Pitch.Common.Quality: data QualityType
+ Music.Pitch.Common.Quality: expectedQualityType :: HasNumber a => a -> QualityType
+ Music.Pitch.Common.Quality: instance Augmentable Quality
+ Music.Pitch.Common.Quality: instance Eq Quality
+ Music.Pitch.Common.Quality: instance Eq QualityType
+ Music.Pitch.Common.Quality: instance HasQuality Quality
+ Music.Pitch.Common.Quality: instance Ord Quality
+ Music.Pitch.Common.Quality: instance Ord QualityType
+ Music.Pitch.Common.Quality: instance Read QualityType
+ Music.Pitch.Common.Quality: instance Show Quality
+ Music.Pitch.Common.Quality: instance Show QualityType
+ Music.Pitch.Common.Quality: invertQuality :: Quality -> Quality
+ Music.Pitch.Common.Quality: isAugmented :: HasQuality a => a -> Bool
+ Music.Pitch.Common.Quality: isDiminished :: HasQuality a => a -> Bool
+ Music.Pitch.Common.Quality: isMajor :: HasQuality a => a -> Bool
+ Music.Pitch.Common.Quality: isMinor :: HasQuality a => a -> Bool
+ Music.Pitch.Common.Quality: isPerfect :: HasQuality a => a -> Bool
+ Music.Pitch.Common.Quality: quality :: HasQuality a => a -> Quality
+ Music.Pitch.Common.Quality: qualityToDiff :: Bool -> QualityType -> Quality -> ChromaticSteps
+ Music.Pitch.Common.Quality: qualityTypes :: Quality -> [QualityType]
+ Music.Pitch.Equal: cast :: (IsNat a, IsNat b) => Equal a -> Equal b
+ Music.Pitch.Equal: data Equal a
+ Music.Pitch.Equal: equalToRatio :: IsNat a => Equal a -> Double
+ Music.Pitch.Equal: fromEqual :: IsNat a => Equal a -> Int
+ Music.Pitch.Equal: instance Eq (Equal a)
+ Music.Pitch.Equal: instance IsNat a => AdditiveGroup (Equal a)
+ Music.Pitch.Equal: instance IsNat a => Monoid (Equal a)
+ Music.Pitch.Equal: instance IsNat a => Num (Equal a)
+ Music.Pitch.Equal: instance IsNat a => Semigroup (Equal a)
+ Music.Pitch.Equal: instance IsNat a => VectorSpace (Equal a)
+ Music.Pitch.Equal: instance Ord (Equal a)
+ Music.Pitch.Equal: instance Show (Equal a)
+ Music.Pitch.Equal: size :: IsNat a => Equal a -> Int
+ Music.Pitch.Equal: toEqual :: IsNat a => Int -> Equal a
+ Music.Pitch.Equal: type Equal12 = Equal N12
+ Music.Pitch.Equal: type Equal17 = Equal N17
+ Music.Pitch.Equal: type Equal24 = Equal N24
+ Music.Pitch.Equal: type Equal36 = Equal N36
+ Music.Pitch.Equal: type Equal6 = Equal N6
+ Music.Pitch.Equal: type N17 = N10 :+: N7
+ Music.Pitch.Equal: type N20 = N10 :*: N2
+ Music.Pitch.Equal: type N24 = N20 :+: N4
+ Music.Pitch.Equal: type N30 = N10 :*: N3
+ Music.Pitch.Equal: type N36 = N30 :+: N6
- Music.Pitch.Clef: type Clef = (ClefSymbol, OctaveAdjustment, StaffLines)
+ Music.Pitch.Clef: type Clef = (ClefSymbol, ClefOctave, ClefLine)

Files

music-pitch.cabal view
@@ -1,6 +1,6 @@  name:                   music-pitch-version:                1.7.2+version:                1.8 cabal-version:          >= 1.10 author:                 Hans Hoglund maintainer:             Hans Hoglund@@ -23,29 +23,35 @@    library                         build-depends:      base                    >= 4 && < 5,-                        time,-                        random,                         containers,+                        lens                    >= 4.6      && < 4.7,                         semigroups              >= 0.13.0.1 && < 1,-                        semigroupoids,-                        music-pitch-literal     == 1.7.2,+                        music-pitch-literal     == 1.8,+                        data-interval           >= 1.0.0 && < 2,                         vector-space            >= 0.8.7 && < 0.9,                         vector-space-points     >= 0.2 && < 0.3,                         nats,+                        positive                >= 0.3 && < 1,                         type-unary              >= 0.2.16 && < 1.0-                        -- type-level              >= 0.2.4 && < 3.0     exposed-modules:    Music.Pitch                         Music.Pitch.Absolute                         Music.Pitch.Equal                         Music.Pitch.Common+                        Music.Pitch.Common.Quality+                        Music.Pitch.Common.Number+                        Music.Pitch.Common.Diatonic+                        Music.Pitch.Common.Chromatic                         Music.Pitch.Common.Interval                         Music.Pitch.Common.Pitch                         Music.Pitch.Common.Semitones                         Music.Pitch.Common.Spell                         Music.Pitch.Common.Harmony+                        Music.Pitch.Common.Names+                        Music.Pitch.Ambitus                         Music.Pitch.StaffLines                         Music.Pitch.Clef                         Music.Pitch.Tokawa                         Music.Pitch.Intonation     hs-source-dirs:     src     default-language:   Haskell2010+    ghc-options:        -fno-warn-typed-holes
src/Music/Pitch.hs view
@@ -14,33 +14,20 @@ -------------------------------------------------------------------------------------  module Music.Pitch (-        -- * Prerequisites         module Data.Semigroup,         module Data.VectorSpace,         module Data.AffineSpace,         module Data.AffineSpace.Point,--        -- * Pitch representation-        -        -- -- | Augmentation and diminishing, generalized to work on all interval types.         module Music.Pitch.Augmentable,--        -- -- | Alteration, sharps and flats, generalized to work on all pitch types.         module Music.Pitch.Alterable,--        -- -- | Frequency, cents and other absolute measurements of pitch.         module Music.Pitch.Absolute,--        -- -- | Pitch and intervals, as defined in Common Music Theory (CMT).-        -- ---        -- --   Includes representation of common practice pitches and intervals such as /c sharp/, -        -- --   /diminished second/ and so on.+        module Music.Pitch.Ambitus,+        module Music.Pitch.Equal,         module Music.Pitch.Common,--        -- * Intonation+        module Music.Pitch.Common.Names,+        module Music.Pitch.StaffLines,+        module Music.Pitch.Clef,         module Music.Pitch.Intonation,-        -        -- * Pitch literals         module Music.Pitch.Literal,   ) where @@ -48,11 +35,15 @@ import Data.VectorSpace hiding (Sum, getSum) import Data.AffineSpace import Data.AffineSpace.Point- import Music.Pitch.Absolute import Music.Pitch.Augmentable import Music.Pitch.Alterable+import Music.Pitch.Ambitus+import Music.Pitch.Equal import Music.Pitch.Common+import Music.Pitch.Common.Names import Music.Pitch.Literal+import Music.Pitch.StaffLines+import Music.Pitch.Clef import Music.Pitch.Intonation 
src/Music/Pitch/Absolute.hs view
@@ -1,5 +1,6 @@ -{-# LANGUAGE GeneralizedNewtypeDeriving, TypeFamilies #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE TypeFamilies               #-}  ------------------------------------------------------------------------------------- -- |@@ -12,78 +13,82 @@ -- Portability : portable -- -- Absolute pitch representation.--- --- The canonical pitch representation is frequency in Hertz (Hz). For conversion, see--- 'HasFrequency'. --+-- The canonical pitch representation is frequency in Hertz (Hz).+--+-- For conversion, see 'HasFrequency'.+-- -------------------------------------------------------------------------------------  module Music.Pitch.Absolute (+        -- * Absolute pitch representation         Hertz(..),         -- FreqRatio(..),         -- Octaves,         Cents,         Fifths,+        +        -- * HasFrequency class         HasFrequency(..),         -- octaves,         fifths,         cents,   ) where -import Data.Maybe-import Data.Either-import Data.Semigroup-import Data.VectorSpace-import Data.AdditiveGroup-import Data.AffineSpace-import Control.Monad-import Control.Applicative+import           Control.Applicative+import           Control.Monad+import           Data.AdditiveGroup+import           Data.AffineSpace+import           Data.Either+import           Data.Maybe+import           Data.Semigroup+import           Data.VectorSpace -import Music.Pitch.Literal+import           Music.Pitch.Literal --- | --- Absolute frequency in Hertz.    --- +-- |+-- Absolute frequency in Hertz.+-- newtype Hertz = Hertz { getHertz :: Double }-    deriving (Read, Show, Eq, Enum, Num, Ord, Fractional, Floating, Real, RealFrac)+  deriving (Read, Show, Eq, Enum, Num, Ord, Fractional, Floating, Real, RealFrac)  {---- | +-- | -- A ratio between two different (Hertz) frequencies.--- +-- newtype FreqRatio = FreqRatio { getFreqRatio :: Double }-    deriving (Read, Show, Eq, Enum, Num, Ord, Fractional, Floating, Real, RealFrac)+  deriving (Read, Show, Eq, Enum, Num, Ord, Fractional, Floating, Real, RealFrac) -} --- | +-- | -- Number of pure octaves. -- -- Octaves are a logarithmic representation of frequency such that ----- > f * (2/1) = frequency (octaves f + 1)    --- +-- > f * (2/1) = frequency (octaves f + 1)+-- newtype Octaves = Octaves { getOctaves :: Hertz }-    deriving (Read, Show, Eq, Enum, Num, Ord, Fractional, Floating, Real, RealFrac)+  deriving (Read, Show, Eq, Enum, Num, Ord, Fractional, Floating, Real, RealFrac) --- | +-- | -- Number of pure octaves. -- -- Cents are a logarithmic representation of frequency such that ----- > f * (2/1) = frequency (cents f + 1200)    --- +-- > f * (2/1) = frequency (cents f + 1200)+-- newtype Cents = Cents { getCents :: Hertz }-    deriving (Read, Show, Eq, Enum, Num, Ord, Fractional, Floating, Real, RealFrac)+  deriving (Read, Show, Eq, Enum, Num, Ord, Fractional, Floating, Real, RealFrac) --- | +-- | -- Number of pure fifths. -- -- Fifths are a logarithmic representation of frequency. ----- > f * (3/2) = frequency (fifths f + 1)    --- +-- > f * (3/2) = frequency (fifths f + 1)+-- newtype Fifths = Fifths { getFifths :: Hertz }-    deriving (Read, Show, Eq, Enum, Num, Ord, Fractional, Floating, Real, RealFrac)+  deriving (Read, Show, Eq, Enum, Num, Ord, Fractional, Floating, Real, RealFrac)   instance Semigroup Hertz    where (<>) = (*)@@ -98,13 +103,13 @@  {- instance AdditiveGroup FreqRatio where-    zeroV   = 1-    (^+^)   = (*)-    negateV f = 1 / f+  zeroV   = 1+  (^+^)   = (*)+  negateV f = 1 / f  instance VectorSpace FreqRatio where-    type Scalar FreqRatio = Double-    (*^) x f = FreqRatio ((getFreqRatio f) ** x)+  type Scalar FreqRatio = Double+  (*^) x f = FreqRatio ((getFreqRatio f) ** x)  instance AffineSpace Hertz where   type Diff Hertz = FreqRatio@@ -112,13 +117,13 @@   (.+^) p f = Hertz $ (getHertz p) * (getFreqRatio f) -} instance AdditiveGroup Hertz where-    zeroV   = 1-    (^+^)   = (*)-    negateV f = 1 / f+  zeroV   = 1+  (^+^)   = (*)+  negateV f = 1 / f  instance VectorSpace Hertz where-    type Scalar Hertz = Hertz-    (*^) x f = Hertz ((getHertz f) ** getHertz x)+  type Scalar Hertz = Hertz+  (*^) x f = Hertz ((getHertz f) ** getHertz x)  instance AffineSpace Hertz where   type Diff Hertz = Hertz@@ -126,19 +131,19 @@   (.+^) = (+)  class HasFrequency a where-    frequency :: a -> Hertz+  frequency :: a -> Hertz  instance HasFrequency Hertz where-    frequency = id+  frequency = id  instance HasFrequency Octaves where-    frequency (Octaves f)  = (2/1) ** f+  frequency (Octaves f) = (2/1) ** f  instance HasFrequency Fifths where-    frequency (Fifths f)   =  (3/2) ** f+  frequency (Fifths f)  =  (3/2) ** f  instance HasFrequency Cents where-    frequency (Cents f)    =  (2/1) ** (f / 1200)+  frequency (Cents f)   =  (2/1) ** (f / 1200)  octaves :: HasFrequency a => a -> Octaves octaves a = Octaves $ logBase (2/1) (frequency a)@@ -149,14 +154,14 @@ cents :: HasFrequency a => a -> Cents cents a = Cents $ logBase (2/1) (frequency a) * 1200 --- +-- -- For convenience. TODO problematic for these reasons:--- +-- --  * Confusing as _P8+m2 is not the same as _P8<>m2 --  * Does not work with HasPitch (up, down...) etc as we do not have an affine/vector space pair -- -- Can we fix this with newtype wrappers?--- +-- instance IsInterval Hertz where   fromInterval (IntervalL (o,d,c)) = (2**fromIntegral o) * (r !! fromIntegral c)     where
+ src/Music/Pitch/Ambitus.hs view
@@ -0,0 +1,49 @@++{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE MultiParamTypeClasses #-}++------------------------------------------------------------------------------------+-- |+-- Copyright   : (c) Hans Hoglund, Edward Lilley 2012–2014+--+-- License     : BSD-style+--+-- Maintainer  : hans@hanshoglund.se+-- Stability   : experimental+-- Portability : non-portable (TF,GNTD)+--+-- Musical ambitus, or pitch ranges.+--+-------------------------------------------------------------------------------------++module Music.Pitch.Ambitus where++import Data.Interval hiding (Interval, interval)+import qualified Data.Interval as I+import Control.Lens++-- | An ambitus is a closed interval (in the mathematical sense).+-- +-- Also known as /range/ or /tessitura/, this type can be used to restrict the+-- range of a melody, chord or other pitch container.+-- +-- It is also used in @music-parts@ to represent the range of instruments.+-- +newtype Ambitus a = Ambitus { getAmbitus :: (I.Interval a) }++instance Wrapped (Ambitus a) where+  type Unwrapped (Ambitus a) = I.Interval a+  _Wrapped' = iso getAmbitus Ambitus+instance Rewrapped (Ambitus a) (Ambitus b)++instance (Show a, Num a, Ord a) => Show (Ambitus a) where+  show a = show (a^.from ambitus) ++ "^.ambitus"++ambitus :: (Num a, Ord a) => Iso' (a, a) (Ambitus a)+ambitus = iso toA unA . _Unwrapped+  where+    toA = (\(m, n) -> (I.<=..<=) (Finite m) (Finite n))+    unA a = case (I.lowerBound a, I.upperBound a) of+      (Finite m, Finite n) -> (m, n)++
src/Music/Pitch/Clef.hs view
@@ -12,14 +12,42 @@ {-# LANGUAGE ScopedTypeVariables        #-} {-# LANGUAGE TypeFamilies               #-} +------------------------------------------------------------------------------------+-- |+-- Copyright   : (c) Hans Hoglund, Edward Lilley 2012–2014+--+-- License     : BSD-style+--+-- Maintainer  : hans@hanshoglund.se+-- Stability   : experimental+-- Portability : non-portable (TF,GNTD)+--+-- Clefs and staff positions.+--+-------------------------------------------------------------------------------------+ module Music.Pitch.Clef (+      -- * Clef representation       ClefSymbol,-      OctaveAdjustment,+      ClefOctave,       Clef,       symbolName,       symbolPitch,       positionPitch,       pitchPosition,+      -- ** Properties+      isModernClef,+      isHistoricalClef,+      isVoiceClef,++      -- * Standard clefs+      trebleClef,+      bassClef,+      sopranoClef,+      mezzoSopranoClef,+      altoClef,+      tenorClef,+      baritoneClef,   ) where  import Data.Typeable@@ -31,9 +59,10 @@ data ClefSymbol = GClef | CClef | FClef | PercClef | NeutralClef     deriving (Eq, Ord, Show, Typeable) -type OctaveAdjustment = Integer+type ClefOctave = Integer+type ClefLine   = StaffLines -type Clef = (ClefSymbol, OctaveAdjustment, StaffLines)+type Clef = (ClefSymbol, ClefOctave, ClefLine)  symbolName :: ClefSymbol -> String symbolName GClef = "G clef"@@ -79,11 +108,33 @@   If 1), do we need to separate G/C/F in ClefSymbol, maybe just put a single constructor for common pitch.   In that case, maybe a function isStandardClefPitch (i.e. c/f/g) would be appropriate. -}-+trebleClef :: Clef+bassClef :: Clef+sopranoClef :: Clef+mezzoSopranoClef :: Clef+altoClef :: Clef+tenorClef :: Clef+baritoneClef :: Clef+trebleClef        = (GClef, -1 :: ClefOctave, -1 :: ClefLine)+bassClef          = (FClef, 1  :: ClefOctave, -1 :: ClefLine)+sopranoClef       = (CClef, 0  :: ClefOctave, -2 :: ClefLine)+mezzoSopranoClef  = (CClef, 0  :: ClefOctave, -1 :: ClefLine)+altoClef          = (CClef, 0  :: ClefOctave, 0  :: ClefLine)+tenorClef         = (CClef, 0  :: ClefOctave, 1  :: ClefLine)+baritoneClef      = (CClef, 0  :: ClefOctave, 2  :: ClefLine) --- isModernClef :: Clef -> Bool--- isHistoricalClef :: Clef -> Bool+isModernClef :: Clef -> Bool+isModernClef x | x == trebleClef  = True+isModernClef x | x == bassClef    = True+isModernClef x | x == altoClef    = True+isModernClef x | x == tenorClef   = True+isModernClef x | otherwise        = False --- i.e. a c clef on some staff--- isVoiceClef :: Clef -> Bool+isHistoricalClef :: Clef -> Bool+isHistoricalClef _ = False +-- | Is this a voice clef, i.e. a c clef on some staff.+isVoiceClef :: Clef -> Bool+isVoiceClef x | x == altoClef    = True+isVoiceClef x | x == tenorClef   = True+isVoiceClef x | otherwise        = False
src/Music/Pitch/Common.hs view
@@ -14,134 +14,16 @@ -------------------------------------------------------------------------------------  module Music.Pitch.Common (-    -- -- * Enharmonic representation-    -- -- ** Octaves-    -- Octaves,-    -- -- HasOctaves(..),-    -- -    -- -- ** Steps-    -- -- Steps,-    -- -- HasSteps(..),-    -- -    -- -- ** Semitones-    -- Semitones,-    -- HasSemitones(..),-    -- semitone,-    -- tone,-    -- ditone,-    -- tritone,-    -- isSemitone,-    -- isTone,-    -- isTritone,-    -- -    -- -- ** Enharmonic equivalence-    -- (=:=),-    -- (/:=),-    -- -    -- -- * Pitches-    -- -- ** Name type-    -- Name(..),-    -- -    -- -- ** Accidental  type-    -- Accidental,-    -- doubleFlat, -    -- flat, -    -- natural, -    -- sharp, -    -- doubleSharp,-    -- -    -- -- *** Inspecting accidentals-    -- isNatural,-    -- isSharpened,-    -- isFlattened,-    -- isStandard,-    -- -    -- -- ** Pitch type-    -- Pitch,    -    -- pitch,-    -- name,-    -- accidental,-    -- asPitch,-    -- -    -- -- module Music.Pitch.Common.Name,-    -- -- module Music.Pitch.Common.Accidental,-    -- -- module Music.Pitch.Common.Pitch,-    -- -    -- -- * Intervals-    -- -- ** Number type-    -- Number,-    -- HasNumber(..),   -    -- unison,-    -- prime,-    -- second,-    -- third,-    -- fourth,-    -- fifth,-    -- sixth,-    -- seventh,-    -- octave,-    -- ninth,-    -- tenth,-    -- twelfth, -    -- duodecim,-    -- thirteenth,-    -- fourteenth,-    -- fifteenth,-    -- -    -- -- ** Quality type-    -- Quality(..),    -    -- HasQuality(..),-    -- invertQuality,-    -- isPerfect,-    -- isMajor,-    -- isMinor,-    -- isAugmented,-    -- isDiminished,-    -- -    -- -- ** Interval type-    -- Interval,-    -- -    -- -- *** Creating intervals-    -- interval,-    -- perfect,-    -- major,-    -- minor,-    -- augmented,-    -- diminished,-    -- doublyAugmented,-    -- doublyDiminished,-    -- asInterval,-    -- -    -- -- *** Inspecting intervals-    -- isNegative,-    -- isPositive,-    -- isNonNegative,-    -- isPerfectUnison,-    -- isStep,-    -- isLeap,-    -- -    -- -- *** Simple and compound intervals-    -- isSimple,-    -- isCompound,-    -- separate,-    -- octaves,-    -- simple,-    -- -    -- -- *** Inversion-    -- invert,  --    -- * Enharmonic representation     module Music.Pitch.Common.Semitones,--    -- * Non-enharmonic representation+    module Music.Pitch.Common.Quality,+    module Music.Pitch.Common.Number,+    module Music.Pitch.Common.Diatonic,+    module Music.Pitch.Common.Chromatic,     module Music.Pitch.Common.Interval,     module Music.Pitch.Common.Pitch,--    -- * Utility     module Music.Pitch.Common.Spell,     module Music.Pitch.Common.Harmony,-)-where+  ) where  import Data.Maybe import Data.Either@@ -150,105 +32,15 @@ import Data.AffineSpace import Control.Monad import Control.Applicative-import qualified Data.List as List  import Music.Pitch.Absolute import Music.Pitch.Literal import Music.Pitch.Common.Pitch+import Music.Pitch.Common.Quality+import Music.Pitch.Common.Number+import Music.Pitch.Common.Diatonic+import Music.Pitch.Common.Chromatic import Music.Pitch.Common.Interval import Music.Pitch.Common.Semitones import Music.Pitch.Common.Spell import Music.Pitch.Common.Harmony---{-  -        Semitones is the smallest musical unit (Semitones in Western music)-        -        The `semitones` function retrieves the number of Semitones in a pitch, for example-            semitones :: Interval -> Semitones-            semitones major third = 4--        Note that semitones is surjetive. We can define a non-deterministic function `spellings`-            spellings :: Semitones -> [Interval]-            spellings 4 = [majorThird, diminishedFourth]-        Law-            map semitones (spellings a) = replicate n a    for all n > 0-        Lemma-            map semitones (spellings a)-        --        isHemitonic   [1,2,2] = True-        isHemitonic   [2,2,2] = False-        isCohemitonic [1,1,2] = True-        isCohemitonic [1,2,1] = False-        isTritonic ...-        -        A Scale is a [Semitones], for example [2,2,1,2,2,2,1]-            From this we can derive       [2,4,5,7,9,11,12]-        A Scale is a function (Number -> Interval)-        A Scale is a function (Number -> Semitones)--        -- TODO simplify etc-        isMelodicDissonance :: Interval -> Bool---    "Post-tonal"-    -        Messiaen-        -        mode1 = [2,2,2,2,2]-        mode2 = [1,2, 1,2, 1,2, 1,2]-        mode3 = [2,1,1, 2,1,1, 2,1,1]-        mode4 = [1,1,3,1,   1,1,3,1]-        mode5 = [1,4,1,     1,4,1]-        mode6 = [2,2,1,1,   2,2,1,1]-        mode7 = [1,1,1,2,1, 1,1,1,2,1]----   Old stuff>------ Semitone is an enumerated associated type-type family Semitone a :: *-type family Alteration a :: *---- A scale is a function :: Semitone a -> a-newtype Scale a = Scale { getScale :: [Semitone a] } --- Eq, Show--semitone :: Scale a -> Semitone a -> a-semitone = undefined---semitone (Scale xs) p = xs !! (fromIntegral p `mod` length xs)---fromSemitone :: (Num a, Ord a, Integral b, Num c) => Scale a -> b -> c-fromSemitone (Scale xs) p = fromIntegral $ fromMaybe (length xs - 1) $ List.findIndex (>= fromIntegral p) xs--scaleFromSemitones :: Num a => [a] -> Scale a-scaleFromSemitones = Scale . accum-    where-        accum = snd . List.mapAccumL add 0-        add a x = (a + x, a + x)---- numberOfSemitones :: Scale a -> Int-numberOfSemitones = length . getScale--major :: Num a => Scale a-major = scaleFromSemitones [0,2,2,1,2,2,2,1]--naturalMinor :: Num a => Scale a-naturalMinor = scaleFromSemitones [0,2,1,2,2,1,2,2]--harmonicMinor :: Num a => Scale a                     -harmonicMinor = scaleFromSemitones [0,2,1,2,2,1,3,1]---}----- or' :: (t -> Bool) -> (t -> Bool) -> t -> Bool--- or' p q x = p x || q x---- replicate' n = replicate (fromIntegral n)
+ src/Music/Pitch/Common/Chromatic.hs view
@@ -0,0 +1,13 @@++{-# LANGUAGE DeriveDataTypeable         #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE NoMonomorphismRestriction  #-}+{-# LANGUAGE StandaloneDeriving         #-}+{-# LANGUAGE TypeFamilies               #-}++module Music.Pitch.Common.Chromatic where+++newtype ChromaticSteps = ChromaticSteps { getChromaticSteps :: Integer }+  deriving (Eq, Ord, Show, Enum, Num, Real, Integral)+
+ src/Music/Pitch/Common/Diatonic.hs view
@@ -0,0 +1,11 @@++{-# LANGUAGE DeriveDataTypeable         #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE NoMonomorphismRestriction  #-}+{-# LANGUAGE StandaloneDeriving         #-}+{-# LANGUAGE TypeFamilies               #-}++module Music.Pitch.Common.Diatonic where++newtype DiatonicSteps = DiatonicSteps { getDiatonicSteps :: Integer }+  deriving (Eq, Ord, Show, Enum, Num, Real, Integral)
src/Music/Pitch/Common/Harmony.hs view
@@ -1,4 +1,18 @@ +------------------------------------------------------------------------------------+-- |+-- Copyright   : (c) Hans Hoglund, Edward Lilley 2012–2014+--+-- License     : BSD-style+--+-- Maintainer  : hans@hanshoglund.se+-- Stability   : experimental+-- Portability : non-portable (TF,GNTD)+--+-- Provides standard intervals.+--+-------------------------------------------------------------------------------------+ module Music.Pitch.Common.Harmony (         isDissonance,         isConsonance,@@ -9,6 +23,8 @@   ) where  import Music.Pitch.Common.Interval+import Music.Pitch.Common.Number+import Music.Pitch.Common.Quality import Music.Pitch.Literal        import Data.Semigroup@@ -25,9 +41,9 @@ -- | Whether the given interval is a (harmonic) dissonance. isDissonance :: Interval -> Bool isDissonance x = case number (simple x) of-    2 -> True-    7 -> True-    _ -> False+  2 -> True+  7 -> True+  _ -> False  -- | Whether the given interval is a (harmonic) consonance. isConsonance :: Interval -> Bool@@ -36,17 +52,17 @@ -- | Whether the given interval is a perfect (harmonic) consonance. isPerfectConsonance :: Interval -> Bool isPerfectConsonance x = case number (simple x) of-    1 -> True-    4 -> True-    5 -> True-    _ -> False+  1 -> True+  4 -> True+  5 -> True+  _ -> False  -- | Whether the given interval is an imperfect (harmonic) consonance. isImperfectConsonance :: Interval -> Bool isImperfectConsonance x = case number (simple x) of-    3 -> True-    6 -> True-    _ -> False+  3 -> True+  6 -> True+  _ -> False  -- | Whether the given interval is a melodic dissonance. isMelodicDissonance :: Interval -> Bool@@ -56,6 +72,7 @@ isMelodicConsonance :: Interval -> Bool isMelodicConsonance x = quality x `elem` [Perfect, Major, Minor] +{- type Chord = Set Interval  majorTriad, minorTriad :: Chord@@ -67,3 +84,4 @@ maj7 = (<> Set.fromList [_M7])  +-}
src/Music/Pitch/Common/Interval.hs view
@@ -1,6 +1,9 @@ -{-# LANGUAGE GeneralizedNewtypeDeriving, StandaloneDeriving, TypeFamilies,-             NoMonomorphismRestriction, DeriveDataTypeable #-}+{-# LANGUAGE DeriveDataTypeable         #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE NoMonomorphismRestriction  #-}+{-# LANGUAGE StandaloneDeriving         #-}+{-# LANGUAGE TypeFamilies               #-}  ------------------------------------------------------------------------------------ -- |@@ -17,41 +20,19 @@ -------------------------------------------------------------------------------------  module Music.Pitch.Common.Interval (-        -- * Quality-        Quality(..),    -        HasQuality(..),-        invertQuality,-        isPerfect,-        isMajor,-        isMinor,-        isAugmented,-        isDiminished, -        -- ** Number-        Number,-        HasNumber(..),   -        unison,-        prime,-        second,-        third,-        fourth,-        fifth,-        sixth,-        seventh,-        octave,-        ninth,-        tenth,-        twelfth, -        duodecim,-        thirteenth,-        fourteenth,-        fifteenth,   -        -- ** Intervals-        Interval(..),--        -- *** Creating intervals-        mkInterval,+        -- * Intervals+        Interval,+        -- ** Creating intervals+        interval,+        interval',+        _number,+        _quality,+        _steps,+        _alteration,+        +        -- ** Synonyms         perfect,         major,         minor,@@ -60,7 +41,7 @@         doublyAugmented,         doublyDiminished, -        -- *** Inspecting intervals+        -- ** Inspecting intervals         isNegative,         isPositive,         isNonNegative,@@ -68,7 +49,7 @@         isStep,         isLeap, -        -- *** Simple and compound intervals+        -- ** Simple and compound intervals         isSimple,         isCompound,         separate,@@ -83,235 +64,59 @@          -- * Basis values         IntervalBasis(..),-       +         -- ** Converting basis         convertBasis,         convertBasisFloat,         intervalDiv,-        -        -- ** Basis values (TODO cleanup)-        basis_P1,-        basis_A1,-        basis_d2,-        basis_P8,-        basis_P5,-        -        -- ** Utility-        intervalDiff,-        mkInterval',   ) where -import Data.Maybe-import Data.Either-import Data.Semigroup-import Data.VectorSpace--- import Data.AffineSpace-import Data.Basis-import Data.Typeable-import Control.Monad-import Control.Applicative-import qualified Data.List as List+import           Data.Either+import           Data.Maybe+import           Data.Semigroup+import           Data.VectorSpace+import           Data.AffineSpace.Point (relative)+import           Control.Applicative+import           Control.Monad+import           Control.Lens hiding (simple)+import           Data.Basis+import qualified Data.List                    as List+import           Data.Typeable+import           Numeric.Positive -import Music.Pitch.Absolute-import Music.Pitch.Augmentable-import Music.Pitch.Literal-import Music.Pitch.Common.Semitones+import           Music.Pitch.Absolute+import           Music.Pitch.Augmentable+import           Music.Pitch.Common.Semitones+import           Music.Pitch.Common.Quality+import           Music.Pitch.Common.Number+import           Music.Pitch.Common.Chromatic+import           Music.Pitch.Common.Diatonic+import           Music.Pitch.Literal --- |--- Interval quality is either perfect, major, minor, augmented, and--- diminished. This representation allows for an arbitrary number of--- augmentation or diminishions, so /augmented/ is represented by @Augmented--- 1@, /doubly augmented/ by @Augmented 2@ and so on.------ The quality of a compound interval is the quality of the simple interval on--- which it is based.------ Note that (Augmented 0) and (Diminished 0) are superfluous identity--- values, use Perfect instead. Augmented and Diminished must also--- take only positive arguments. -data Quality-    = Major-    | Minor-    | Perfect-    | Augmented Int-    | Diminished Int-    deriving (Eq, Ord, Show) -instance HasQuality Quality where-    quality = id  --- | Augmentable Quality instance--- --- This Augmentable instance exists solely for use of the getQuality--- function, which ensures that there is never any ambiguity around--- diminished/augmented intervals turning into major/minor/perfect--- intervals. -instance Augmentable Quality where-  augment Major = Augmented 1-  augment Minor = Major-  augment Perfect = Augmented 1-  augment (Augmented n) = Augmented (n + 1)-  augment (Diminished n) = Diminished (n - 1)-  diminish Major = Minor-  diminish Minor = Diminished 1-  diminish Perfect = Diminished 1-  diminish (Augmented n) = Augmented (n - 1)-  diminish (Diminished n) = Diminished (n + 1) -class HasQuality a where-    quality :: a -> Quality --- |--- Invert a quality.--- --- Perfect is unaffected, major becomes minor and vice versa, augmented--- becomes diminished and vice versa. ----invertQuality :: Quality -> Quality-invertQuality = go-    where-        go Major            = Minor-        go Minor            = Major-        go Perfect          = Perfect-        go (Augmented n)    = Diminished n-        go (Diminished n)   = Augmented n  --- | --- Returns whether the given quality is perfect.--- -isPerfect :: HasQuality a => a -> Bool-isPerfect a = case quality a of { Perfect -> True ; _ -> False } --- | --- Returns whether the given quality is major.--- -isMajor :: HasQuality a => a -> Bool-isMajor a = case quality a of { Major -> True ; _ -> False } --- | --- Returns whether the given quality is minor.--- -isMinor :: HasQuality a => a -> Bool-isMinor a = case quality a of { Minor -> True ; _ -> False } --- | --- Returns whether the given quality is /augmented/ (including double augmented etc).--- -isAugmented :: HasQuality a => a -> Bool-isAugmented a = case quality a of { Augmented _ -> True ; _ -> False } --- | --- Returns whether the given quality is /diminished/ (including double diminished etc).--- -isDiminished :: HasQuality a => a -> Bool-isDiminished a = case quality a of { Diminished _ -> True ; _ -> False }- -- |--- The number portion of an interval (i.e. second, third, etc).------ Note that the interval number is always one step larger than number of steps spanned by--- the interval (i.e. a third spans two diatonic steps). Thus 'number' does not distribute--- over addition:------ > number (a + b) = number a + number b - 1+-- A musical interval such as minor third, augmented fifth, duodecim etc. ---newtype Number = Number { getNumber :: Int }-    deriving (Eq, Ord, Num, Enum, Real, Integral)-    -instance Show Number where { show = show . getNumber }-instance HasNumber Number where number = id----- | A synonym for @1@.-unison      :: Number-unison      = 1---- | A synonym for @1@.-prime       :: Number-prime       = 1---- | A synonym for @2@.-second      :: Number-second      = 2---- | A synonym for @3@.-third       :: Number-third       = 3---- | A synonym for @4@.-fourth      :: Number-fourth      = 4     ---- | A synonym for @5@.-fifth       :: Number-fifth       = 5---- | A synonym for @6@.-sixth       :: Number-sixth       = 6---- | A synonym for @7@.-seventh     :: Number-seventh     = 7---- | A synonym for @8@.-octave      :: Number-octave      = 8---- | A synonym for @9@.-ninth       :: Number-ninth       = 9---- | A synonym for @10@.-tenth       :: Number-tenth       = 10---- | A synonym for @11@.-eleventh    :: Number-eleventh    = 11---- | A synonym for @12@.-twelfth     :: Number-twelfth     = 12---- | A synonym for @12@.-duodecim    :: Number-duodecim    = 12---- | A synonym for @13@.-thirteenth  :: Number-thirteenth  = 13---- | A synonym for @14@.-fourteenth  :: Number-fourteenth  = 14---- | A synonym for @15@.-fifteenth   :: Number-fifteenth   = 15--class HasNumber a where-    -- |-    -- Returns the number portion of an interval.-    ---    -- The interval number is negative if and only if the interval is negative.-    ---    -- See also 'quality', 'octaves' and 'semitones'.-    ---    number :: a -> Number--                                                   -                                                   --- |--- An interval is the difference between two pitches, incuding negative--- intervals.+-- We include direction in in this definition, so a downward minor third (written @-m3@)+-- is distinct from an upward minor third (written @m3@). Note that @_P1@ and @-P1@ are+-- synynoms. ----- Intervals and pitches can be added using '.+^'. To get the interval between--- two pitches, use '.-.'.+-- Not to be confused with a mathematical inverval in pitch space, which is called+-- 'Ambitus'. Intervals and pitches form an affine-vector space pair with intervals and+-- /vectors/ and pitches as /points/. To add an interval to a, use '.+^'. To get the+-- interval between two pitches, use '.-.'. -- -- > c .+^ minor third == eb -- > f .-. c           == perfect fourth@@ -321,36 +126,41 @@ -- > m3 ^+^ _M3 = _P5 -- > d5 ^+^ _M6 = m10 ----- The scalar type of 'Interval' is 'Int', using '^*' to stack intervals of a certain--- type on top of each other. For example @_P5 ^* 2@ is a stack of 2 perfect fifths, or a--- major ninth. The 'Num' instance works as expected for '+', 'negate' and 'abs', and+-- The scalar type of 'Interval' is 'Int', using '^*' to stack intervals of a certain type+-- on top of each other. For example @_P5 ^* 2@ is a stack of 2 perfect fifths, or a major+-- ninth. The 'Num' instance works as expected for '+', 'negate' and 'abs', and -- (arbitrarily) uses minor seconds for multiplication. If you find yourself '*', or -- 'signum' on intervals, consider switching to '*^' or 'normalized'. ----- Intervals are generally described in terms of 'Quality' and 'Number'. To--- construct an interval, use the 'interval' constructor, the utility--- constructors 'major', 'minor', 'augmented' and 'diminished', or the--- interval literals:+-- Intervals are generally described in terms of 'Quality' and 'Number'. To construct an+-- interval, use the 'interval' constructor, the utility constructors 'major', 'minor',+-- 'augmented' and 'diminished', or the interval literals: ----- > m5  == minor   fifth    == interval Minor   5--- > _P4 == perfect fourth   == interval Perfect 5--- > d5  == diminished fifth == diminish (perfect fifth)+-- > m5  == minor   fifth    == interval Minor   5 > _P4 == perfect fourth   == interval+-- Perfect 5 > d5  == diminished fifth == diminish (perfect fifth) -- newtype Interval = Interval { getInterval :: (-            Int,        -- number of A1, i.e. chromatic steps-            Int        -- number of d2, i.e. diatonic steps+            Int,  -- Number of A1, i.e. chromatic steps+            Int   -- Number of d2, i.e. diatonic steps     ) }-    deriving (Eq, Ord, Typeable)+    deriving (Eq, Typeable) +-- | Lexicographical ordering, comparing the 'd2' component of the+-- Interval first, as it's tied to the Number which is expected to be+-- 'bigger' than the Quality, assuming ordinary tuning systems+instance Ord Interval where+  Interval a `compare` Interval b = swap a `compare` swap b+    where swap (x,y) = (y,x)+ -- | Avoid using '(*)', or 'signum' on intervals. instance Num Interval where-    (+)           = addInterval-    negate        = negateInterval-    abs a         = if isNegative a then negate a else a-    (*)           = error "Music.Pitch.Common.Interval: no overloading for (*)"-    signum        = error "Music.Pitch.Common.Interval: no overloading for signum"-    fromInteger   = error "Music.Pitch.Common.Interval: no overloading for fromInteger"-        +  (+)           = addInterval+  negate        = negateInterval+  abs a         = if isNegative a then negate a else a+  (*)           = error "Music.Pitch.Common.Interval: no overloading for (*)"+  signum        = error "Music.Pitch.Common.Interval: no overloading for signum"+  fromInteger   = error "Music.Pitch.Common.Interval: no overloading for fromInteger"+ instance Show Interval where   show a     | isNegative a = "-" ++ showQuality (extractQuality a) ++ show (abs $ extractNumber a)@@ -359,24 +169,24 @@       showQuality Major            = "_M"       showQuality Minor            = "m"       showQuality Perfect          = "_P"-      showQuality (Augmented n)    = "_" ++ replicate' n 'A'-      showQuality (Diminished n)   = replicate' n 'd'+      showQuality (Augmented n)    = "_" ++ replicate (fromIntegral n) 'A'+      showQuality (Diminished n)   = replicate (fromIntegral n) 'd'  instance Semigroup Interval where-    (<>)    = addInterval+  (<>)    = addInterval  instance Monoid Interval where-    mempty  = perfect unison-    mappend = addInterval+  mempty  = basis_P1+  mappend = addInterval  instance AdditiveGroup Interval where-    zeroV   = perfect unison-    (^+^)   = addInterval-    negateV = negateInterval+  zeroV   = basis_P1+  (^+^)   = addInterval+  negateV = negateInterval  instance VectorSpace Interval where-    type Scalar Interval = Integer-    (*^) = stackInterval+  type Scalar Interval = Integer+  (*^) = stackInterval  -- TODO move data IntervalBasis = Chromatic | Diatonic@@ -413,8 +223,9 @@ addInterval (Interval (a1, d1)) (Interval (a2, d2)) = Interval (a1 + a2, d1 + d2)  stackInterval :: Integer -> Interval -> Interval-stackInterval n a | n >= 0    = mconcat $ replicate (fromIntegral n) a-                  | otherwise = negate $ stackInterval (negate n) a+stackInterval n a+  | n >= 0    = mconcat $ replicate (fromIntegral n) a+  | otherwise = negate $ stackInterval (negate n) a  intervalDiff :: Interval -> Int intervalDiff (Interval (c, d)) = c - diatonicToChromatic d@@ -426,7 +237,7 @@ -- major interval instead. Given 'Major' or 'Minor' with a number indicating a perfect -- consonance, 'interval' returns a perfect or diminished interval respectively. ---mkInterval' +mkInterval'   :: Int        -- ^ Difference in chromatic steps (?).   -> Int        -- ^ Number of diatonic steps (NOT interval number).   -> Interval@@ -439,63 +250,7 @@ basis_P8 = Interval (12, 7)  -mkInterval :: Quality -> Number -> Interval - -- our identity:-mkInterval Perfect 1 = basis_P1- -- and our two basis vectors:-mkInterval (Augmented 1) 1 = basis_A1-mkInterval (Diminished 1) 2 = basis_d2--mkInterval Minor 2 = basis_d2 ^+^ basis_A1-mkInterval Major 2 = (mkInterval Minor 2) ^+^ basis_A1-mkInterval (Augmented 1) 2 = (mkInterval Major 2) ^+^ basis_A1--mkInterval (Diminished 1) 3 = (mkInterval Minor 3) ^-^ basis_A1-mkInterval Minor 3 = (mkInterval Major 2) ^+^ (mkInterval Minor 2)-mkInterval Major 3 = (mkInterval Major 2) ^+^ (mkInterval Major 2)-mkInterval (Augmented 1) 3 =  (mkInterval Major 3) ^+^ basis_A1--mkInterval (Diminished 1) 4 = (mkInterval Perfect 4) ^-^ basis_A1-mkInterval Perfect 4 = (mkInterval Major 3) ^+^ (mkInterval Minor 2)-mkInterval (Augmented 1) 4 =  (mkInterval Perfect 4) ^+^ basis_A1--mkInterval (Diminished 1) 5 = (mkInterval Perfect 5) ^-^ basis_A1-mkInterval Perfect 5 = (mkInterval Perfect 4) ^+^ (mkInterval Major 2)-mkInterval (Augmented 1) 5 =  (mkInterval Perfect 5) ^+^ basis_A1--mkInterval (Diminished 1) 6 = (mkInterval Minor 6) ^-^ basis_A1-mkInterval Minor 6 = (mkInterval Perfect 5) ^+^ (mkInterval Minor 2)-mkInterval Major 6 = (mkInterval Perfect 5) ^+^ (mkInterval Major 2)-mkInterval (Augmented 1) 6 =  (mkInterval Major 6) ^+^ basis_A1--mkInterval (Diminished 1) 7 = (mkInterval Minor 7) ^-^ basis_A1-mkInterval Minor 7 = (mkInterval Major 6) ^+^ (mkInterval Minor 2)-mkInterval Major 7 = (mkInterval Major 6) ^+^ (mkInterval Major 2)-mkInterval (Augmented 1) 7 =  (mkInterval Major 7) ^+^ basis_A1--mkInterval Minor 1 = error "invalid interval"-mkInterval Major 1 = error "invalid interval"-mkInterval Perfect 2 = error "invalid interval"-mkInterval Perfect 3 = error "invalid interval"-mkInterval Minor 4 = error "invalid interval"-mkInterval Major 4 = error "invalid interval"-mkInterval Minor 5 = error "invalid interval"-mkInterval Major 5 = error "invalid interval"-mkInterval Perfect 6 = error "invalid interval"-mkInterval Perfect 7 = error "invalid interval"--mkInterval (Diminished 0) n = error "(Diminished 0) is not a valid Quality"-mkInterval (Augmented 0) n = error  "(Augmented 0) is not a valid Quality"--mkInterval (Diminished q) n = (mkInterval (Diminished (q - 1)) n) ^-^ basis_A1-mkInterval (Augmented q) n = (mkInterval (Diminished (q - 1)) n) ^+^ basis_A1--mkInterval q (Number n) = if n > 0-                          then (mkInterval q (Number (n - 7))) ^+^ basis_P8-                          else (mkInterval q (Number (n + 7))) ^-^ basis_P8-- -- | -- Extracting the 'number' from an interval vector. --@@ -503,7 +258,7 @@ -- * d2), so the 'number' part of the interval must be stored entirely -- in the d * d2 part (adding a unison, perfect or otherwise, can -- never increase the number of the interval)--- +-- extractNumber :: Interval -> Number extractNumber (Interval (a, d))   | d >= 0    = Number (d + 1)@@ -588,10 +343,10 @@  Prelude Music.Prelude> separate (2*^_P8+m3) (2,m3)-Prelude Music.Prelude> +Prelude Music.Prelude> Prelude Music.Prelude> separate (3*^_P8+m3) (3,m3)-Prelude Music.Prelude> +Prelude Music.Prelude> Prelude Music.Prelude> separate (0*^_P8+m3) (0,m3) Prelude Music.Prelude> separate ((-1)*^_P8+m3)@@ -613,14 +368,7 @@ -- > _P8^*octaves x ^+^ simple x = x -- octaves :: Interval -> Octaves-octaves i -  | isNegative i && not (isOctaveMultiple i) = negate (octaves' i) - 1-  | isNegative i && isOctaveMultiple i       = negate (octaves' i)-  | otherwise                                = octaves' i--isOctaveMultiple (Interval (_,d)) = d `mod` 7 == 0--octaves' i = fromIntegral $ intervalDiv i basis_P8+octaves (Interval (_,d)) = fromIntegral $ d `div` 7  -- | -- Returns the simple part of an interval.@@ -669,7 +417,7 @@ -- Returns whether the given interval a perfect unison. -- isPerfectUnison :: Interval -> Bool-isPerfectUnison = (== perfect unison)+isPerfectUnison (Interval (a, d)) = (a,d) == (0,0)  -- | -- Returns whether the given interval is a step (a second or smaller).@@ -712,17 +460,107 @@ asInterval :: Interval -> Interval asInterval = id +++++++mkInterval :: Quality -> Number -> Interval+mkInterval q n = mkInterval' (fromIntegral diff) (fromIntegral steps)+  where+    diff  = qualityToDiff (n > 0) (expectedQualityType n) (q)+    steps = case n `compare` 0 of+      GT -> n - 1+      EQ -> error "diatonicSteps: Invalid number 0"+      LT -> n + 1+    -- steps = n^.diatonicSteps+++++++-- | View or set the alteration (i.e. the number of chromatic steps differing from the excepted number) in an interval.+_alteration :: Lens' Interval ChromaticSteps+_alteration = from interval' . _1++-- | View or set the number of chromatic steps in an interval.+_steps :: Lens' Interval DiatonicSteps+_steps = from interval' . _2++-- | View or set the quality of an interval.+_quality :: Lens' Interval Quality+_quality = from interval . _1++-- | View or set the number component of an interval.+_number :: Lens' Interval Number +_number = from interval . _2++-- | View an interval as a pair of quality and number or vice versa.+interval :: Iso' (Quality, Number) Interval+interval = iso (uncurry mkInterval) (\x -> (quality x, number x))++-- | View an interval as a pair of alteration and diatonic steps or vice versa.+interval' :: Iso' (ChromaticSteps, DiatonicSteps) Interval+interval' = iso (\(d,s) -> mkInterval' (fromIntegral d) (fromIntegral s)) +  (\x -> (qualityToDiff (number x >= 0) (expectedQualityType (number x)) (quality x), (number x)^.diatonicSteps))+ {--isPerfectNumber :: Int -> Bool-isPerfectNumber 0 = True-isPerfectNumber 1 = False-isPerfectNumber 2 = False-isPerfectNumber 3 = True-isPerfectNumber 4 = True-isPerfectNumber 5 = False-isPerfectNumber 6 = False++-- -- TODO be "nice"+-- mkIntervalNice :: Quality -> Number -> Interval+-- mkIntervalNice q n+--   | expectedQualityType n `elem` qualityTypes q = mkInterval q n +--   | expectedQualityType n == MajorMinorType     = mkInterval (toMajorMinorType q) n+--   | expectedQualityType n == PerfectType        = mkInterval (toPerfectType q) n++toMajorMinorType Perfect = Major+toPerfectType    Major   = Perfect+toPerfectType    Minor   = (Diminished 1)+-- toPerfectType    x = x+ -} ++          +{-|+>>> m3 & _number %~ pred+m2+>>> m3 & _number %~ succ+d4+>>> _M3 & _number %~ succ+_P4+++>>> m3 & _number +~ 1+d4+>>> m3 & _number +~ 2+d5+>>> m3 & _number +~ 3+m6+>>> m3 & _number +~ 4+++>>> m3 & _quality .~ Minor+m3+>>> _P5 & _quality .~ Minor+d5+>>> (-d5) & _quality %~ diminish+++TODO only obeys lens laws up to quality normalization++>>> _P5 & _quality .~ Minor+d5+>>> _P5 & _quality .~ (Diminished 1)+d5++-}             +++-- Internal stuff+ -- TODO more generic pattern here diatonicToChromatic :: Int -> Int diatonicToChromatic d = (octaves*12) + go restDia@@ -731,14 +569,6 @@         (octaves, restDia) = d `divMod` 7         go = ([0,2,4,5,7,9,11] !!) --- {-# DEPRECATED intervalDiff "This should be hidden" #-}--- {-# DEPRECATED mkInterval'  "This should be hidden "#-}--replicate' n = replicate (fromIntegral n)---- -- | Integer div of intervals: i / di = x, where x is an integer intervalDiv :: Interval -> Interval -> Int intervalDiv (Interval (a, d)) (Interval (1, 0)) = a@@ -747,7 +577,7 @@   | (i > basis_P1) = intervalDivPos i di   | (i < basis_P1) = intervalDivNeg i di   | otherwise = 0 :: Int-  where +  where     intervalDivPos i di       | (i < basis_P1) = undefined       | (i ^-^ di) < basis_P1 = 0@@ -758,36 +588,37 @@       | otherwise = 1 + (intervalDiv (i ^+^ di) di)  -- | Represent an interval i in a new basis (j, k).--- +-- -- We want x,y where i = x*j + y*k -- -- e.g., convertBasis basis_d2 _P5 basis_P8 == Just (-12,7), as expected.  convertBasis-  :: Interval -  -> Interval -  -> Interval +  :: Interval+  -> Interval+  -> Interval   -> Maybe (Int, Int) convertBasis i j k   | (p == 0) = Nothing   | not $ p `divides` r = Nothing   | not $ p `divides` q = Nothing   | otherwise = Just (r `div` p, q `div` p)-  where Interval (m, n) = i-        Interval (a, b) = j-        Interval (c, d) = k-        p = (a*d - b*c)-        q = (a*n - b*m)-        r = (d*m - c*n)+  where+    Interval (m, n) = i+    Interval (a, b) = j+    Interval (c, d) = k+    p = (a*d - b*c)+    q = (a*n - b*m)+    r = (d*m - c*n)   -- | Same as above, but don't worry if new interval has non-integer -- coefficients -- useful when getting a value to use as a frequency -- ratio in a tuning system. convertBasisFloat :: (Fractional t, Eq t)-  => Interval -  -> Interval -  -> Interval +  => Interval+  -> Interval+  -> Interval   -> Maybe (t, t) convertBasisFloat i j k   | (p == 0) = Nothing
+ src/Music/Pitch/Common/Names.hs view
@@ -0,0 +1,414 @@++------------------------------------------------------------------------------------+-- |+-- Copyright   : (c) Hans Hoglund, Edward Lilley 2012–2014+--+-- License     : BSD-style+--+-- Maintainer  : hans@hanshoglund.se+-- Stability   : experimental+-- Portability : non-portable (TF,GNTD)+--+-- Provides standard intervals.+--+-------------------------------------------------------------------------------------++module Music.Pitch.Common.Names (+      Language(..),+      Mode(..),+      showKey,+      showPitch,+      showMode,+      showSep,+  ) where++import Music.Pitch.Literal+import Music.Pitch.Common.Pitch+import Music.Pitch.Common.Interval+import Data.Maybe+import qualified Data.List++{-+Original at http://tinyurl.com/ongo4al+Use convertcsv.com to convert to JSON array+-}++data Language+  = English+  | German+  | Dutch+  | Japanese+  | Italian+  | French+  | Spanish+  | Portuguese+  | Russian+  | Romanian+  | Swedish+  | NewSwedish+  deriving (Show, Eq, Ord)+  +showPitch :: Language -> Pitch -> String+showPitch lang pitch = (!! (pitchToIndex + pitchNameOffset)) $ fromMaybe (error "showPitch: Bad lang") $ listToMaybe $ filter (\xs -> head xs == show lang) $ pitchNames+  where+    -- TODO normalize dbb etc.+    pitchToIndex = fromMaybe (error "showPitch: Bad pitch") $ Data.List.findIndex (== pitch) +      [cb,c,cs,+       db,d,ds,+       eb,e,{-es,-}+       {-fb,-}f,fs,+       gb,g,gs,+       ab,a,as,+       bb,b,bs]     +    pitchNameOffset = 3++data Mode = MajorMode | MinorMode+  deriving (Eq, Ord, Show)++showMode :: Language -> Mode -> String+showMode lang mode = (!! (modeToIndex + modeNameOffset)) $ fromMaybe (error "showMode: Bad lang") $ listToMaybe $ filter (\xs -> head xs == show lang) $ modeNames+  where+    modeToIndex = fromMaybe (error "showPitch: Bad mode") $ Data.List.findIndex (== mode) +      [MajorMode,MinorMode]     +    modeNameOffset = 1++showKey :: Language -> Pitch -> Mode -> String+showKey lang pitch mode = showPitch lang pitch ++ showSep lang ++ showMode lang mode++showSep :: Language -> String+showSep lang = fromMaybe (error "showSep: Bad lang") $ Data.List.lookup (show lang) nameModeSeparator++pitchNames :: [[String]]+-- [[language,_,_,cb,c,cs,db...bs]]+pitchNames =+  [["English",+    "",+    "",+    "C flat",+    "C",+    "C sharp",+    "D flat",+    "D",+    "D sharp",+    "E flat",+    "E",+    "F",+    "F sharp",+    "G flat",+    "G",+    "G sharp",+    "A flat",+    "A",+    "A sharp",+    "B flat",+    "B",+    "B sharp"],+  ["German",+    "",+    "",+    "Ces",+    "C",+    "Cis",+    "Des",+    "D",+    "Dis",+    "Es",+    "E",+    "F",+    "Fis",+    "Ges",+    "G",+    "Gis",+    "As",+    "A",+    "Ais",+    "B",+    "H",+    "His"],+    +  ["Dutch",+    "(Netherlands)",+    "(Written)",+    "Ces / C mol",+    "C",+    "Cis / C kruis",+    "Des / D mol",+    "D",+    "Dis / D kruis",+    "Es / E mol",+    "E",+    "F",+    "Fis / F kruis",+    "Ges / G mol",+    "G",+    "Gis / G kruis",+    "As / A mol",+    "A",+    "Ais / A kruis",+    "Bes / B mol",+    "B",+    "Bis / B kruis"],+    +  ["Japanese",+    "",+    "",+    "\22793\12495 (hen-ha)",+    "\12495 (ha)",+    "\23344\12495 (ei-ha)",+    "\22793\12491 (hen-ni)",+    "\12491 (ni)",+    "\23344\12491 (ei-ni)",+    "\22793\12507 (hen-ho)",+    "\12507 (ho)",+    "\12504 (he)",+    "\23344\12504 (ei-he)",+    "\22793\12488 (hen-to)",+    "\12488 (to)",+    "\23344\12488 (ei-to)",+    "\22793\12452 (hen-i)",+    "\12452 (i)",+    "\23344\12452 (ei-i)",+    "\22793\12525 (hen-ro)",+    "\12525 (ro)",+    ""],+    +  ["Italian",+    "",+    "",+    "Do bemolle",+    "Do",+    "Do diesis",+    "Re bemolle",+    "Re",+    "Re diesis",+    "Mi bemolle",+    "Mi",+    "Fa",+    "Fa diesis",+    "Sol bemolle",+    "Sol",+    "Sol diesis",+    "La bemolle",+    "La",+    "La diesis",+    "Si bemolle",+    "Si",+    "Si diesis"],+    +  ["French",+    "",+    "",+    "Do b\233mol",+    "Do (Ut)",+    "Do di\232se",+    "R\233 b\233mol",+    "R\233",+    "R\233 di\232se",+    "Mi b\233mol",+    "Mi",+    "Fa",+    "Fa di\232se",+    "Sol b\233mol",+    "Sol",+    "Sol di\232se",+    "La b\233mol",+    "La",+    "La di\232se",+    "Si b\233mol",+    "Si",+    "Si di\232se"],+    +  ["Spanish",+    "",+    "",+    "Do bemol",+    "Do",+    "Do sostenido",+    "Re bemol",+    "Re",+    "Re sostenido",+    "Mi bemol",+    "Mi",+    "Fa",+    "Fa sostenido",+    "Sol bemol",+    "Sol",+    "Sol sostenido",+    "La bemol",+    "La",+    "La sostenido",+    "Si bemol",+    "Si",+    "Si sostenido"],+    +  ["Portuguese",+    "",+    "",+    "D\243 bemol",+    "D\243",+    "D\243 sustenido",+    "R\233 bemol",+    "R\233",+    "R\233 sustenido",+    "Mi bemol",+    "Mi",+    "F\225",+    "F\225 sustenido",+    "Sol bemol",+    "Sol",+    "Sol sustenido",+    "L\225 bemol",+    "L\225",+    "L\225 sustenido",+    "Si bemol",+    "Si",+    "Si sustenido"],+    +  ["Russian",+    "",+    "",+    "\1044\1086-\1073\1077\1084\1086\1083\1100",+    "\1044\1086",+    "\1044\1086-\1076\1080\1077\1079",+    "\1056\1077-\1073\1077\1084\1086\1083\1100",+    "\1056\1077",+    "\1056\1077-\1076\1080\1077\1079",+    "\1052\1080-\1073\1077\1084\1086\1083\1100",+    "\1052\1080",+    "\1060\1072",+    "\1060\1072-\1076\1080\1077\1079",+    "\1057\1086\1083\1100-\1073\1077\1084\1086\1083\1100",+    "\1057\1086\1083\1100",+    "\1057\1086\1083\1100-\1076\1080\1077\1079",+    "\1051\1103-\1073\1077\1084\1086\1083\1100",+    "\1051\1103",+    "\1051\1103-\1076\1080\1077\1079",+    "\1057\1080-\1073\1077\1084\1086\1083\1100",+    "\1057\1080",+    ""],+    +  ["Romanian",+    "",+    "",+    "Do bemol",+    "Do",+    "Do diez",+    "Re bemol",+    "Re",+    "Re diez",+    "Mi bemol",+    "Mi",+    "Fa",+    "Fa diez",+    "Sol bemol",+    "Sol",+    "Sol diez",+    "La bemol",+    "La",+    "La diez",+    "Si bemol",+    "Si",+    "Si diez"],+    +  ["Belgian dutch",+    "",+    "",+    "Do mol",+    "Do",+    "Do kruis",+    "Re mol",+    "Re",+    "Re kruis",+    "Mi mol",+    "Mi",+    "Fa",+    "Fa kruis",+    "Sol mol",+    "Sol",+    "Sol kruis",+    "La mol",+    "La",+    "La kruis",+    "Si mol",+    "Si",+    "Si kruis"],+    +  ["Swedish",+    "",+    "",+    "Cess",+    "C",+    "Ciss",+    "Dess",+    "D",+    "Diss",+    "Ess",+    "E",+    "F",+    "Fiss",+    "Gess",+    "G",+    "Giss",+    "Ass",+    "A",+    "Aiss",+    "B",+    "H",+    "Hiss"],+    +  ["NewSwedish",+    "",+    "",+    "Cess",+    "C",+    "Ciss",+    "Dess",+    "D",+    "Diss",+    "Ess",+    "E",+    "F",+    "Fiss",+    "Gess",+    "G",+    "Giss",+    "Ass",+    "A",+    "Aiss",+    "Bess",+    "B",+    "Biss"]]++modeNames :: [[String]] -- [[language,major,minor]]+modeNames =+  [["English","major","minor"],+  ["German","Dur","Moll"],+  ["Dutch","groot","klein"],+  ["Japanese","\38263\35519 (ch\333ch\333)","\30701\35519 (tanch\333)"],+  ["Italian","maggiore","minore"],+  ["French","majeur","mineur"],+  ["Spanish","mayor","menor"],+  ["Portuguese","maior","menor"],+  ["Russian","\1084\1072\1078\1086\1088","\1084\1080\1085\1086\1088"],+  ["Romanian","major","minor"],+  ["Belgian dutch","groot","klein"],+  ["Swedish","dur","moll"],+  ["NewSwedish","dur","moll"],+  ["","dur","moll"]]++nameModeSeparator :: [(String, String)] -- [(language,separator)]+nameModeSeparator =+  [("English"," "),+  ("German","-"),+  ("Dutch"," "),+  ("Japanese"," "),+  ("Italian"," "),+  ("French"," "),+  ("Spanish"," "),+  ("Portuguese"," "),+  ("Russian"," "),+  ("Romanian"," "),+  ("Belgian dutch"," "),+  ("Swedish","-"),+  ("NewSwedish","-")]+
+ src/Music/Pitch/Common/Number.hs view
@@ -0,0 +1,142 @@++{-# LANGUAGE DeriveDataTypeable         #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE NoMonomorphismRestriction  #-}+{-# LANGUAGE StandaloneDeriving         #-}+{-# LANGUAGE TypeFamilies               #-}++module Music.Pitch.Common.Number where++import Control.Lens+import Music.Pitch.Common.Diatonic++{-++-- ** Number+Number,+HasNumber(..),+unison,+prime,+second,+third,+fourth,+fifth,+sixth,+seventh,+octave,+ninth,+tenth,+twelfth,+duodecim,+thirteenth,+fourteenth,+fifteenth,++-}+++-- |+-- The number portion of an interval (i.e. second, third, etc).+--+-- Note that the interval number is always one step larger than number of steps spanned by+-- the interval (i.e. a third spans two diatonic steps). Thus 'number' does not distribute+-- over addition:+--+-- > number (a + b) = number a + number b - 1+--+newtype Number = Number { getNumber :: Int }+  deriving (Eq, Ord, Num, Enum, Real, Integral)++instance Show Number where { show = show . getNumber }+instance HasNumber Number where number = id++-- | A synonym for @1@.+unison      :: Number+unison      = 1++-- | A synonym for @1@.+prime       :: Number+prime       = 1++-- | A synonym for @2@.+second      :: Number+second      = 2++-- | A synonym for @3@.+third       :: Number+third       = 3++-- | A synonym for @4@.+fourth      :: Number+fourth      = 4++-- | A synonym for @5@.+fifth       :: Number+fifth       = 5++-- | A synonym for @6@.+sixth       :: Number+sixth       = 6++-- | A synonym for @7@.+seventh     :: Number+seventh     = 7++-- | A synonym for @8@.+octave      :: Number+octave      = 8++-- | A synonym for @9@.+ninth       :: Number+ninth       = 9++-- | A synonym for @10@.+tenth       :: Number+tenth       = 10++-- | A synonym for @11@.+eleventh    :: Number+eleventh    = 11++-- | A synonym for @12@.+twelfth     :: Number+twelfth     = 12++-- | A synonym for @12@.+duodecim    :: Number+duodecim    = 12++-- | A synonym for @13@.+thirteenth  :: Number+thirteenth  = 13++-- | A synonym for @14@.+fourteenth  :: Number+fourteenth  = 14++-- | A synonym for @15@.+fifteenth   :: Number+fifteenth   = 15++class HasNumber a where+    -- |+    -- Returns the number portion of an interval.+    --+    -- The interval number is negative if and only if the interval is negative.+    --+    -- See also 'quality', 'octaves' and 'semitones'.+    --+    number :: a -> Number+++-- TODO rename numberDiatonicSteps+diatonicSteps :: Iso' Number DiatonicSteps+diatonicSteps = iso n2d d2n+  where+    n2d n | n > 0  = fromIntegral (n - 1)+    n2d n | n == 0 = error "diatonicSteps: Invalid number 0"+    n2d n | n < 0  = fromIntegral (n + 1)++    d2n n | n >= 0 = fromIntegral (n + 1)+    d2n n | n <  0 = fromIntegral (n - 1)+
src/Music/Pitch/Common/Pitch.hs view
@@ -1,6 +1,9 @@ -{-# LANGUAGE GeneralizedNewtypeDeriving, StandaloneDeriving, TypeFamilies, -    FlexibleInstances, DeriveDataTypeable #-}+{-# LANGUAGE DeriveDataTypeable         #-}+{-# LANGUAGE FlexibleInstances          #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE StandaloneDeriving         #-}+{-# LANGUAGE TypeFamilies               #-}  ------------------------------------------------------------------------------------ -- |@@ -19,48 +22,61 @@ module Music.Pitch.Common.Pitch (         -- * Accidentals         Accidental,-        natural, -        flat, -        sharp, -        doubleFlat, +        natural,+        flat,+        sharp,+        doubleFlat,         doubleSharp,          -- ** Inspecting accidentals         isNatural,         isFlattened,         isSharpened,-        isStandard,+        isStandardAccidental,          -- ** Name         Name(..),          -- * Pitch         Pitch,-        Pitch(..),-                 mkPitch,         name,         accidental,++        -- ** Diatonic and chromatic pitch+        upDiatonicP,+        downDiatonicP,+        upChromaticP,+        downChromaticP,+        invertDiatonicallyP,+        invertChromaticallyP,+        +        -- ** Utility         asPitch   ) where -import Data.Maybe-import Data.Either-import Data.Semigroup-import Data.VectorSpace-import Data.AffineSpace-import Data.Typeable-import Control.Monad-import Control.Applicative-import qualified Data.Char as Char-import qualified Data.List as List+import           Control.Applicative+import           Control.Monad+import           Control.Lens hiding (simple)+import           Data.AffineSpace+import           Data.AffineSpace.Point+import qualified Data.Char                    as Char+import           Data.Either+import qualified Data.List                    as List+import           Data.Maybe+import           Data.Semigroup+import           Data.Typeable+import           Data.VectorSpace -import Music.Pitch.Absolute-import Music.Pitch.Literal-import Music.Pitch.Alterable-import Music.Pitch.Augmentable-import Music.Pitch.Common.Interval-import Music.Pitch.Common.Semitones+import           Music.Pitch.Absolute+import           Music.Pitch.Alterable+import           Music.Pitch.Augmentable+import           Music.Pitch.Common.Number+import           Music.Pitch.Common.Interval+import           Music.Pitch.Common.Semitones+import           Music.Pitch.Common.Chromatic+import           Music.Pitch.Common.Diatonic+import           Music.Pitch.Literal  -- | -- An accidental is either flat, natural or sharp.@@ -68,31 +84,31 @@ -- This representation allows for an arbitrary number of flats or sharps rather than just -- single and double. ----- The 'Num' and 'Enum' instances treat 'Accidental' as the number of altered semitones, +-- The 'Num' and 'Enum' instances treat 'Accidental' as the number of altered semitones, -- i.e. a double flat is @-2@, natural @0@ and so on. -- newtype Accidental = Accidental { getAccidental :: Integer }-    deriving (Eq, Ord, Num, Enum, Real, Integral)-    +  deriving (Eq, Ord, Num, Enum, Real, Integral)+ instance Show Accidental where-    show n | n == 0    = "natural"-           | n == 1    = "sharp"-           | n == (-1) = "flat"-           | n == 2    = "doubleSharp"-           | n == (-2) = "doubleFlat"-           | n > 0     = "sharp * " ++ show (getAccidental n)-           | n < 0     = "flat * " ++ show (negate $ getAccidental n)+  show n | n == 0    = "natural"+         | n == 1    = "sharp"+         | n == (-1) = "flat"+         | n == 2    = "doubleSharp"+         | n == (-2) = "doubleFlat"+         | n > 0     = "sharp * " ++ show (getAccidental n)+         | n < 0     = "flat * " ++ show (negate $ getAccidental n)  instance Alterable Accidental where-    sharpen = succ-    flatten = pred+  sharpen = succ+  flatten = pred --- | +-- | -- Magic instance that allow us to write @c sharp@ instead of @sharpen c@. -- instance (IsPitch a, Alterable a) => IsPitch (Accidental -> a) where-    fromPitch l 1       = sharpen (fromPitch l)-    fromPitch l (-1)    = flatten (fromPitch l)+  fromPitch l 1     = sharpen (fromPitch l)+  fromPitch l (-1)  = flatten (fromPitch l) -- Requires FlexibleInstances  sharp, flat, natural, doubleFlat, doubleSharp :: Accidental@@ -114,27 +130,27 @@  isNatural, isSharpened, isFlattened :: Accidental -> Bool --- | Returns whether this is a natural accidental.+-- | Returns whether this is a natural accidental. isNatural   = (== 0) --- | Returns whether this is a sharp, double sharp etc.+-- | Returns whether this is a sharp, double sharp etc. isSharpened = (> 0) --- | Returns whether this is a flat, double flat etc.+-- | Returns whether this is a flat, double flat etc. isFlattened = (< 0)  --- | Returns whether this is a standard accidental, i.e.+-- | Returns whether this is a standard accidental, i.e. --   either a double flat, flat, natural, sharp or double sharp.-isStandard :: Accidental -> Bool-isStandard a = abs a < 2-+isStandardAccidental :: Accidental -> Bool+isStandardAccidental a = abs a < 2+-- was: isStandard  -- | -- A pitch name. -- data Name = C | D | E | F | G | A | B-    deriving (Eq, Ord, Show, Enum)+  deriving (Eq, Ord, Show, Enum)  -- | -- Common pitch representation.@@ -188,51 +204,52 @@ -- > d5  == diminished fifth == diminish (perfect fifth) -- newtype Pitch = Pitch { getPitch :: Interval }-    deriving (Eq, Ord, Typeable)-    -instance Num Pitch where-    Pitch a + Pitch b = Pitch (a + b)-    negate (Pitch a)  = Pitch (negate a)-    abs (Pitch a)     = Pitch (abs a)-    (*)           = error  "Music.Pitch.Common.Pitch: no overloading for (*)"-    signum        = error "Music.Pitch.Common.Pitch: no overloading for signum"-    fromInteger   = error "Music.Pitch.Common.Pitch: no overloading for fromInteger"+  deriving (Eq, Ord, Typeable) -instance AffineSpace Pitch where-    type Diff Pitch     = Interval-    Pitch a .-. Pitch b = a ^-^ b-    Pitch a .+^ b       = Pitch (a ^+^ b)+instance IsPitch Pitch where+  fromPitch (PitchL (c, a, o)) =+    Pitch $ (\a b -> (fromIntegral a, fromIntegral b)^.interval') (qual a) c ^+^ (_P8^* fromIntegral o)+    where+      qual Nothing  = 0+      qual (Just n) = round n -instance Show Pitch where-    show p = showName (name p) ++ showAccidental (accidental p) ++ showOctave (octaves $ getPitch p)-        where        -            showName = fmap Char.toLower . show-            showOctave n-                | n > 0     = replicate' n '\''-                | otherwise = replicate' (negate n) '_'-            showAccidental n-                | n > 0     = replicate' n 's'-                | otherwise = replicate' (negate n) 'b'+instance Enum Pitch where+  toEnum = Pitch . (\a b -> (fromIntegral a, fromIntegral b)^.interval') 0 . fromIntegral+  fromEnum = fromIntegral . pred . number . (.-. c)  instance Alterable Pitch where-    sharpen (Pitch a) = Pitch (augment a)-    flatten (Pitch a) = Pitch (diminish a)+  sharpen (Pitch a) = Pitch (augment a)+  flatten (Pitch a) = Pitch (diminish a) -instance Enum Pitch where-    toEnum = Pitch . mkInterval' 0 . fromIntegral-    fromEnum = fromIntegral . pred . number . (.-. c)+instance Show Pitch where+  show p = showName (name p) ++ showAccidental (accidental p) ++ showOctave (octaves $ getPitch p)+    where+      showName = fmap Char.toLower . show+      showOctave n+        | n > 0     = replicate (fromIntegral n) '\''+        | otherwise = replicate (negate $ fromIntegral n) '_'+      showAccidental n+        | n > 0     = replicate (fromIntegral n) 's'+        | otherwise = replicate (negate $ fromIntegral n) 'b' --- |--- This is just the identity function, but is useful to fix the type of 'Pitch'.----asPitch :: Pitch -> Pitch-asPitch = id+instance Num Pitch where+  Pitch a + Pitch b = Pitch (a + b)+  negate (Pitch a)  = Pitch (negate a)+  abs (Pitch a)     = Pitch (abs a)+  (*)           = error  "Music.Pitch.Common.Pitch: no overloading for (*)"+  signum        = error "Music.Pitch.Common.Pitch: no overloading for signum"+  fromInteger   = error "Music.Pitch.Common.Pitch: no overloading for fromInteger" +instance AffineSpace Pitch where+  type Diff Pitch     = Interval+  Pitch a .-. Pitch b = a ^-^ b+  Pitch a .+^ b       = Pitch (a ^+^ b)+ -- | -- Creates a pitch from name accidental. -- mkPitch :: Name -> Accidental -> Pitch-mkPitch name acc = Pitch $ mkInterval' (fromIntegral acc) (fromEnum name)+mkPitch name acc = Pitch $ (\a b -> (fromIntegral a, fromIntegral b)^.interval') (fromIntegral acc) (fromEnum name)  -- | -- Returns the name of a pitch.@@ -245,7 +262,7 @@ -- @ -- name :: Pitch -> Name-name x               +name x   | i == 7           = toEnum 0 -- Arises for flat C etc.   | 0 <= i && i <= 6 = toEnum i   | otherwise        = error $ "Pitch.name: Bad value " ++ show i@@ -259,22 +276,31 @@ -- accidental :: Pitch -> Accidental accidental = fromIntegral . intervalDiff . simple . getPitch+  where+    intervalDiff = view (from interval'._1) --- | The same as 'c', but fixed to 'Pitch'. This is useful if you want---   to treat 'Pitch' as an affine space around middle C, that is /C4/ in Scientific Pitch Notation.-middleC :: Pitch-middleC = c+-- |+-- This is just the identity function, but is useful to fix the type of 'Pitch'.+--+asPitch :: Pitch -> Pitch+asPitch = id -instance IsPitch Pitch where-    fromPitch (PitchL (c, a, o)) =-        Pitch $ mkInterval' (qual a) c-            ^+^-            (perfect octave^* fromIntegral o)-        where-            qual Nothing  = 0-            qual (Just n) = round n+upChromaticP :: Pitch -> ChromaticSteps -> Pitch -> Pitch+upChromaticP origin n = relative origin $ (_alteration +~ n) --- midiNumber :: Pitch -> Integer--- midiNumber = fromIntegral . semitones . getPitch+downChromaticP :: Pitch -> ChromaticSteps -> Pitch -> Pitch+downChromaticP origin n = relative origin $ (_alteration -~ n) -replicate' n = replicate (fromIntegral n)+upDiatonicP :: Pitch -> DiatonicSteps -> Pitch -> Pitch+upDiatonicP origin n = relative origin $ (_steps +~ n)++downDiatonicP :: Pitch -> DiatonicSteps -> Pitch -> Pitch+downDiatonicP origin n = relative origin $ (_steps -~ n)++invertDiatonicallyP :: Pitch -> Pitch -> Pitch+invertDiatonicallyP origin = relative origin $ (_steps %~ negate)++invertChromaticallyP :: Pitch -> Pitch -> Pitch+invertChromaticallyP origin = relative origin $ (_alteration %~ negate)++
+ src/Music/Pitch/Common/Quality.hs view
@@ -0,0 +1,153 @@++{-# LANGUAGE DeriveDataTypeable         #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE NoMonomorphismRestriction  #-}+{-# LANGUAGE StandaloneDeriving         #-}+{-# LANGUAGE TypeFamilies               #-}++module Music.Pitch.Common.Quality where+{-+-- * Quality+Quality(..),+HasQuality(..),+invertQuality,+isPerfect,+isMajor,+isMinor,+isAugmented,+isDiminished,++QualityType(..),+expectedQualityType,+qualityTypes,+qualityToDiff,++-}+import           Music.Pitch.Augmentable+import           Music.Pitch.Common.Number+import           Music.Pitch.Common.Chromatic++-- | Types of value that has an interval quality (mainly 'Interval' and 'Quality' itself).+class HasQuality a where+  quality :: a -> Quality++-- |+-- Returns whether the given quality is perfect.+--+isPerfect :: HasQuality a => a -> Bool+isPerfect a = case quality a of { Perfect -> True ; _ -> False }++-- |+-- Returns whether the given quality is major.+--+isMajor :: HasQuality a => a -> Bool+isMajor a = case quality a of { Major -> True ; _ -> False }++-- |+-- Returns whether the given quality is minor.+--+isMinor :: HasQuality a => a -> Bool+isMinor a = case quality a of { Minor -> True ; _ -> False }++-- |+-- Returns whether the given quality is /augmented/ (including double augmented etc).+--+isAugmented :: HasQuality a => a -> Bool+isAugmented a = case quality a of { Augmented _ -> True ; _ -> False }++-- |+-- Returns whether the given quality is /diminished/ (including double diminished etc).+--+isDiminished :: HasQuality a => a -> Bool+isDiminished a = case quality a of { Diminished _ -> True ; _ -> False }++-- |+-- Interval quality is either perfect, major, minor, augmented, and+-- diminished. This representation allows for an arbitrary number of+-- augmentations or diminutions, so /augmented/ is represented by @Augmented+-- 1@, /doubly augmented/ by @Augmented 2@ and so on.+--+-- The quality of a compound interval is the quality of the simple interval on+-- which it is based.+--+data Quality+  = Major+  | Minor+  | Perfect+  -- TODO we really want to use Positive here, but that requires a+  -- rewrite of extractQuality below+  | Augmented Integer+  | Diminished Integer+  deriving (Eq, Ord, Show)++instance HasQuality Quality where+  quality = id+++-- | Augmentable Quality instance+--+-- This Augmentable instance exists solely for use of the extractQuality+-- function, which ensures that there is never any ambiguity around+-- diminished/augmented intervals turning into major/minor/perfect+-- intervals.++instance Augmentable Quality where+  augment Major = Augmented 1+  augment Minor = Major+  augment Perfect = Augmented 1+  augment (Augmented n) = Augmented (n + 1)+  augment (Diminished n) = Diminished (n - 1)+  diminish Major = Minor+  diminish Minor = Diminished 1+  diminish Perfect = Diminished 1+  diminish (Augmented n) = Augmented (n - 1)+  diminish (Diminished n) = Diminished (n + 1)++-- |+-- Invert a quality.+--+-- Perfect is unaffected, major becomes minor and vice versa, augmented+-- becomes diminished and vice versa.+--+invertQuality :: Quality -> Quality+invertQuality = go+  where+    go Major            = Minor+    go Minor            = Major+    go Perfect          = Perfect+    go (Augmented n)    = Diminished n+    go (Diminished n)   = Augmented n+++data QualityType = PerfectType | MajorMinorType+  deriving (Eq, Ord, Read, Show)++expectedQualityType :: HasNumber a => a -> QualityType+expectedQualityType x = if ((abs (number x) - 1) `mod` 7) + 1 `elem` [1,4,5]+  then PerfectType else MajorMinorType++qualityTypes :: Quality -> [QualityType]+qualityTypes Perfect = [PerfectType]+qualityTypes Major   = [MajorMinorType]+qualityTypes Minor   = [MajorMinorType]+qualityTypes _       = [PerfectType, MajorMinorType]++-- FIXME problem that this treats major as neutral, while this only holds for positive intervals+qualityToDiff :: Bool -> QualityType -> Quality -> ChromaticSteps+qualityToDiff positive qt q = fromIntegral $ go positive qt q+  where+    go True MajorMinorType (Augmented n)  = 0 + n+    go True MajorMinorType Major          = 0+    go True MajorMinorType Minor          = (-1)+    go True MajorMinorType (Diminished n) = -(1 + n)++    go False MajorMinorType (Augmented n)  = -(1 + n)+    go False MajorMinorType Major          = -1+    go False MajorMinorType Minor          = 0+    go False MajorMinorType (Diminished n) = 0 + n+    +    go _ PerfectType (Augmented n)  = 0 + n+    go _ PerfectType Perfect        = 0+    go _ PerfectType (Diminished n) = 0 - n+    +    go _ qt q = error $ "qualityToDiff: Unknown interval expression (" ++ show qt ++ ", " ++ show q ++ ")"
src/Music/Pitch/Common/Semitones.hs view
@@ -1,5 +1,6 @@ -{-# LANGUAGE GeneralizedNewtypeDeriving, StandaloneDeriving #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE StandaloneDeriving         #-}  ------------------------------------------------------------------------------------ -- |@@ -35,7 +36,7 @@         isSemitone,         isTone,         isTritone,-        +         -- * Enharmonic equivalence         (=:=),         (/:=),@@ -48,8 +49,8 @@ -- > octaves a = semitones a `div` 12 -- > steps   a = semitones a `mod` 12 ---newtype Octaves = Octaves { getOctaves :: Integer }     -    deriving (Eq, Ord, Num, Enum, Real, Integral)+newtype Octaves = Octaves { getOctaves :: Integer }+  deriving (Eq, Ord, Num, Enum, Real, Integral)  instance Show       Octaves where { show = show . getOctaves } instance HasOctaves Octaves where { octaves = id }@@ -58,19 +59,19 @@ -- Class of intervals that has a number of 'Octaves'. -- class HasOctaves a where-    -- |-    -- Returns the number of octaves spanned by an interval.-    ---    -- The number of octaves is negative if and only if the interval is-    -- negative.-    ---    -- Examples:-    ---    -- > octaves (perfect unison)  =  0-    -- > octaves (d5 ^* 4)         =  2-    -- > octaves (-_P8)            =  -1-    ---    octaves :: a -> Octaves+  -- |+  -- Returns the number of octaves spanned by an interval.+  --+  -- The number of octaves is negative if and only if the interval is+  -- negative.+  --+  -- Examples:+  --+  -- > octaves (perfect unison)  =  0+  -- > octaves (d5 ^* 4)         =  2+  -- > octaves (-_P8)            =  -1+  --+  octaves :: a -> Octaves   @@ -81,9 +82,9 @@ -- > steps   a = semitones a `mod` 12 -- newtype Steps = Steps { getSteps :: Integer }-    deriving (Eq, Ord, Num, Enum, Real, Integral)+  deriving (Eq, Ord, Num, Enum, Real, Integral) -instance Show     Steps where { show = show . getSteps }+instance Show Steps where { show = show . getSteps } -- instance HasSteps Steps where { steps = id }  {-@@ -91,16 +92,16 @@ -- Class of intervals that has a number of 'Steps'. -- class HasSteps a where-    -- |-    -- The number of steps is always in the range /0 ≤ x < 12/.-    ---    -- Examples:-    ---    -- > octaves (perfect unison)  =  0-    -- > octaves (d5 ^* 4)         =  2-    -- > octaves (-m7)             =  -1-    ---    steps :: a -> Steps+  -- |+  -- The number of steps is always in the range /0 ≤ x < 12/.+  --+  -- Examples:+  --+  -- > octaves (perfect unison)  =  0+  -- > octaves (d5 ^* 4)         =  2+  -- > octaves (-m7)             =  -1+  --+  steps :: a -> Steps -}  @@ -122,7 +123,7 @@ -- d5 -- newtype Semitones = Semitones { getSemitones :: Integer }-    deriving (Eq, Ord, Num, Enum, Real, Integral)+  deriving (Eq, Ord, Num, Enum, Real, Integral)  instance Show         Semitones where { show = show . getSemitones } instance HasSemitones Semitones where { semitones = id }@@ -132,22 +133,22 @@ -- class HasSemitones a where -    -- |-    -- Returns the number of semitones spanned by an interval.-    ---    -- The number of semitones is negative if and only if the interval is-    -- negative.-    ---    -- >>> semitones (perfect unison)-    -- 0-    -- >>> semitones tritone-    -- 6-    -- >>> semitones d5-    -- 6-    -- >>> semitones (-_P8)-    -- -12-    ---    semitones :: a -> Semitones+  -- |+  -- Returns the number of semitones spanned by an interval.+  --+  -- The number of semitones is negative if and only if the interval is+  -- negative.+  --+  -- >>> semitones (perfect unison)+  -- 0+  -- >>> semitones tritone+  -- 6+  -- >>> semitones d5+  -- 6+  -- >>> semitones (-_P8)+  -- -12+  --+  semitones :: a -> Semitones   
src/Music/Pitch/Common/Spell.hs view
@@ -1,6 +1,8 @@- -{-# LANGUAGE GeneralizedNewtypeDeriving, StandaloneDeriving, TypeFamilies #-} +{-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE StandaloneDeriving         #-}+{-# LANGUAGE TypeFamilies               #-}+ ------------------------------------------------------------------------------------ -- | -- Copyright   : (c) Hans Hoglund, Edward Lilley 2012–2014@@ -24,47 +26,49 @@         Spelling,         spell,         spelled,-        +         -- ** Standard spellings         modally,         usingSharps,         usingFlats,   ) where -import Data.VectorSpace-import Data.AffineSpace+import           Data.AffineSpace+import           Data.VectorSpace+import           Control.Lens -import Music.Pitch.Absolute-import Music.Pitch.Literal-import Music.Pitch.Alterable-import Music.Pitch.Augmentable-import Music.Pitch.Common.Pitch-import Music.Pitch.Common.Interval-import Music.Pitch.Common.Semitones+import           Music.Pitch.Absolute+import           Music.Pitch.Alterable+import           Music.Pitch.Augmentable+import           Music.Pitch.Common.Interval+import           Music.Pitch.Common.Number+import           Music.Pitch.Common.Pitch+import           Music.Pitch.Common.Semitones+import           Music.Pitch.Literal  -- $semitonesAndSpellings -- -- TODO document better -- -- The `semitones` function retrieves the number of Semitones in a pitch, for example--- +-- -- > semitones :: Interval -> Semitones -- > semitones major third = 4--- +-- -- Note that semitones is surjetive. We can define a non-deterministic function `spellings`--- +-- -- > spellings :: Semitones -> [Interval] -- > spellings 4 = [majorThird, diminishedFourth] -- -- /Law/--- +-- -- > map semitones (spellings a) = replicate n a    for all n > 0 -- -- /Lemma/--- +-- -- > map semitones (spellings a) --- | +-- | -- A spelling provide a way of notating a semitone interval such as 'tritone'. -- -- Examples:@@ -81,27 +85,27 @@ -- spell :: HasSemitones a => Spelling -> a -> Interval spell spelling x = let-    -- TODO use Steps etc to remove fromIntegral-    (octaves, steps) = semitones x `divMod` 12-    num  = fromIntegral (spelling steps)-    diff = fromIntegral steps - fromIntegral (diatonicToChromatic num)-    in mkInterval' diff num ^+^ _P8^*(fromIntegral octaves)+  -- TODO use Steps etc to remove fromIntegral+  (octaves, steps) = semitones x `divMod` 12+  num  = fromIntegral (spelling steps)+  diff = fromIntegral steps - fromIntegral (diatonicToChromatic num)+  in (\a b -> (fromIntegral a, fromIntegral b)^.interval') diff num ^+^ _P8^*(fromIntegral octaves)     where-        diatonicToChromatic = go-            where-                go 0 = 0-                go 1 = 2-                go 2 = 4-                go 3 = 5-                go 4 = 7-                go 5 = 9-                go 6 = 11+      diatonicToChromatic = go+        where+          go 0 = 0+          go 1 = 2+          go 2 = 4+          go 3 = 5+          go 4 = 7+          go 5 = 9+          go 6 = 11  -- | -- Flipped version of 'spell'. To be used infix, as in: -- -- > d5 `spelled` usingSharps---        +-- spelled :: HasSemitones a => a -> Spelling -> Interval spelled = flip spell @@ -115,19 +119,19 @@ -- modally :: Spelling modally = go-    where-        go 0  = 0-        go 1  = 0-        go 2  = 1-        go 3  = 2-        go 4  = 2-        go 5  = 3-        go 6  = 3-        go 7  = 4-        go 8  = 4-        go 9  = 5-        go 10 = 6-        go 11 = 6+  where+    go 0  = 0+    go 1  = 0+    go 2  = 1+    go 3  = 2+    go 4  = 2+    go 5  = 3+    go 6  = 3+    go 7  = 4+    go 8  = 4+    go 9  = 5+    go 10 = 6+    go 11 = 6  -- | -- Spell using sharps. Double sharps and flats are not preserved.@@ -136,19 +140,19 @@ -- usingSharps :: Spelling usingSharps = go-    where-        go 0  = 0-        go 1  = 0-        go 2  = 1-        go 3  = 1-        go 4  = 2-        go 5  = 3-        go 6  = 3-        go 7  = 4-        go 8  = 4-        go 9  = 5-        go 10 = 5-        go 11 = 6+  where+    go 0  = 0+    go 1  = 0+    go 2  = 1+    go 3  = 1+    go 4  = 2+    go 5  = 3+    go 6  = 3+    go 7  = 4+    go 8  = 4+    go 9  = 5+    go 10 = 5+    go 11 = 6  -- | -- Spell using flats. Double sharps and flats are not preserved.@@ -157,17 +161,17 @@ -- usingFlats :: Spelling usingFlats = go-    where-        go 0  = 0-        go 1  = 1-        go 2  = 1-        go 3  = 2-        go 4  = 2-        go 5  = 3-        go 6  = 4-        go 7  = 4-        go 8  = 5-        go 9  = 5-        go 10 = 6-        go 11 = 6-                         +  where+    go 0  = 0+    go 1  = 1+    go 2  = 1+    go 3  = 2+    go 4  = 2+    go 5  = 3+    go 6  = 4+    go 7  = 4+    go 8  = 5+    go 9  = 5+    go 10 = 6+    go 11 = 6+
src/Music/Pitch/Equal.hs view
@@ -1,5 +1,8 @@ +{-# LANGUAGE StandaloneDeriving #-} {-# LANGUAGE RankNTypes #-}+{-# LANGUAGE TypeOperators #-}+{-# LANGUAGE TypeFamilies #-}  ------------------------------------------------------------------------------------- -- |@@ -11,99 +14,167 @@ -- Stability   : experimental -- Portability : portable ----- Equal temperament pitch of any size.+-- Generic equal temperament pitch. --+-- Use the type-level numbers from @type-unary@ to construct an temperement dividing+-- the octave in any number of steps. Common cases such as 6-TET (whole-tones),+-- 12-TET (half-tones) and 24-TET (quarter-tones) are provided for convenience.+-- -------------------------------------------------------------------------------------  module Music.Pitch.Equal (-    -- Equal,-    -- toEqual,-    -- Equal6,-    -- Equal12,-    -- Equal17,-    -- Equal24,-    -- Equal36,-    -- -- toEqual',-    -- unsafeToEqual,-    -- value,-    -- size,-    -- cast,+    -- * Equal temperament+    Equal,+    toEqual,+    fromEqual,+    equalToRatio,+    size,+    cast,++    -- ** Synonyms+    Equal6,+    Equal12,+    Equal17,+    Equal24,+    Equal36,++    -- ** Extra type-level naturals+    N20,+    N30,+    N17,+    N24,+    N36, ) where --- {---- --- TODO mixing things up here--- ---   This type implements limited values (useful for interval *steps*)---   An ET-interval is just an int, with a type-level size (divMod is "separate")--- --- --- -}--- --- --- import Data.Maybe--- import Data.Either--- import Data.Semigroup--- import Control.Monad--- import Control.Applicative--- import Music.Pitch.Absolute--- --- import Data.TypeLevel.Num hiding ((<), (>), (+), (<=), (*))--- import qualified Data.TypeLevel.Num as TL--- --- data Foo = Foo Int deriving Show--- --- newtype Equal a = Equal { getEqual :: Pos a => Int }---   deriving ()--- --- instance Pos a => Show (Equal a) where---   -- show (Equal x) = "(Equal " ++ (show x) ++ ")"---   showsPrec d (Equal x) = showParen (d > app_prec) $---        showString "Equal " . showsPrec (app_prec+1) x---     where app_prec = 10--- --- -- Convenience to avoid ScopedTypeVariables etc    --- getSize :: Pos a => Equal a -> a--- getSize = undefined--- --- -- | Value, which is in @[0,size x)@.--- value :: Pos a => Equal a -> Int--- value = getEqual--- --- -- | Size of this type (value not evaluated).--- size :: Pos a => Equal a -> Int--- size = toInt . getSize--- --- toEqual :: Pos a => Int -> Maybe (Equal a)--- toEqual = toEqual' undefined--- --- toEqual' :: Pos a => a -> Int -> Maybe (Equal a)--- toEqual' s n = if 0 <= n && n < toInt s then Just (Equal n) else Nothing--- --- unsafeToEqual :: Int -> Equal a--- unsafeToEqual n = Equal n+import Data.Maybe+import Data.Either+import Data.Semigroup+import Data.VectorSpace+import Data.AffineSpace+import Control.Monad+import Control.Applicative++import Music.Pitch.Absolute++import TypeUnary.Nat++-- Based on Data.Fixed++newtype Equal a = Equal { getEqual :: Int }++deriving instance {-IsNat a =>-} Eq (Equal a)+deriving instance {-IsNat a =>-} Ord (Equal a)++instance {-IsNat a =>-} Show (Equal a) where+  show (Equal a) = show a+  -- showsPrec d (Equal x) = showParen (d > app_prec) $+  --      showString "Equal " . showsPrec (app_prec+1) x+  --   where app_prec = 10++instance IsNat a => Num (Equal a) where+  Equal a + Equal b = Equal (a + b)+  Equal a * Equal b = Equal (a * b)+  negate (Equal a)  = Equal (negate a)+  abs (Equal a)     = Equal (abs a)+  signum (Equal a)  = Equal (signum a)+  fromInteger       = toEqual . fromIntegral++instance IsNat a => Semigroup (Equal a) where+  (<>)    = (+)++instance IsNat a => Monoid (Equal a) where+  mempty  = 0+  mappend = (+)++instance IsNat a => AdditiveGroup (Equal a) where+  zeroV   = 0+  (^+^)   = (+)+  negateV = negate++instance IsNat a => VectorSpace (Equal a) where+  type Scalar (Equal a) = Equal a+  (*^) = (*)++-- Convenience to avoid ScopedTypeVariables etc    +getSize :: IsNat a => Equal a -> Nat a+getSize _ = nat ++-- | Size of this type (value not evaluated). -- --- type Equal6  = Equal D6--- type Equal12 = Equal D12--- type Equal17 = Equal D17--- type Equal24 = Equal D24--- type Equal36 = Equal D36+-- >>> size (undefined :: Equal N2)+-- 2 -- --- -- unsafemapValue :: (Int -> Int) -> Equal a -> Equal b--- -- mapValue+-- >>> size (undefined :: Equal N12)+-- 12 -- --- -- b = 24, a = 12, mul = 24/12--- -- | Safely cast a tempered value to a larger size.--- ----- -- >>> cast (unsafeToEqual 1 :: Equal12) :: Equal24--- -- Equal 2 :: Equal24--- ----- cast :: (Pos a, Pos b, Pos c, Div b a c) => Equal a -> Equal b--- cast = cast' undefined+size :: IsNat a => Equal a -> Int+size = natToZ . getSize++-- TODO I got this part wrong -- --- cast' :: (Pos a, Pos b, Pos c, Div b a c) => Equal c -> Equal a -> Equal b--- cast' cDummy (Equal a) = Equal (a * size cDummy)+-- This type implements limited values (useful for interval *steps*)+-- An ET-interval is just an int, with a type-level size (divMod is "separate")++-- -- | Create an equal-temperament value.+-- toEqual :: IsNat a => Int -> Maybe (Equal a)+-- toEqual = checkSize . Equal -- +-- -- | Unsafely create an equal-temperament value.+-- unsafeToEqual :: IsNat a => Int -> Equal a+-- unsafeToEqual n = case toEqual n of+--   Nothing -> error $ "Bad equal: " ++ show n+--   Just x  -> x -- +-- checkSize :: IsNat a => Equal a -> Maybe (Equal a)+-- checkSize x = if 0 <= fromEqual x && fromEqual x < size x then Just x else Nothing -- ++-- | Create an equal-temperament value.+toEqual :: IsNat a => Int -> Equal a+toEqual = Equal++-- | Extract an equal-temperament value.+fromEqual :: IsNat a => Equal a -> Int+fromEqual = getEqual++-- | Convert an equal-temeperament value to a frequency ratio.+--+-- >>> equalToRatio (7 :: Equal12)+-- 1.4983070768766815+--+-- >>> equalToRatio (4 :: Equal12)+-- 1.2599210498948732+--+equalToRatio :: IsNat a => Equal a -> Double+equalToRatio x = 2**(realToFrac (fromEqual x) / realToFrac (size x))++-- | Safely cast a tempered value to another size.+--+-- >>> cast (1 :: Equal12) :: Equal24+-- 2 :: Equal24+--+-- >>> cast (8 :: Equal12) :: Equal6+-- 4 :: Equal6+--+-- >>> (2 :: Equal12) + cast (2 :: Equal24)+-- 3 :: Equal12+--+cast :: (IsNat a, IsNat b) => Equal a -> Equal b+cast = cast' undefined++cast' :: (IsNat a, IsNat b) => Equal b -> Equal a -> Equal b+cast' bDummy aDummy@(Equal a) = Equal $ (a * size bDummy) `div` size aDummy++type Equal6  = Equal N6+type Equal12 = Equal N12+type Equal17 = Equal N17+type Equal24 = Equal N24+type Equal36 = Equal N36++type N20 = N10 :*: N2+type N30 = N10 :*: N3+type N17 = N10 :+: N7+type N24 = N20 :+: N4+type N36 = N30 :+: N6+
src/Music/Pitch/Intonation.hs view
@@ -1,4 +1,6 @@ +{-# LANGUAGE ViewPatterns #-}+ ------------------------------------------------------------------------------------- -- | -- Copyright   : (c) Hans Hoglund 2012@@ -9,7 +11,7 @@ -- Stability   : experimental -- Portability : portable ----- Provides intonation.+-- Provides intonation, i.e. mappings from relative to absolute pitch. -- ------------------------------------------------------------------------------------- @@ -47,9 +49,10 @@ import Data.AffineSpace import Control.Monad import Control.Applicative+import Control.Lens  import Music.Pitch.Absolute-import Music.Pitch.Literal+import Music.Pitch.Literal as Intervals import Music.Pitch.Common.Interval import Music.Pitch.Common.Pitch @@ -57,10 +60,10 @@ type Tuning i = i -> {-FreqRatio-}Hertz  synTune :: (Interval, {-FreqRatio-}Hertz) -> (Interval, {-FreqRatio-}Hertz) -> Interval -> {-FreqRatio-}Hertz-synTune (i1, i1rat) (i2, i2rat) (Interval (a1, d2)) =+synTune (i1, i1rat) (i2, i2rat) (view (from interval') -> (a1, d2)) =   ((makeA1 (i1, i1rat) (i2, i2rat)) ^* (fromIntegral a1)) ^+^ ((maked2 (i1, i1rat) (i2, i2rat)) ^* (fromIntegral d2))-  where makeA1 = makeBasis basis_A1-        maked2 = makeBasis basis_d2+  where makeA1 = makeBasis (Intervals._A1 :: Interval)+        maked2 = makeBasis (Intervals.d2  :: Interval)  makeBasis :: Interval -> (Interval, {-FreqRatio-}Hertz) -> (Interval, {-FreqRatio-}Hertz) -> {-FreqRatio-}Hertz makeBasis i (i1, r1) (i2, r2) = case (convertBasisFloat i i1 i2) of
src/Music/Pitch/StaffLines.hs view
@@ -12,6 +12,20 @@ {-# LANGUAGE ScopedTypeVariables        #-} {-# LANGUAGE TypeFamilies               #-} +------------------------------------------------------------------------------------+-- |+-- Copyright   : (c) Hans Hoglund, Edward Lilley 2012–2014+--+-- License     : BSD-style+--+-- Maintainer  : hans@hanshoglund.se+-- Stability   : experimental+-- Portability : non-portable (TF,GNTD)+--+-- Lines and staff positions.+--+-------------------------------------------------------------------------------------+ module Music.Pitch.StaffLines (         StaffLines,         HalfSpaces,