packages feed

music-pitch 1.8.1 → 1.9.0

raw patch · 21 files changed

+1031/−1105 lines, 21 filesdep +aesondep ~lensdep ~music-pitch-literaldep ~positivePVP ok

version bump matches the API change (PVP)

Dependencies added: aeson

Dependency ranges changed: lens, music-pitch-literal, positive, vector-space, vector-space-points

API changes (from Hackage documentation)

- Music.Pitch: data HalfSpaces
- Music.Pitch: data StaffLines
- Music.Pitch.Absolute: instance AdditiveGroup Hertz
- Music.Pitch.Absolute: instance IsInterval Hertz
- Music.Pitch.Absolute: instance VectorSpace Hertz
- Music.Pitch.Ambitus: ambitus' :: (Num a, Ord a) => Iso' (a, a) (Ambitus a)
- Music.Pitch.Clef: type Clef = (ClefSymbol, ClefOctave, ClefLine)
- Music.Pitch.Common.Chromatic: data ChromaticSteps
- 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.Diatonic: data DiatonicSteps
- 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.Interval: asInterval :: Interval -> Interval
- Music.Pitch.Common.Interval: instance Enum IntervalBasis
- Music.Pitch.Common.Interval: instance Eq Interval
- Music.Pitch.Common.Interval: instance Eq IntervalBasis
- Music.Pitch.Common.Interval: instance Ord Interval
- Music.Pitch.Common.Interval: instance Ord IntervalBasis
- Music.Pitch.Common.Interval: instance Show IntervalBasis
- Music.Pitch.Common.Interval: instance Typeable Interval
- Music.Pitch.Common.Number: Number :: Int -> Number
- Music.Pitch.Common.Number: duodecim :: 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 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.Pitch: asPitch :: Pitch -> Pitch
- Music.Pitch.Common.Pitch: instance (IsPitch a, Alterable a) => IsPitch (Accidental -> a)
- Music.Pitch.Common.Pitch: instance Alterable Accidental
- Music.Pitch.Common.Pitch: instance Enum Accidental
- Music.Pitch.Common.Pitch: instance Enum Name
- Music.Pitch.Common.Pitch: instance Eq Accidental
- Music.Pitch.Common.Pitch: instance Eq Name
- Music.Pitch.Common.Pitch: instance Eq Pitch
- Music.Pitch.Common.Pitch: instance Integral Accidental
- Music.Pitch.Common.Pitch: instance Num Accidental
- Music.Pitch.Common.Pitch: instance Ord Accidental
- Music.Pitch.Common.Pitch: instance Ord Name
- Music.Pitch.Common.Pitch: instance Ord Pitch
- Music.Pitch.Common.Pitch: instance Real Accidental
- Music.Pitch.Common.Pitch: instance Show Accidental
- Music.Pitch.Common.Pitch: instance Show Name
- Music.Pitch.Common.Pitch: instance Typeable Pitch
- Music.Pitch.Common.Quality: instance Eq Quality
- Music.Pitch.Common.Quality: instance Eq QualityType
- 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.Semitones: data Semitones
- Music.Pitch.Common.Semitones: data Steps
- Music.Pitch.Common.Semitones: instance Enum Octaves
- Music.Pitch.Common.Semitones: instance Enum Semitones
- Music.Pitch.Common.Semitones: instance Enum Steps
- Music.Pitch.Common.Semitones: instance Eq Octaves
- Music.Pitch.Common.Semitones: instance Eq Semitones
- Music.Pitch.Common.Semitones: instance Eq Steps
- Music.Pitch.Common.Semitones: instance HasSemitones Semitones
- Music.Pitch.Common.Semitones: instance Integral Octaves
- Music.Pitch.Common.Semitones: instance Integral Semitones
- Music.Pitch.Common.Semitones: instance Integral Steps
- Music.Pitch.Common.Semitones: instance Num Octaves
- Music.Pitch.Common.Semitones: instance Num Semitones
- Music.Pitch.Common.Semitones: instance Num Steps
- Music.Pitch.Common.Semitones: instance Ord Octaves
- Music.Pitch.Common.Semitones: instance Ord Semitones
- Music.Pitch.Common.Semitones: instance Ord Steps
- Music.Pitch.Common.Semitones: instance Real Octaves
- Music.Pitch.Common.Semitones: instance Real Semitones
- Music.Pitch.Common.Semitones: instance Real Steps
- Music.Pitch.Common.Semitones: instance Show Octaves
- Music.Pitch.Common.Semitones: instance Show Semitones
- Music.Pitch.Common.Semitones: instance Show Steps
- Music.Pitch.Intonation: tetTune :: Interval -> Interval -> Hertz
- Music.Pitch.Intonation: type Intonation p = p -> Hertz
- Music.Pitch.Intonation: type Tuning i = i -> Hertz
- Music.Pitch.Scale: _intervals :: Lens' (Function a) [Diff a]
- Music.Pitch.Scale: _repeat :: Lens' (Function a) (Diff a)
- Music.Pitch.Scale: _tonic :: Lens' (Chord a) a
- Music.Pitch.Scale: bluesScale :: Mode Pitch
- Music.Pitch.Scale: majorSeventhChord :: Function Pitch
- Music.Pitch.Scale: melodicMinorScale :: Mode Pitch
+ Music.Pitch.Clef: CClef :: ClefSymbol
+ Music.Pitch.Clef: Clef :: (ClefSymbol, ClefOctave, ClefLine) -> Clef
+ Music.Pitch.Clef: FClef :: ClefSymbol
+ Music.Pitch.Clef: GClef :: ClefSymbol
+ Music.Pitch.Clef: NeutralClef :: ClefSymbol
+ Music.Pitch.Clef: PercClef :: ClefSymbol
+ Music.Pitch.Clef: data HalfSpaces
+ Music.Pitch.Clef: data StaffLines
+ Music.Pitch.Clef: getClef :: Clef -> (ClefSymbol, ClefOctave, ClefLine)
+ Music.Pitch.Clef: instance Enum HalfSpaces
+ Music.Pitch.Clef: instance Enum StaffLines
+ Music.Pitch.Clef: instance Eq Clef
+ Music.Pitch.Clef: instance Eq HalfSpaces
+ Music.Pitch.Clef: instance Eq StaffLines
+ Music.Pitch.Clef: instance Integral HalfSpaces
+ Music.Pitch.Clef: instance Integral StaffLines
+ Music.Pitch.Clef: instance Num HalfSpaces
+ Music.Pitch.Clef: instance Num StaffLines
+ Music.Pitch.Clef: instance Ord Clef
+ Music.Pitch.Clef: instance Ord HalfSpaces
+ Music.Pitch.Clef: instance Ord StaffLines
+ Music.Pitch.Clef: instance Read HalfSpaces
+ Music.Pitch.Clef: instance Read StaffLines
+ Music.Pitch.Clef: instance Real HalfSpaces
+ Music.Pitch.Clef: instance Real StaffLines
+ Music.Pitch.Clef: instance Show Clef
+ Music.Pitch.Clef: instance Show HalfSpaces
+ Music.Pitch.Clef: instance Show StaffLines
+ Music.Pitch.Clef: instance Typeable Clef
+ Music.Pitch.Clef: instance Typeable HalfSpaces
+ Music.Pitch.Clef: instance Typeable StaffLines
+ Music.Pitch.Clef: newtype Clef
+ Music.Pitch.Clef: type ClefLine = StaffLines
+ Music.Pitch.Common.Interval: instance ToJSON ChromaticSteps
+ Music.Pitch.Common.Interval: instance ToJSON DiatonicSteps
+ Music.Pitch.Common.Interval: instance ToJSON Interval
+ Music.Pitch.Common.Interval: interval'' :: Iso' (ChromaticSteps, DiatonicSteps) Interval
+ Music.Pitch.Common.Number: data Number
+ Music.Pitch.Common.Pitch: instance ToJSON Pitch
+ Music.Pitch.Common.Quality: Downward :: Direction
+ Music.Pitch.Common.Quality: Upward :: Direction
+ Music.Pitch.Common.Quality: data Direction
+ Music.Pitch.Common.Quality: instance Eq Direction
+ Music.Pitch.Common.Quality: instance Ord Direction
+ Music.Pitch.Common.Quality: instance Show Direction
+ Music.Pitch.Common.Quality: qualityToAlteration :: Direction -> QualityType -> Quality -> Maybe ChromaticSteps
+ Music.Pitch.Common.Semitones: instance HasSemitones ChromaticSteps
+ Music.Pitch.Common.Semitones: type Semitones = ChromaticSteps
+ Music.Pitch.Common.Types: A :: Name
+ Music.Pitch.Common.Types: Augmented :: Integer -> Quality
+ Music.Pitch.Common.Types: B :: Name
+ Music.Pitch.Common.Types: C :: Name
+ Music.Pitch.Common.Types: Chromatic :: IntervalBasis
+ Music.Pitch.Common.Types: D :: Name
+ Music.Pitch.Common.Types: Diatonic :: IntervalBasis
+ Music.Pitch.Common.Types: Diminished :: Integer -> Quality
+ Music.Pitch.Common.Types: E :: Name
+ Music.Pitch.Common.Types: F :: Name
+ Music.Pitch.Common.Types: G :: Name
+ Music.Pitch.Common.Types: Interval :: (ChromaticSteps, DiatonicSteps) -> Interval
+ Music.Pitch.Common.Types: Major :: Quality
+ Music.Pitch.Common.Types: MajorMinorType :: QualityType
+ Music.Pitch.Common.Types: Minor :: Quality
+ Music.Pitch.Common.Types: Perfect :: Quality
+ Music.Pitch.Common.Types: PerfectType :: QualityType
+ Music.Pitch.Common.Types: Pitch :: Interval -> Pitch
+ Music.Pitch.Common.Types: data Accidental
+ Music.Pitch.Common.Types: data ChromaticSteps
+ Music.Pitch.Common.Types: data DiatonicSteps
+ Music.Pitch.Common.Types: data IntervalBasis
+ Music.Pitch.Common.Types: data Name
+ Music.Pitch.Common.Types: data Number
+ Music.Pitch.Common.Types: data Octaves
+ Music.Pitch.Common.Types: data Quality
+ Music.Pitch.Common.Types: data QualityType
+ Music.Pitch.Common.Types: getInterval :: Interval -> (ChromaticSteps, DiatonicSteps)
+ Music.Pitch.Common.Types: getPitch :: Pitch -> Interval
+ Music.Pitch.Common.Types: instance (IsPitch a, Alterable a) => IsPitch (Accidental -> a)
+ Music.Pitch.Common.Types: instance AdditiveGroup ChromaticSteps
+ Music.Pitch.Common.Types: instance AdditiveGroup DiatonicSteps
+ Music.Pitch.Common.Types: instance Alterable Accidental
+ Music.Pitch.Common.Types: instance Enum Accidental
+ Music.Pitch.Common.Types: instance Enum ChromaticSteps
+ Music.Pitch.Common.Types: instance Enum DiatonicSteps
+ Music.Pitch.Common.Types: instance Enum IntervalBasis
+ Music.Pitch.Common.Types: instance Enum Name
+ Music.Pitch.Common.Types: instance Enum Number
+ Music.Pitch.Common.Types: instance Enum Octaves
+ Music.Pitch.Common.Types: instance Eq Accidental
+ Music.Pitch.Common.Types: instance Eq ChromaticSteps
+ Music.Pitch.Common.Types: instance Eq DiatonicSteps
+ Music.Pitch.Common.Types: instance Eq Interval
+ Music.Pitch.Common.Types: instance Eq IntervalBasis
+ Music.Pitch.Common.Types: instance Eq Name
+ Music.Pitch.Common.Types: instance Eq Number
+ Music.Pitch.Common.Types: instance Eq Octaves
+ Music.Pitch.Common.Types: instance Eq Pitch
+ Music.Pitch.Common.Types: instance Eq Quality
+ Music.Pitch.Common.Types: instance Eq QualityType
+ Music.Pitch.Common.Types: instance Integral Accidental
+ Music.Pitch.Common.Types: instance Integral ChromaticSteps
+ Music.Pitch.Common.Types: instance Integral DiatonicSteps
+ Music.Pitch.Common.Types: instance Integral Number
+ Music.Pitch.Common.Types: instance Integral Octaves
+ Music.Pitch.Common.Types: instance Num Accidental
+ Music.Pitch.Common.Types: instance Num ChromaticSteps
+ Music.Pitch.Common.Types: instance Num DiatonicSteps
+ Music.Pitch.Common.Types: instance Num Number
+ Music.Pitch.Common.Types: instance Num Octaves
+ Music.Pitch.Common.Types: instance Ord Accidental
+ Music.Pitch.Common.Types: instance Ord ChromaticSteps
+ Music.Pitch.Common.Types: instance Ord DiatonicSteps
+ Music.Pitch.Common.Types: instance Ord Interval
+ Music.Pitch.Common.Types: instance Ord IntervalBasis
+ Music.Pitch.Common.Types: instance Ord Name
+ Music.Pitch.Common.Types: instance Ord Number
+ Music.Pitch.Common.Types: instance Ord Octaves
+ Music.Pitch.Common.Types: instance Ord Pitch
+ Music.Pitch.Common.Types: instance Ord Quality
+ Music.Pitch.Common.Types: instance Ord QualityType
+ Music.Pitch.Common.Types: instance Read QualityType
+ Music.Pitch.Common.Types: instance Real Accidental
+ Music.Pitch.Common.Types: instance Real ChromaticSteps
+ Music.Pitch.Common.Types: instance Real DiatonicSteps
+ Music.Pitch.Common.Types: instance Real Number
+ Music.Pitch.Common.Types: instance Real Octaves
+ Music.Pitch.Common.Types: instance Show Accidental
+ Music.Pitch.Common.Types: instance Show ChromaticSteps
+ Music.Pitch.Common.Types: instance Show DiatonicSteps
+ Music.Pitch.Common.Types: instance Show IntervalBasis
+ Music.Pitch.Common.Types: instance Show Name
+ Music.Pitch.Common.Types: instance Show Number
+ Music.Pitch.Common.Types: instance Show Octaves
+ Music.Pitch.Common.Types: instance Show Quality
+ Music.Pitch.Common.Types: instance Show QualityType
+ Music.Pitch.Common.Types: instance Typeable Interval
+ Music.Pitch.Common.Types: instance Typeable Pitch
+ Music.Pitch.Common.Types: newtype Interval
+ Music.Pitch.Common.Types: newtype Pitch
+ Music.Pitch.Common.Types: type Semitones = ChromaticSteps
+ Music.Pitch.Intonation: Intonation :: (p -> Hertz) -> Intonation p
+ Music.Pitch.Intonation: Tuning :: (i -> Double) -> Tuning i
+ Music.Pitch.Intonation: getIntonation :: Intonation p -> p -> Hertz
+ Music.Pitch.Intonation: getTuning :: Tuning i -> i -> Double
+ Music.Pitch.Intonation: newtype Intonation p
+ Music.Pitch.Intonation: newtype Tuning i
+ Music.Pitch.Scale: bluesMajor :: Mode Pitch
+ Music.Pitch.Scale: bluesMinor :: Mode Pitch
+ Music.Pitch.Scale: chordFunction :: Lens' (Chord a) (Function a)
+ Music.Pitch.Scale: chordToList :: AffineSpace a => Chord a -> [a]
+ Music.Pitch.Scale: chordTonic :: Lens' (Chord a) a
+ Music.Pitch.Scale: complementInterval :: AffineSpace a => Function a -> Diff a
+ Music.Pitch.Scale: functionFromSteps :: [Diff a] -> Diff a -> Function a
+ Music.Pitch.Scale: functionIntervals :: Lens' (Function a) [Diff a]
+ Music.Pitch.Scale: functionRepeat :: Lens' (Function a) (Diff a)
+ Music.Pitch.Scale: functionToChord :: AffineSpace a => a -> Function a -> Chord a
+ Music.Pitch.Scale: invertChord :: AffineSpace a => Int -> Function a -> Function a
+ Music.Pitch.Scale: invertMode :: AffineSpace a => Int -> Mode a -> Mode a
+ Music.Pitch.Scale: leadingInterval :: AffineSpace a => Mode a -> Diff a
+ Music.Pitch.Scale: majorMajorSeventhChord :: Function Pitch
+ Music.Pitch.Scale: majorMinorSeventhChord :: Function Pitch
+ Music.Pitch.Scale: melodicMinorScaleUp :: Mode Pitch
+ Music.Pitch.Scale: modeFromSteps :: [Diff a] -> Diff a -> Mode a
+ Music.Pitch.Scale: modeIntervals :: Lens' (Mode a) [Diff a]
+ Music.Pitch.Scale: modeRepeat :: Lens' (Mode a) (Diff a)
+ Music.Pitch.Scale: modeToScale :: AffineSpace a => a -> Mode a -> Scale a
+ Music.Pitch.Scale: scaleMode :: Lens' (Scale a) (Mode a)
+ Music.Pitch.Scale: scaleToList :: AffineSpace a => Scale a -> [a]
+ Music.Pitch.Scale: scaleTonic :: Lens' (Scale a) a
- Music.Pitch.Common.Quality: expectedQualityType :: HasNumber a => a -> QualityType
+ Music.Pitch.Common.Quality: expectedQualityType :: Number -> QualityType
- Music.Pitch.Intonation: pureOctaveWith :: (Interval, Hertz) -> Interval -> Hertz
+ Music.Pitch.Intonation: pureOctaveWith :: (Interval, Double) -> Tuning Interval
- Music.Pitch.Intonation: synTune :: (Interval, Hertz) -> (Interval, Hertz) -> Interval -> Hertz
+ Music.Pitch.Intonation: synTune :: (Interval, Double) -> (Interval, Double) -> Interval -> Double

Files

music-pitch.cabal view
@@ -1,6 +1,6 @@  name:                   music-pitch-version:                1.8.1+version:                1.9.0 cabal-version:          >= 1.10 author:                 Hans Hoglund maintainer:             Hans Hoglund@@ -22,25 +22,25 @@   location:             git://github.com/music-suite/music-pitch.git    library                    -    build-depends:      base                    >= 4 && < 5,+    build-depends:      base                    >= 4        && < 5,                         containers,-                        lens                    >= 4.6      && < 4.7,+                        lens                    >= 4.11     && < 5,                         semigroups              >= 0.13.0.1 && < 1,-                        music-pitch-literal     == 1.8.1,-                        data-interval           >= 1.0.0 && < 2,-                        vector-space            >= 0.8.7 && < 0.9,-                        vector-space-points     >= 0.2 && < 0.3,+                        music-pitch-literal     == 1.9.0,+                        data-interval           >= 1.0.0    && < 2,+                        vector-space            >= 0.10.2   && < 1,+                        vector-space-points     >= 0.2      && < 1,                         nats,-                        positive                >= 0.3 && < 1,-                        type-unary              >= 0.2.16 && < 1.0+                        positive                >= 0.4      && < 1,+                        type-unary              >= 0.2.16   && < 1.0,+                        aeson                   >= 0.7.0.6  && < 1     exposed-modules:    Music.Pitch                         Music.Pitch.Absolute                         Music.Pitch.Equal                         Music.Pitch.Common+                        Music.Pitch.Common.Types                         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@@ -51,8 +51,15 @@                         Music.Pitch.Scale                         Music.Pitch.Clef                         Music.Pitch.Intonation-    other-modules:      Music.Pitch.StaffLines-                        Music.Pitch.Tokawa+    other-modules:      Music.Pitch.Tokawa     hs-source-dirs:     src     default-language:   Haskell2010+    default-extensions: StandaloneDeriving,+                        TypeFamilies,+                        TypeOperators,+                        GeneralizedNewtypeDeriving,+                        MultiParamTypeClasses,+                        DeriveDataTypeable,+                        ViewPatterns,+                        OverloadedStrings     ghc-options:        -fno-warn-typed-holes
src/Music/Pitch.hs view
@@ -18,32 +18,35 @@         module Data.VectorSpace,         module Data.AffineSpace,         module Data.AffineSpace.Point,+         module Music.Pitch.Augmentable,         module Music.Pitch.Alterable,+         module Music.Pitch.Absolute,-        module Music.Pitch.Ambitus,-        module Music.Pitch.Equal,         module Music.Pitch.Common,-        module Music.Pitch.Common.Names,-        module Music.Pitch.StaffLines,+        module Music.Pitch.Equal,+         module Music.Pitch.Clef,         module Music.Pitch.Intonation,         module Music.Pitch.Literal,+        module Music.Pitch.Ambitus,+        module Music.Pitch.Scale,   ) where  import Data.Semigroup 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 hiding (Mode) import Music.Pitch.Common.Names import Music.Pitch.Literal-import Music.Pitch.StaffLines import Music.Pitch.Clef import Music.Pitch.Intonation+import Music.Pitch.Scale 
src/Music/Pitch/Absolute.hs view
@@ -1,38 +1,19 @@ -{-# LANGUAGE GeneralizedNewtypeDeriving #-}-{-# LANGUAGE TypeFamilies               #-}------------------------------------------------------------------------------------------ |--- Copyright   : (c) Hans Hoglund 2012------ License     : BSD-style------ Maintainer  : hans@hanshoglund.se--- Stability   : experimental--- Portability : portable------ Absolute pitch representation.------ 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,+-- | Absolute pitch representation.+module Music.Pitch.Absolute+  (+  -- * Absolute pitch representation+  Hertz(..),+  -- FreqRatio(..),+  -- Octaves,+  Cents,+  Fifths,+  +  -- * HasFrequency class+  HasFrequency(..),+  -- octaves,+  fifths,+  cents,   ) where  import           Control.Applicative@@ -46,89 +27,61 @@  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, 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)--}+{-|+Number of pure octaves. --- |--- Number of pure octaves.------ Octaves are a logarithmic representation of frequency such that------ > f * (2/1) = frequency (octaves f + 1)---+Octaves are a logarithmic representation of frequency such that++> f * (2/1) = frequency (octaves f + 1)+-} newtype Octaves = Octaves { getOctaves :: Hertz }   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)----newtype Cents = Cents { getCents :: Hertz }-  deriving (Read, Show, Eq, Enum, Num, Ord, Fractional, Floating, Real, RealFrac)+{-|+Number of pure fifths. --- |--- Number of pure fifths.------ Fifths are a logarithmic representation of frequency.------ > f * (3/2) = frequency (fifths f + 1)---+Fifths are a logarithmic representation of frequency.++> f * (3/2) = frequency (fifths f + 1)++-} newtype Fifths = Fifths { getFifths :: Hertz }   deriving (Read, Show, Eq, Enum, Num, Ord, Fractional, Floating, Real, RealFrac) +{-|+Number of cents. -instance Semigroup Hertz    where (<>) = (*)-instance Semigroup Octaves  where (<>) = (+)-instance Semigroup Fifths   where (<>) = (+)-instance Semigroup Cents    where (<>) = (+)+Cents are a logarithmic representation of frequency such that -instance Monoid Hertz       where { mempty  = 1 ; mappend = (*) }-instance Monoid Octaves     where { mempty  = 0 ; mappend = (+) }-instance Monoid Fifths      where { mempty  = 0 ; mappend = (+) }-instance Monoid Cents       where { mempty  = 0 ; mappend = (+) }+> f * (2/1) = frequency (cents f + 1200) -{--instance AdditiveGroup FreqRatio where-  zeroV   = 1-  (^+^)   = (*)-  negateV f = 1 / f+-}+newtype Cents = Cents { getCents :: Hertz }+  deriving (Read, Show, Eq, Enum, Num, Ord, Fractional, Floating, Real, RealFrac) -instance VectorSpace FreqRatio where-  type Scalar FreqRatio = Double-  (*^) x f = FreqRatio ((getFreqRatio f) ** x) -instance AffineSpace Hertz where-  type Diff Hertz = FreqRatio-  (.-.) f1 f2 = FreqRatio $ (getHertz f1) / (getHertz f2)-  (.+^) p f = Hertz $ (getHertz p) * (getFreqRatio f)--}-instance AdditiveGroup Hertz where-  zeroV   = 1-  (^+^)   = (*)-  negateV f = 1 / f+instance Show Hertz where show h = (show (getHertz h)) ++ " Hz" -instance VectorSpace Hertz where-  type Scalar Hertz = Hertz-  (*^) x f = Hertz ((getHertz f) ** getHertz x)+instance Semigroup Hertz    where (<>) = (*)+instance Semigroup Octaves  where (<>) = (+)+instance Semigroup Fifths   where (<>) = (+)+instance Semigroup Cents    where (<>) = (+) +instance Monoid Hertz       where mempty  = 1 ; mappend = (*)+instance Monoid Octaves     where mempty  = 0 ; mappend = (+)+instance Monoid Fifths      where mempty  = 0 ; mappend = (+)+instance Monoid Cents       where mempty  = 0 ; mappend = (+)+ instance AffineSpace Hertz where-  type Diff Hertz = Hertz-  (.-.) = (-)-  (.+^) = (+)+  type Diff Hertz = Double+  (.-.) f1 f2 = (getHertz f1) / (getHertz f2)+  (.+^) f x = Hertz $ (getHertz f) * x  class HasFrequency a where   frequency :: a -> Hertz@@ -145,31 +98,15 @@ instance HasFrequency Cents where   frequency (Cents f)   =  (2/1) ** (f / 1200) +-- | Convert a frequency to octaves. octaves :: HasFrequency a => a -> Octaves octaves a = Octaves $ logBase (2/1) (frequency a) +-- | Convert a frequency to fifths. fifths :: HasFrequency a => a -> Fifths fifths a = Fifths $ logBase (3/2) (frequency a) +-- | Convert a frequency to cents. 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-      r = [-        1/1,-        (8*2)/15, 9/8,      (2*3)/5, 5/4,     (2*2)/3,-        10/7,-        3/2,      (4*2)/5,  5/3,     (2*8)/9, 15/8-        ]- 
src/Music/Pitch/Ambitus.hs view
@@ -1,25 +1,9 @@ -{-# 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.------------------------------------------------------------------------------------------+-- | Pitch range or ambitus. module Music.Pitch.Ambitus (     Ambitus,     ambitus,-    ambitus',+    -- ambitus',     mapAmbitus,     ambitusHighest,     ambitusLowest,@@ -32,32 +16,35 @@ import Data.VectorSpace import Data.AffineSpace --- | An ambitus is a closed interval (in the mathematical sense).+-- | An ambitus is (mathematical) interval. --  -- 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.+-- range instruments, chords, melodies etc. --  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) (b, b) (Ambitus a) (Ambitus b) 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)+      -- FIXME this can happen as empty span can be represented as PosInf..NegInf+      -- _                    -> error $ "Strange ambitus: " ++ show (I.lowerBound a, I.upperBound a)+      _                    -> error $ "Strange ambitus" -ambitus' :: (Num a, Ord a) => Iso' (a, a) (Ambitus a)-ambitus' = ambitus+-- ambitus' :: (Num a, Ord a) => Iso' (a, a) (Ambitus a)+-- ambitus' = ambitus  -- | Not a true functor for similar reasons as sets. mapAmbitus :: (Ord b, Num b) => (a -> b) -> Ambitus a -> Ambitus b
src/Music/Pitch/Clef.hs view
@@ -1,40 +1,21 @@ -{-# LANGUAGE ConstraintKinds            #-}-{-# LANGUAGE DeriveDataTypeable         #-}-{-# LANGUAGE DeriveFoldable             #-}-{-# LANGUAGE DeriveFunctor              #-}-{-# LANGUAGE DeriveTraversable          #-}-{-# LANGUAGE FlexibleContexts           #-}-{-# LANGUAGE FlexibleInstances          #-}-{-# LANGUAGE GADTs                      #-}-{-# LANGUAGE GeneralizedNewtypeDeriving #-}-{-# LANGUAGE MultiParamTypeClasses      #-}-{-# 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 (+-- | Clefs and staff positions.+module Music.Pitch.Clef+(+      -- * Staff lines+      StaffLines,+      HalfSpaces,+      ClefLine,+             -- * Clef representation-      ClefSymbol,+      ClefSymbol(..),       ClefOctave,-      Clef,+      Clef(..),       symbolName,       symbolPitch,       positionPitch,       pitchPosition,+       -- ** Properties       isModernClef,       isHistoricalClef,@@ -48,22 +29,47 @@       altoClef,       tenorClef,       baritoneClef,-  ) where+) where  import Data.Typeable -import Music.Pitch.StaffLines import Music.Pitch.Common import Music.Pitch.Literal +-- | Represents staff number relative middle. Staff zero is either the middle staff, or if using an+-- even number of lines, the staff below the middle space.+--+newtype StaffLines = StaffLines { getStaffLines :: Integer }+  deriving (Eq, Ord, Read, Show, Enum,+            Num, Real, Integral, Typeable)++-- | Represents the difference betwee  staff positions (often corresponding to one diatonic step).+newtype HalfSpaces = HalfSpaces { getHalfSpaces :: Integer }+  deriving (Eq, Ord, Read, Show, Enum,+            Num, Real, Integral, Typeable)++-- | Common clef symbols data ClefSymbol = GClef | CClef | FClef | PercClef | NeutralClef     deriving (Eq, Ord, Show, Typeable)  type ClefOctave = Integer type ClefLine   = StaffLines -type Clef = (ClefSymbol, ClefOctave, ClefLine)+newtype Clef = Clef { getClef :: (ClefSymbol, ClefOctave, ClefLine) }+  deriving (Eq, Ord, Typeable) +instance Show Clef where+  show x@(Clef a)+    | x == trebleClef       = "trebleClef"+    | x == bassClef         = "bassClef"+    | x == sopranoClef      = "sopranoClef"+    | x == mezzoSopranoClef = "mezzoSopranoClef"+    | x == altoClef         = "altoClef"+    | x == tenorClef        = "tenorClef"+    | x == baritoneClef     = "baritoneClef"+    | otherwise             = show a+    +-- | Return the English name of the given clef. symbolName :: ClefSymbol -> String symbolName GClef = "G clef" symbolName CClef = "C clef"@@ -71,21 +77,22 @@ symbolName PercClef = "Percussion clef" symbolName NeutralClef = "Neutral clef" +-- | Return the pitch implied by the given clef at the middle space or line. symbolPitch :: ClefSymbol -> Maybe Pitch-symbolPitch GClef = Just g+symbolPitch GClef = Just b' symbolPitch CClef = Just c-symbolPitch FClef = Just f+symbolPitch FClef = Just d_ symbolPitch _     = Nothing  -- TODO consolidate with common pitchPosition :: Clef -> Pitch -> Maybe StaffLines-pitchPosition (s,o,l) x = undefined+pitchPosition (Clef (s,o,l)) x = undefined   where     numbersPerOctave = 7     referencePitch = symbolPitch s :: Maybe Pitch  positionPitch :: Clef -> StaffLines -> Maybe Pitch-positionPitch (s,o,l) x = fmap (upDiatonic relativePosition) referencePitch+positionPitch (Clef (s,o,l)) x = fmap (upDiatonic relativePosition) referencePitch   where     numbersPerOctave = 7     referencePitch = symbolPitch s :: Maybe Pitch@@ -93,7 +100,7 @@  -- TODO implement fully in Pitch.Common.Diatonic upDiatonic :: Number -> Pitch -> Pitch-upDiatonic = error "Not implemented: upDiatonic"+upDiatonic = upDiatonicP c . fromIntegral -- TODO Why c?  {- TODO@@ -108,21 +115,30 @@   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. -}++-- | Standard treble clef. trebleClef :: Clef+-- | Standard bass clef. bassClef :: Clef+-- | Standard soprano clef. sopranoClef :: Clef+-- | Standard mezzo soprano clef. mezzoSopranoClef :: Clef+-- | Standard alto clef. altoClef :: Clef+-- | Standard tenor clef. tenorClef :: Clef+-- | Standard baritone 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)+trebleClef        = Clef (GClef, -1 :: ClefOctave, -1 :: ClefLine)+bassClef          = Clef (FClef, 1  :: ClefOctave, -1 :: ClefLine)+sopranoClef       = Clef (CClef, 0  :: ClefOctave, -2 :: ClefLine)+mezzoSopranoClef  = Clef (CClef, 0  :: ClefOctave, -1 :: ClefLine)+altoClef          = Clef (CClef, 0  :: ClefOctave, 0  :: ClefLine)+tenorClef         = Clef (CClef, 0  :: ClefOctave, 1  :: ClefLine)+baritoneClef      = Clef (CClef, 0  :: ClefOctave, 2  :: ClefLine) +-- | Is this a clef used in contemporary notation? isModernClef :: Clef -> Bool isModernClef x | x == trebleClef  = True isModernClef x | x == bassClef    = True@@ -130,11 +146,14 @@ isModernClef x | x == tenorClef   = True isModernClef x | otherwise        = False +-- | Is this an historical clef? isHistoricalClef :: Clef -> Bool isHistoricalClef _ = False --- | Is this a voice clef, i.e. a c clef on some staff.+-- | Is this a traditional 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
@@ -1,46 +1,22 @@ ---------------------------------------------------------------------------------------- |--- Copyright   : (c) Hans Hoglund 2012------ License     : BSD-style------ Maintainer  : hans@hanshoglund.se--- Stability   : experimental--- Portability : non-portable (TF,GNTD)------ Provides a representation of pitch as defined in Common Music Theory (CMT).------------------------------------------------------------------------------------------+-- | Common pitch representation. module Music.Pitch.Common (     module Music.Pitch.Common.Semitones,     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,     module Music.Pitch.Common.Spell,     module Music.Pitch.Common.Harmony,+    module Music.Pitch.Common.Names,   ) where -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 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.Types import Music.Pitch.Common.Harmony+import Music.Pitch.Common.Names
− src/Music/Pitch/Common/Chromatic.hs
@@ -1,15 +0,0 @@--{-# LANGUAGE DeriveDataTypeable         #-}-{-# LANGUAGE GeneralizedNewtypeDeriving #-}-{-# LANGUAGE NoMonomorphismRestriction  #-}-{-# LANGUAGE StandaloneDeriving         #-}-{-# LANGUAGE TypeFamilies               #-}--module Music.Pitch.Common.Chromatic (-    ChromaticSteps,-  ) where---newtype ChromaticSteps = ChromaticSteps { getChromaticSteps :: Integer }-  deriving (Eq, Ord, Show, Enum, Num, Real, Integral)-
− src/Music/Pitch/Common/Diatonic.hs
@@ -1,13 +0,0 @@--{-# LANGUAGE DeriveDataTypeable         #-}-{-# LANGUAGE GeneralizedNewtypeDeriving #-}-{-# LANGUAGE NoMonomorphismRestriction  #-}-{-# LANGUAGE StandaloneDeriving         #-}-{-# LANGUAGE TypeFamilies               #-}--module Music.Pitch.Common.Diatonic (-    DiatonicSteps,-  ) where--newtype DiatonicSteps = DiatonicSteps { getDiatonicSteps :: Integer }-  deriving (Eq, Ord, Show, Enum, Num, Real, Integral)
src/Music/Pitch/Common/Harmony.hs view
@@ -1,18 +1,5 @@ ---------------------------------------------------------------------------------------- |--- 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.------------------------------------------------------------------------------------------+-- | Basic harmony. module Music.Pitch.Common.Harmony (         isDissonance,         isConsonance,
src/Music/Pitch/Common/Interval.hs view
@@ -1,32 +1,13 @@ -{-# LANGUAGE DeriveDataTypeable         #-}-{-# LANGUAGE GeneralizedNewtypeDeriving #-}-{-# LANGUAGE NoMonomorphismRestriction  #-}-{-# LANGUAGE StandaloneDeriving         #-}-{-# LANGUAGE TypeFamilies               #-}----------------------------------------------------------------------------------------- |--- 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.Interval (--+-- | Common intervals.+module Music.Pitch.Common.Interval+(         -- * Intervals         Interval,         -- ** Creating intervals         interval,         interval',+        interval'',         _number,         _quality,         _steps,@@ -59,9 +40,6 @@         -- *** Inversion         invert, -        -- * Utility-        asInterval,-         -- * Basis values         IntervalBasis(..), @@ -69,7 +47,7 @@         convertBasis,         convertBasisFloat,         intervalDiv,-  ) where+) where  import           Data.Either import           Data.Maybe@@ -83,79 +61,22 @@ import qualified Data.List                    as List import           Data.Typeable import           Numeric.Positive+import           Data.Aeson                    (ToJSON (..))+import qualified Data.Aeson  import           Music.Pitch.Absolute import           Music.Pitch.Augmentable+import           Music.Pitch.Common.Types 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  --------------- |--- A musical interval such as minor third, augmented fifth, duodecim etc.------ 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.------ 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------ Adding intervals preserves spelling. For example:------ > 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--- (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:------ > 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-    ) }-    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+  (+)           = (^+^)+  negate        = negateV   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"@@ -173,24 +94,24 @@       showQuality (Diminished n)   = replicate (fromIntegral n) 'd'  instance Semigroup Interval where-  (<>)    = addInterval+  (<>)    = (^+^)  instance Monoid Interval where   mempty  = basis_P1-  mappend = addInterval+  mappend = (^+^)  instance AdditiveGroup Interval where   zeroV   = basis_P1-  (^+^)   = addInterval-  negateV = negateInterval+  (Interval (a1, d1)) ^+^ (Interval (a2, d2)) = Interval (a1 ^+^ a2, d1 ^+^ d2)+  negateV (Interval (a, d)) = Interval (-a, -d)  instance VectorSpace Interval where   type Scalar Interval = Integer   (*^) = stackInterval---- TODO move-data IntervalBasis = Chromatic | Diatonic-  deriving (Eq, Ord, Show, Enum)+    where+      stackInterval n a+        | n >= 0    = mconcat $ replicate (fromIntegral n) a+        | otherwise = negate $ stackInterval (negate n) a  instance HasBasis Interval where   type Basis Interval = IntervalBasis@@ -216,19 +137,17 @@ instance IsInterval Interval where   fromInterval (IntervalL (o,d,c)) = (basis_P8^*o) ^+^ (basis_A1^*c) ^+^ (basis_d2^*d) -negateInterval :: Interval -> Interval-negateInterval (Interval (a, d)) = Interval (-a, -d)+instance ToJSON DiatonicSteps where+  toJSON = toJSON . toInteger -addInterval :: Interval -> Interval -> Interval-addInterval (Interval (a1, d1)) (Interval (a2, d2)) = Interval (a1 + a2, d1 + d2)+instance ToJSON ChromaticSteps where+  toJSON = toJSON . toInteger -stackInterval :: Integer -> Interval -> Interval-stackInterval n a-  | n >= 0    = mconcat $ replicate (fromIntegral n) a-  | otherwise = negate $ stackInterval (negate n) a+instance ToJSON Interval where+  toJSON i = Data.Aeson.object [("steps", toJSON $ i^._steps), ("alteration", toJSON $ i^._alteration)]  intervalDiff :: Interval -> Int-intervalDiff (Interval (c, d)) = c - diatonicToChromatic d+intervalDiff (Interval (c, d)) = fromIntegral $ c - fromIntegral (diatonicToChromatic d)  -- | -- Creates an interval from a quality and number.@@ -241,7 +160,7 @@   :: Int        -- ^ Difference in chromatic steps (?).   -> Int        -- ^ Number of diatonic steps (NOT interval number).   -> Interval-mkInterval' diff diatonic = Interval (diatonicToChromatic diatonic + diff, diatonic)+mkInterval' diff diatonic = Interval (diatonicToChromatic (fromIntegral diatonic) + fromIntegral diff, fromIntegral diatonic)  basis_P1 = Interval (0, 0) basis_A1 = Interval (1, 0)@@ -259,10 +178,10 @@ -- in the d * d2 part (adding a unison, perfect or otherwise, can -- never increase the number of the interval) ---extractNumber :: Interval -> Number+extractNumber                     :: Interval -> Number extractNumber (Interval (a, d))-  | d >= 0    = Number (d + 1)-  | otherwise = Number (d - 1)+  | d >= 0                        = fromIntegral (d + 1)+  | otherwise                     = fromIntegral (d - 1)   -- |@@ -273,39 +192,39 @@ -- we are used to reading.  extractQuality :: Interval -> Quality-extractQuality (Interval (a, d))-  | (a < 0) && (d == 0) = diminish (extractQuality (Interval ((a + 1), d)))-  | (a, d) == (0, 0) = Perfect-  | (a > 0) && (d == 0) = augment (extractQuality (Interval ((a - 1), d)))-  | (a < 1) && (d == 1) = diminish (extractQuality (Interval ((a + 1), d)))-  | (a, d) == (1, 1) = Minor-  | (a, d) == (2, 1) = Major-  | (a > 2) && (d == 1) = augment (extractQuality (Interval ((a - 1), d)))-  | (a < 3) && (d == 2) = diminish (extractQuality (Interval ((a + 1), d)))-  | (a, d) == (3, 2) = Minor-  | (a, d) == (4, 2) = Major-  | (a > 4) && (d == 2) = augment (extractQuality (Interval ((a - 1), d)))-  | (a < 5) && (d == 3) = diminish (extractQuality (Interval ((a + 1), d)))-  | (a, d) == (5, 3) = Perfect-  | (a > 5) && (d == 3) = augment (extractQuality (Interval ((a - 1), d)))-  | (a < 7) && (d == 4) = diminish (extractQuality (Interval ((a + 1), d)))-  | (a, d) == (7, 4) = Perfect-  | (a > 7) && (d == 4) = augment (extractQuality (Interval ((a - 1), d)))-  | (a < 8) && (d == 5) = diminish (extractQuality (Interval ((a + 1), d)))-  | (a, d) == (8, 5) = Minor-  | (a, d) == (9, 5) = Major-  | (a > 9) && (d == 5) = augment (extractQuality (Interval ((a - 1), d)))-  | (a < 10) && (d == 6) = diminish (extractQuality (Interval ((a + 1), d)))-  | (a, d) == (10, 6) = Minor-  | (a, d) == (11, 6) = Major-  | (a > 11) && (d == 6) = augment (extractQuality (Interval ((a - 1), d)))-  | (a < 12) && (d == 7) = diminish (extractQuality (Interval ((a + 1), d)))-  | (a, d) == (12, 7) = Perfect-  | (a > 12) && (d == 7) = augment (extractQuality (Interval ((a - 1), d)))--- note: these last two cases *have* to be this way round, otherwise--- infinite loop occurs.-  | (a > 12) || (d > 7) = extractQuality (Interval ((a - 12), (d - 7)))-  | (a < 0) || (d < 0) = extractQuality (Interval ((-a), (-d)))+extractQuality (Interval (a, d))  +  | (a < 0)  && (d == 0)          = diminish $ extractQuality (Interval ((a + 1), d))+  | (a, d)   == (0, 0)            = Perfect+  | (a > 0)  && (d == 0)          = augment  $ extractQuality (Interval ((a - 1), d))+  | (a < 1)  && (d == 1)          = diminish $ extractQuality (Interval ((a + 1), d))+  | (a, d)   == (1, 1)            = Minor+  | (a, d)   == (2, 1)            = Major+  | (a > 2)  && (d == 1)          = augment  $ extractQuality (Interval ((a - 1), d))+  | (a < 3)  && (d == 2)          = diminish $ extractQuality (Interval ((a + 1), d))+  | (a, d)   == (3, 2)            = Minor+  | (a, d)   == (4, 2)            = Major+  | (a > 4)  && (d == 2)          = augment  $ extractQuality (Interval ((a - 1), d))+  | (a < 5)  && (d == 3)          = diminish $ extractQuality (Interval ((a + 1), d))+  | (a, d)   == (5, 3)            = Perfect+  | (a > 5)  && (d == 3)          = augment  $ extractQuality (Interval ((a - 1), d))+  | (a < 7)  && (d == 4)          = diminish $ extractQuality (Interval ((a + 1), d))+  | (a, d)   == (7, 4)            = Perfect+  | (a > 7)  && (d == 4)          = augment  $ extractQuality (Interval ((a - 1), d))+  | (a < 8)  && (d == 5)          = diminish $ extractQuality (Interval ((a + 1), d))+  | (a, d)   == (8, 5)            = Minor+  | (a, d)   == (9, 5)            = Major+  | (a > 9)  && (d == 5)          = augment  $ extractQuality (Interval ((a - 1), d))+  | (a < 10) && (d == 6)          = diminish $ extractQuality (Interval ((a + 1), d))+  | (a, d)   == (10, 6)           = Minor+  | (a, d)   == (11, 6)           = Major+  | (a > 11) && (d == 6)          = augment  $ extractQuality (Interval ((a - 1), d))+  | (a < 12) && (d == 7)          = diminish $ extractQuality (Interval ((a + 1), d))+  | (a, d)   == (12, 7)           = Perfect+  | (a > 12) && (d == 7)          = augment  $ extractQuality (Interval ((a - 1), d))+  -- note: these last two cases *have* to be this way round, otherwise+  -- infinite loop occurs.+  | (a > 12) || (d > 7)           = extractQuality (Interval ((a - 12), (d - 7)))+  | (a < 0)  || (d < 0)           = extractQuality (Interval ((-a), (-d)))   -- | Creates a perfect interval.@@ -339,24 +258,19 @@ doublyDiminished :: Number -> Interval doublyDiminished = mkInterval (Diminished 2) -{---Prelude Music.Prelude> separate (2*^_P8+m3)-(2,m3)-Prelude Music.Prelude>-Prelude Music.Prelude> separate (3*^_P8+m3)-(3,m3)-Prelude Music.Prelude>-Prelude Music.Prelude> separate (0*^_P8+m3)-(0,m3)-Prelude Music.Prelude> separate ((-1)*^_P8+m3)---} -- | -- Separate a compound interval into octaves and a simple interval. ----- > (perfect octave)^*x + y = z  iff  (x, y) = separate z+-- > x*^_P8 + y = z  iff  (x, y) = separate z --+-- >>> separate (2*^_P8+m3)+-- (2,m3)+-- >>> separate (3*^_P8+m3)+-- (3,m3)+-- >>> separate (0*^_P8+m3)+-- (0,m3)+-- >>> separate ((-1)*^_P8+m3)+--  separate :: Interval -> (Octaves, Interval) separate i = (fromIntegral o, i ^-^ (fromIntegral o *^ basis_P8))   where@@ -390,8 +304,14 @@ -- Returns whether the given interval is compound. -- -- A compound interval is either a negative interval, or a positive interval spanning--- one octave or more.+-- one octave or more. Note that compound intervals may be smaller than an octave if+-- they are negative, so --+-- >>> isCompound (-m3)+-- True +-- >>> isCompound $ abs (-m3)+-- False +-- isCompound :: Interval -> Bool isCompound x = octaves x /= 0 @@ -454,18 +374,10 @@ invert :: Interval -> Interval invert = simple . negate --- |--- This is just the identity function, but is useful to fix the type of 'Interval'.----asInterval :: Interval -> Interval-asInterval = id    --- mkInterval :: Quality -> Number -> Interval mkInterval q n = mkInterval' (fromIntegral diff) (fromIntegral steps)   where@@ -506,24 +418,17 @@ interval' = iso (\(d,s) -> mkInterval' (fromIntegral d) (fromIntegral s))    (\x -> (qualityToDiff (number x >= 0) (expectedQualityType (number x)) (quality x), (number x)^.diatonicSteps)) -{----- -- 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+-- | View an interval as a pair of total number of chromatic and diatonic steps.+interval'' :: Iso' (ChromaticSteps, DiatonicSteps) Interval+interval'' = iso Interval getInterval -toMajorMinorType Perfect = Major-toPerfectType    Major   = Perfect-toPerfectType    Minor   = (Diminished 1)--- toPerfectType    x = x+{-+Note: This is *not* the same as wrapping/unwrapping, as the number of chromatic steps viewed here is+an *alteration*, rather than the total number of chromatic steps (basis d2). +E.g. d5 is internally represented as (6,4) but _P5^.from interval' == (-1,4). -}---          +          {-| >>> m3 & _number %~ pred m2@@ -555,24 +460,23 @@ d5 >>> _P5 & _quality .~ (Diminished 1) d5- -}                -- Internal stuff  -- TODO more generic pattern here-diatonicToChromatic :: Int -> Int-diatonicToChromatic d = (octaves*12) + go restDia+diatonicToChromatic :: DiatonicSteps -> ChromaticSteps+diatonicToChromatic d = fromIntegral $ (octaves*12) + go restDia     where         -- restDia is always in [0..6]-        (octaves, restDia) = d `divMod` 7+        (octaves, restDia) = fromIntegral d `divMod` 7         go = ([0,2,4,5,7,9,11] !!)  -- | Integer div of intervals: i / di = x, where x is an integer intervalDiv :: Interval -> Interval -> Int-intervalDiv (Interval (a, d)) (Interval (1, 0)) = a-intervalDiv (Interval (a, d)) (Interval (0, 1)) = d+intervalDiv (Interval (a, d)) (Interval (1, 0)) = fromIntegral a+intervalDiv (Interval (a, d)) (Interval (0, 1)) = fromIntegral d intervalDiv i di   | (i > basis_P1) = intervalDivPos i di   | (i < basis_P1) = intervalDivNeg i di@@ -604,13 +508,15 @@   | 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+    Interval (fromIntegral -> m, fromIntegral -> n) = i+    Interval (fromIntegral -> a, fromIntegral -> b) = j+    Interval (fromIntegral -> c, fromIntegral -> d) = k     p = (a*d - b*c)     q = (a*n - b*m)     r = (d*m - c*n)-+    +    divides :: Integral a => a -> a -> Bool+    x `divides` y = (y `rem` x) == 0  -- | Same as above, but don't worry if new interval has non-integer -- coefficients -- useful when getting a value to use as a frequency@@ -623,14 +529,9 @@ convertBasisFloat i j k   | (p == 0) = Nothing   | otherwise = Just (r / p, q / p)-  where Interval (m, n) = i-        Interval (a, b) = j-        Interval (c, d) = k+  where Interval (fromIntegral -> m, fromIntegral -> n) = i+        Interval (fromIntegral -> a, fromIntegral -> b) = j+        Interval (fromIntegral -> c, fromIntegral -> d) = k         p = fromIntegral $ (a*d - b*c)         q = fromIntegral $ (a*n - b*m)         r = fromIntegral $ (d*m - c*n)---divides :: Integral a => a -> a -> Bool-x `divides` y = (y `rem` x) == 0-
src/Music/Pitch/Common/Names.hs view
@@ -1,18 +1,5 @@ ---------------------------------------------------------------------------------------- |--- 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.------------------------------------------------------------------------------------------+-- | Common pitch names in various (human) languages. module Music.Pitch.Common.Names (       Language(..),       Mode(..),@@ -48,6 +35,12 @@   | NewSwedish   deriving (Show, Eq, Ord)   +data Mode = MajorMode | MinorMode+  deriving (Eq, Ord, Show)++showKey :: Language -> Pitch -> Mode -> String+showKey lang pitch mode = showPitch lang pitch ++ showSep lang ++ showMode lang mode+ showPitch :: Language -> Pitch -> String showPitch lang pitch = (!! (pitchToIndex + pitchNameOffset)) $ fromMaybe (error "showPitch: Bad lang") $ listToMaybe $ filter (\xs -> head xs == show lang) $ pitchNames   where@@ -62,18 +55,12 @@        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
src/Music/Pitch/Common/Number.hs view
@@ -1,53 +1,31 @@ -{-# LANGUAGE DeriveDataTypeable         #-}-{-# LANGUAGE GeneralizedNewtypeDeriving #-}-{-# LANGUAGE NoMonomorphismRestriction  #-}-{-# LANGUAGE StandaloneDeriving         #-}-{-# LANGUAGE TypeFamilies               #-}--module Music.Pitch.Common.Number where+-- | Number component of intervals.+module Music.Pitch.Common.Number+(+        Number,+        HasNumber(..),+        unison,+        prime,+        second,+        third,+        fourth,+        fifth,+        sixth,+        seventh,+        octave,+        ninth,+        tenth,+        eleventh,+        twelfth,+        thirteenth,+        fourteenth,+        fifteenth,+        diatonicSteps,+) 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)+import Music.Pitch.Common.Types -instance Show Number where { show = show . getNumber } instance HasNumber Number where number = id  -- | A synonym for @1@.
src/Music/Pitch/Common/Pitch.hs view
@@ -1,25 +1,7 @@ -{-# LANGUAGE DeriveDataTypeable         #-}-{-# LANGUAGE FlexibleInstances          #-}-{-# LANGUAGE GeneralizedNewtypeDeriving #-}-{-# LANGUAGE StandaloneDeriving         #-}-{-# LANGUAGE TypeFamilies               #-}----------------------------------------------------------------------------------------- |--- Copyright   : (c) Hans Hoglund, Edward Lilley 2012–2014------ License     : BSD-style------ Maintainer  : hans@hanshoglund.se--- Stability   : experimental--- Portability : non-portable (TF,GNTD)------ Provides a standard pitch representation.-------------------------------------------------------------------------------------------module Music.Pitch.Common.Pitch (+-- | Common pitch.+module Music.Pitch.Common.Pitch+(         -- * Accidentals         Accidental,         natural,@@ -50,10 +32,7 @@         downChromaticP,         invertDiatonicallyP,         invertChromaticallyP,-        -        -- ** Utility-        asPitch-  ) where+) where  import           Control.Applicative import           Control.Monad@@ -67,50 +46,19 @@ import           Data.Semigroup import           Data.Typeable import           Data.VectorSpace+import           Data.Aeson                    (ToJSON (..))+import qualified Data.Aeson  import           Music.Pitch.Absolute import           Music.Pitch.Alterable import           Music.Pitch.Augmentable+import           Music.Pitch.Common.Types 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.------ 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,--- i.e. a double flat is @-2@, natural @0@ and so on.----newtype Accidental = Accidental { getAccidental :: Integer }-  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)--instance Alterable Accidental where-  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)--- Requires FlexibleInstances- sharp, flat, natural, doubleFlat, doubleSharp :: Accidental  -- | The double sharp accidental.@@ -146,66 +94,7 @@ isStandardAccidental a = abs a < 2 -- was: isStandard --- |--- A pitch name.----data Name = C | D | E | F | G | A | B-  deriving (Eq, Ord, Show, Enum) --- |--- Common pitch representation.------ Intervals and pitches can be added using '.+^'. To get the interval between--- two pitches, use '.-.'.------ Pitches are normally entered using the following literals.------ > c d e f g a b------ Notes with accidentals can be written by adding the @s@ or @b@ suffices--- (or two for double sharps and flats).------ > cs, ds, es ...    -- sharp--- > cb, db, eb ...    -- flat--- > css, dss, ess ... -- double sharp--- > cbb, dbb, ebb ... -- double flat------ There is also a convenience syntax for entering pitches one octave up or--- down, using @'@ and @_@ respectively.------ > g a b c'--- > d c b_ c------ Because of some overloading magic, we can actually write @sharp@ and--- @flat@ as /postfix/ functions. This gives a better read:------ > cs == c sharp--- > db == c flat------ You can of course use typical functional transformation of pitch as well.--- For example 'sharpen' and 'flatten' are the ordinary (prefix) versions of--- 'sharp' and 'flat'------ > sharpen c             == c sharp       == cs--- > flatten d             == d flat        == ds--- > (sharpen . sharpen) c == c doubleSharp == css--- > (flatten . flatten) d == d doubleFlat  == dss------ Note that there is no guarantee that your pitch representation use--- enharmonic equivalence, so @cs == db@ may or may not hold.------ > c .+^ minor third == eb--- > f .-. c           == perfect fourth------ Pitches are described by name, accidental and octave number.------ > c   == fromIntegral 0--- > _P4 == perfect fourth   == interval Perfect 5--- > d5  == diminished fifth == diminish (perfect fifth)----newtype Pitch = Pitch { getPitch :: Interval }-  deriving (Eq, Ord, Typeable)- instance IsPitch Pitch where   fromPitch (PitchL (c, a, o)) =     Pitch $ (\a b -> (fromIntegral a, fromIntegral b)^.interval') (qual a) c ^+^ (_P8^* fromIntegral o)@@ -238,13 +127,16 @@   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"+  fromInteger   = toEnum . fromInteger  instance AffineSpace Pitch where   type Diff Pitch     = Interval   Pitch a .-. Pitch b = a ^-^ b   Pitch a .+^ b       = Pitch (a ^+^ b) +instance ToJSON Pitch where+  toJSON = toJSON . (.-. c)+ -- | -- Creates a pitch from name accidental. --@@ -278,12 +170,6 @@ accidental = fromIntegral . intervalDiff . simple . getPitch   where     intervalDiff = view (from interval'._1)---- |--- This is just the identity function, but is useful to fix the type of 'Pitch'.----asPitch :: Pitch -> Pitch-asPitch = id  upChromaticP :: Pitch -> ChromaticSteps -> Pitch -> Pitch upChromaticP origin n = relative origin $ (_alteration +~ n)
src/Music/Pitch/Common/Quality.hs view
@@ -1,32 +1,34 @@ -{-# LANGUAGE DeriveDataTypeable         #-}-{-# LANGUAGE GeneralizedNewtypeDeriving #-}-{-# LANGUAGE NoMonomorphismRestriction  #-}-{-# LANGUAGE StandaloneDeriving         #-}-{-# LANGUAGE TypeFamilies               #-}+-- | Common interval quality.+module Music.Pitch.Common.Quality+(+        -- * Quality+        Quality(..),+        qualityTypes,+        +        HasQuality(..),+        invertQuality,+        isPerfect,+        isMajor,+        isMinor,+        isAugmented,+        isDiminished, -module Music.Pitch.Common.Quality (-    -- * Quality-    Quality(..),-    HasQuality(..),-    invertQuality,-    isPerfect,-    isMajor,-    isMinor,-    isAugmented,-    isDiminished,+        -- ** Quality type+        QualityType(..),+        expectedQualityType, -    -- * Quality type-    QualityType(..),-    expectedQualityType,-    qualityTypes,-    qualityToDiff+        -- ** Quality to alteration+        Direction(..),+        qualityToAlteration, +        qualityToDiff ) where  import           Music.Pitch.Augmentable+import           Music.Pitch.Common.Types import           Music.Pitch.Common.Number-import           Music.Pitch.Common.Chromatic+import           Data.Maybe (fromMaybe)  -- | Types of value that has an interval quality (mainly 'Interval' and 'Quality' itself). class HasQuality a where@@ -51,36 +53,17 @@ isMinor a = case quality a of { Minor -> True ; _ -> False }  -- |--- Returns whether the given quality is /augmented/ (including double augmented etc).+-- 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).+-- 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 @@ -93,17 +76,18 @@ -- 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)+  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. --@@ -120,35 +104,64 @@     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]+-- | +-- The quality type expected for a given number, i.e. perfect for unisons, fourths,+-- and fifths and major/minor for everything else.  +expectedQualityType :: Number -> QualityType+expectedQualityType x = if ((abs x - 1) `mod` 7) + 1 `elem` [1,4,5]   then PerfectType else MajorMinorType +-- |+-- Return all possible quality types for a given quality. 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+-- |+-- Return whether the given combination of quality and number forms a valid interval+-- expression.+--  +isValidQualityNumber :: Quality -> Number -> Bool+isValidQualityNumber q n = expectedQualityType n `elem` qualityTypes q++data Direction = Upward | Downward+  deriving (Eq, Ord, Show)++-- |+-- Return the alteration in implied by the given quality to a number of a given quality type.+--+qualityToAlteration :: Direction -> QualityType -> Quality -> Maybe ChromaticSteps+qualityToAlteration d qt q = fmap fromIntegral $ go d 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 Upward MajorMinorType (Augmented n)    = Just $ 0 + n+    go Upward MajorMinorType Major            = Just $ 0+    go Upward MajorMinorType Minor            = Just $ (-1)+    go Upward MajorMinorType (Diminished n)   = Just $ -(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 Downward MajorMinorType (Augmented n)  = Just $ -(1 + n)+    go Downward MajorMinorType Major          = Just $ -1+    go Downward MajorMinorType Minor          = Just $ 0+    go Downward MajorMinorType (Diminished n) = Just $ 0 + n     -    go _ PerfectType (Augmented n)  = 0 + n-    go _ PerfectType Perfect        = 0-    go _ PerfectType (Diminished n) = 0 - n+    go Upward PerfectType (Augmented n)       = Just $ 0 + n+    go Upward PerfectType Perfect             = Just $ 0+    go Upward PerfectType (Diminished n)      = Just $ 0 - n++    go Downward PerfectType (Augmented n)     = Just $ 0 - n+    go Downward PerfectType Perfect           = Just $ 0+    go Downward PerfectType (Diminished n)    = Just $ 0 + n     -    go _ qt q = error $ "qualityToDiff: Unknown interval expression (" ++ show qt ++ ", " ++ show q ++ ")"+    go _ qt q = Nothing++qualityToDiff x qt q = fromMaybe e $ qualityToAlteration (f x) qt q+  where+    f True  = Upward+    f False = Downward+    e       = error $+      "qualityToDiff: Unknown interval expression (" +      ++ show qt ++ ", " ++ show q ++ ")"++{-# DEPRECATED qualityToDiff "Use qualityToAlteration" #-}+
src/Music/Pitch/Common/Semitones.hs view
@@ -1,31 +1,11 @@ -{-# LANGUAGE GeneralizedNewtypeDeriving #-}-{-# LANGUAGE StandaloneDeriving         #-}----------------------------------------------------------------------------------------- |--- Copyright   : (c) Hans Hoglund, Edward Lilley 2012–2014------ License     : BSD-style------ Maintainer  : hans@hanshoglund.se--- Stability   : experimental--- Portability : non-portable (TF,GNTD)------ Provides semitone, octave and step representation of intervals.-------------------------------------------------------------------------------------------module Music.Pitch.Common.Semitones (+-- | Semitones and enharmonic equivalence.+module Music.Pitch.Common.Semitones+(         -- * Types         -- ** Octaves         Octaves,-        -- HasOctaves(..), -        -- ** Steps-        Steps,-        -- HasSteps(..),-         -- ** Semitones         Semitones,         HasSemitones(..),@@ -40,20 +20,9 @@         -- * Enharmonic equivalence         (=:=),         (/:=),-  ) where---- |--- An interval represented as a number of octaves, including negative--- intervals.------ > octaves a = semitones a `div` 12--- > steps   a = semitones a `mod` 12----newtype Octaves = Octaves { getOctaves :: Integer }-  deriving (Eq, Ord, Num, Enum, Real, Integral)+) where -instance Show       Octaves where { show = show . getOctaves }-instance HasOctaves Octaves where { octaves = id }+import Music.Pitch.Common.Types  -- | -- Class of intervals that has a number of 'Octaves'.@@ -73,20 +42,9 @@   --   octaves :: a -> Octaves +instance HasOctaves Octaves where { octaves = id }  --- |--- An interval represented as a number of steps in the range /0 ≤ x < 12/.------ > octaves a = semitones a `div` 12--- > steps   a = semitones a `mod` 12----newtype Steps = Steps { getSteps :: Integer }-  deriving (Eq, Ord, Num, Enum, Real, Integral)--instance Show Steps where { show = show . getSteps }--- instance HasSteps Steps where { steps = id }- {- -- | -- Class of intervals that has a number of 'Steps'.@@ -104,31 +62,7 @@   steps :: a -> Steps -} -- -- |--- An interval represented as a number of semitones, including negative--- intervals, as well as intervals larger than one octave. This representation--- does not take spelling into account, so for example a major third and a--- diminished fourth can not be distinguished.------ Intervals that name a number of semitones (i.e. 'semitone', 'tritone') does--- not have an unequivocal spelling. To convert these to an interval, a--- 'Spelling' must be provided:------ >>> spell usingSharps tritone--- _A4------ >>> spell usingFlats  tritone--- d5----newtype Semitones = Semitones { getSemitones :: Integer }-  deriving (Eq, Ord, Num, Enum, Real, Integral)--instance Show         Semitones where { show = show . getSemitones }-instance HasSemitones Semitones where { semitones = id }---- | -- Class of intervals that can be converted to a number of 'Semitones'. -- class HasSemitones a where@@ -150,6 +84,7 @@   --   semitones :: a -> Semitones +instance HasSemitones ChromaticSteps where { semitones = id }   semitone, tone, ditone, tritone :: Semitones
src/Music/Pitch/Common/Spell.hs view
@@ -1,23 +1,7 @@ -{-# LANGUAGE GeneralizedNewtypeDeriving #-}-{-# LANGUAGE StandaloneDeriving         #-}-{-# LANGUAGE TypeFamilies               #-}----------------------------------------------------------------------------------------- |--- Copyright   : (c) Hans Hoglund, Edward Lilley 2012–2014------ License     : BSD-style------ Maintainer  : hans@hanshoglund.se--- Stability   : experimental--- Portability : non-portable (TF,GNTD)------ Provides pitch spellings.-------------------------------------------------------------------------------------------module Music.Pitch.Common.Spell (+-- | Provides pitch spelling.+module Music.Pitch.Common.Spell+(         -- ** Spelling         -- * About         -- $semitonesAndSpellings@@ -31,7 +15,7 @@         modally,         usingSharps,         usingFlats,-  ) where+) where  import           Data.AffineSpace import           Data.VectorSpace
+ src/Music/Pitch/Common/Types.hs view
@@ -0,0 +1,305 @@++{-# LANGUAGE FlexibleInstances #-}++-- | Common (Western classical) pitches, intervals and related types.+module Music.Pitch.Common.Types+(+        -- * Even octaves and steps+        Octaves,+        DiatonicSteps,+        ChromaticSteps,+        Semitones,+        +        -- * Intervals+        Number,+        Quality(..),+        QualityType(..),+        IntervalBasis(..),+        Interval(..),++        -- * Pitch+        Name(..),+        Accidental,+        Pitch(..),        +) where++import Data.Typeable+import Data.AdditiveGroup++import Music.Pitch.Literal+import Music.Pitch.Alterable+import Music.Pitch.Augmentable++{-|+Number of chromatic steps.+May be negative, indicating a downward interval. +-}+newtype ChromaticSteps = ChromaticSteps { getChromaticSteps :: Int }+  deriving (Eq, Ord, Show, Enum, Num, Real, Integral)++{-| +Number of diatonic steps.+May be negative, indicating a downward interval. +-}+newtype DiatonicSteps = DiatonicSteps { getDiatonicSteps :: Int }+  deriving (Eq, Ord, Show, Enum, Num, Real, Integral)++{-| +Number of octaves.+May be negative, indicating a downward interval. +-}+newtype Octaves = Octaves { getOctaves :: Int }+  deriving (Eq, Ord, Num, Enum, Real, Integral)++{-|+Number of semitones.+May be negative, indicating a downward interval. +-}+type Semitones = ChromaticSteps++{-|+The /number/ component of an interval (fourth, fifth) etc.+May be negative, indicating a downward interval. +-}+newtype Number = Number { getNumber :: Integer }+  deriving (Eq, Ord, Num, Enum, Real, Integral)++{-|+The /quality/ component of an interval (minor, major, augmented).+Generalized from single\/double augmented\/diminished to any number of steps.+-}+data Quality+  = Major+  | Minor+  | Perfect+  | Augmented Integer+  | Diminished Integer+  deriving (Eq, Ord, Show)+{-+TODO we really want to use Positive instead of Integer+Alternatively, we could do it as a recursive type++data Quality+  = Major+  | Minor+  | Perfect+  | Augment Quality+  | Diminish Quality+-}++{-|+The alteration implied by a quality is dependent on whether it is attached+to a major\/minor vs. a perfect-style number. This type represents the two possibilities.+-}+data QualityType = PerfectType | MajorMinorType+  deriving (Eq, Ord, Read, Show)++{-|+Accidental, represented as number of alterations.+Generalized from natural and single\/double sharp\/flat to any number of steps.+-}+newtype Accidental = Accidental { getAccidental :: Integer }+  deriving (Eq, Ord, Num, Enum, Real, Integral)++{-|+Pitch name component.+-}+data Name = C | D | E | F | G | A | B+  deriving (Eq, Ord, Show, Enum)++{-|+This type represents standard basis for intervbals.+ -}+data IntervalBasis = Chromatic | Diatonic+  deriving (Eq, Ord, Show, Enum)++{-|+Interval type.+ -}+newtype Interval = Interval { getInterval :: (ChromaticSteps, DiatonicSteps) }+  deriving (Eq, Typeable)++{-|+Pitch type.+-}+newtype Pitch = Pitch { getPitch :: Interval }+  deriving (Eq, Ord, Typeable)++++instance Show Octaves where+  show = show . getOctaves++instance Show Number where+  show = show . getNumber++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)++instance Alterable Accidental where+  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)+-- Requires FlexibleInstances++{-| 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)++instance AdditiveGroup ChromaticSteps where+  zeroV = 0+  (^+^) = (+)+  negateV = negate++instance AdditiveGroup DiatonicSteps where+  zeroV = 0+  (^+^) = (+)+  negateV = negate++++++{-+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+-}++{-+Common pitch representation.++Intervals and pitches can be added using '.+^'. To get the interval between+two pitches, use '.-.'.++Pitches are normally entered using the following literals.++> c d e f g a b++Notes with accidentals can be written by adding the @s@ or @b@ suffices+(or two for double sharps and flats).++> cs, ds, es ...    -- sharp+> cb, db, eb ...    -- flat+> css, dss, ess ... -- double sharp+> cbb, dbb, ebb ... -- double flat++There is also a convenience syntax for entering pitches one octave up or+down, using @'@ and @_@ respectively.++> g a b c'+> d c b_ c++Because of some overloading magic, we can actually write @sharp@ and+@flat@ as /postfix/ functions. This gives a better read:++> cs == c sharp+> db == c flat++You can of course use typical functional transformation of pitch as well.+For example 'sharpen' and 'flatten' are the ordinary (prefix) versions of+'sharp' and 'flat'++> sharpen c             == c sharp       == cs+> flatten d             == d flat        == ds+> (sharpen . sharpen) c == c doubleSharp == css+> (flatten . flatten) d == d doubleFlat  == dss++Note that there is no guarantee that your pitch representation use+enharmonic equivalence, so @cs == db@ may or may not hold.++> c .+^ minor third == eb+> f .-. c           == perfect fourth++Pitches are described by name, accidental and octave number.++> c   == fromIntegral 0+> _P4 == perfect fourth   == interval Perfect 5+> d5  == diminished fifth == diminish (perfect fifth)++-}++{-+A musical interval such as minor third, augmented fifth, duodecim etc.++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.++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++Adding intervals preserves spelling. For example:++> 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+(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:++> m5  == minor   fifth    == interval Minor   5 > _P4 == perfect fourth   == interval+Perfect 5 > d5  == diminished fifth == diminish (perfect fifth)++-}+++{-+An accidental is either flat, natural or sharp.++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,+i.e. a double flat is @-2@, natural @0@ and so on.++-}++{-+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.++-}++{-+An interval represented as a number of octaves, including negative+intervals.++> octaves a = semitones a `div` 12+> steps   a = semitones a `mod` 12+-}+
src/Music/Pitch/Equal.hs view
@@ -1,28 +1,15 @@ -{-# LANGUAGE StandaloneDeriving #-} {-# LANGUAGE RankNTypes #-}-{-# LANGUAGE TypeOperators #-}-{-# LANGUAGE TypeFamilies #-} ----------------------------------------------------------------------------------------- |--- Copyright   : (c) Hans Hoglund 2012------ License     : BSD-style------ Maintainer  : hans@hanshoglund.se--- Stability   : experimental--- Portability : portable------ 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.-----------------------------------------------------------------------------------------+{-| Generic equal temperament pitch. -module Music.Pitch.Equal (+Use the type-level numbers to construct an temperement dividing+the octave in any number of equal-sized steps.++Common cases such as 6, 12 and 24 are provided for convenience.+-}+module Music.Pitch.Equal+(     -- * Equal temperament     Equal,     toEqual,@@ -63,11 +50,12 @@  newtype Equal a = Equal { getEqual :: Int } -deriving instance {-IsNat a =>-} Eq (Equal a)-deriving instance {-IsNat a =>-} Ord (Equal a)+deriving instance Eq (Equal a)+deriving instance Ord (Equal a) -instance {-IsNat a =>-} Show (Equal a) where+instance Show (Equal a) where   show (Equal a) = show a+  -- OR:   -- showsPrec d (Equal x) = showParen (d > app_prec) $   --      showString "Equal " . showsPrec (app_prec+1) x   --   where app_prec = 10@@ -100,14 +88,14 @@ getSize :: IsNat a => Equal a -> Nat a getSize _ = nat  --- | Size of this type (value not evaluated).--- --- >>> size (undefined :: Equal N2)--- 2--- --- >>> size (undefined :: Equal N12)--- 12--- +{-| Size of this type (value not evaluated).++>>> size (undefined :: Equal N2)+2++>>> size (undefined :: Equal N12)+12+-} size :: IsNat a => Equal a -> Int size = natToZ . getSize @@ -138,28 +126,29 @@ 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---+{-| 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---+{-| 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 
src/Music/Pitch/Intonation.hs view
@@ -1,28 +1,13 @@ -{-# LANGUAGE ViewPatterns #-}------------------------------------------------------------------------------------------ |--- Copyright   : (c) Hans Hoglund 2012------ License     : BSD-style------ Maintainer  : hans@hanshoglund.se--- Stability   : experimental--- Portability : portable------ Provides intonation, i.e. mappings from relative to absolute pitch.------------------------------------------------------------------------------------------+-- | Intonation and tuning. module Music.Pitch.Intonation (-      Intonation,-      Tuning,+      Intonation(..),+      Tuning(..),        intone,       -- makeBasis,       synTune,-      tetTune,+      -- tetTune,       pureOctaveWith,        -- * Specific tunings@@ -47,8 +32,11 @@ import Data.Semigroup import Data.VectorSpace import Data.AffineSpace+import Data.Basis import Control.Monad import Control.Applicative+import Data.Fixed+import Data.Ratio import Control.Lens  import Music.Pitch.Absolute@@ -56,30 +44,39 @@ import Music.Pitch.Common.Interval import Music.Pitch.Common.Pitch -type Intonation p = p -> Hertz-type Tuning i = i -> {-FreqRatio-}Hertz+newtype Tuning i = Tuning { getTuning :: i -> Double } -synTune :: (Interval, {-FreqRatio-}Hertz) -> (Interval, {-FreqRatio-}Hertz) -> Interval -> {-FreqRatio-}Hertz-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 (Intervals._A1 :: Interval)-        maked2 = makeBasis (Intervals.d2  :: Interval)+newtype Intonation p = Intonation { getIntonation :: p -> Hertz } -makeBasis :: Interval -> (Interval, {-FreqRatio-}Hertz) -> (Interval, {-FreqRatio-}Hertz) -> {-FreqRatio-}Hertz+basis_A1 :: Interval+basis_A1 = basisValue Chromatic++basis_d2 :: Interval+basis_d2 = basisValue Diatonic++synTune :: (Interval, Double) -> (Interval, Double) -> Interval -> Double+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++makeBasis :: Interval -> (Interval, Double) -> (Interval, Double) -> Double makeBasis i (i1, r1) (i2, r2) = case (convertBasisFloat i i1 i2) of-  Just (x, y) -> (x *^ r1) ^+^ (y *^ r2)+  Just (x, y) -> (r1 ** x) * (r2 ** y)   Nothing -> error ("Cannot use intervals " ++ (show i1) ++ " and " ++ (show i2) ++ " as basis pair to represent " ++ (show i))  -- | Turn a tuning into an intonation. intone :: (Pitch, Hertz) -> Tuning Interval -> Intonation Pitch-intone (b, f) t p = f .+^ (t i) where i = p .-. b+intone (b, f) (Tuning t) = Intonation $ int+  where int p = f .+^ (t i) where i = p .-. b -- More generally: -- intone :: AffineSpace p => (p, Hertz) -> Tuning (Diff p) -> Intonation p   -- Standard syntonic (meantone) tunings, with P8 = 2 -pureOctaveWith = synTune (_P8, 2)+pureOctaveWith :: (Interval, Double) -> Tuning Interval+pureOctaveWith = Tuning . synTune (_P8, 2)  pythagorean :: Tuning Interval pythagorean = pureOctaveWith (_P5, 3/2)@@ -92,6 +89,7 @@  -- TET tunings, i.e. where P8 = 2 and (some other interval) = 1 +tetTune :: Interval -> Tuning Interval tetTune i = pureOctaveWith (i, 1)  fiveToneEqual :: Tuning Interval@@ -115,3 +113,22 @@ -- | Modern standard intonation, i.e. 12-TET with @a = 440 Hz@. standardIntonation :: Intonation Pitch standardIntonation = intone (a, 440) twelveToneEqual++{-+Possible instances for numeric types based on standard intonation.++Not used, the user should choose perform the appropriate conversion for a given+tuning system.++instance IsInterval Double where+  fromInterval i = getTuning twelveToneEqual $ fromInterval i++instance IsInterval Float where+    fromInterval x = realToFrac (fromInterval x :: Double)++instance HasResolution a => IsInterval (Fixed a) where+    fromInterval x = realToFrac (fromInterval x :: Double)++instance Integral a => IsInterval (Ratio a) where+    fromInterval x = realToFrac (fromInterval x :: Double)+-}
src/Music/Pitch/Scale.hs view
@@ -1,188 +1,310 @@ -{-# LANGUAGE DeriveDataTypeable         #-}-{-# LANGUAGE DeriveFoldable             #-}-{-# LANGUAGE DeriveFunctor              #-}-{-# LANGUAGE DeriveTraversable          #-}-{-# LANGUAGE GeneralizedNewtypeDeriving #-}-{-# LANGUAGE MultiParamTypeClasses      #-}-{-# LANGUAGE TypeFamilies               #-}+-- | Scales and chords.+module Music.Pitch.Scale+(+        -- * Modes and scales+        Mode,+        modeFromSteps,+        modeIntervals,+        modeRepeat,+        Scale,+        scaleTonic,+        scaleMode,+        leadingInterval,           +        invertMode,                +        modeToScale,+        scaleToList, ---------------------------------------------------------------------------------------- |--- Copyright   : (c) Hans Hoglund, Edward Lilley 2012–2014------ License     : BSD-style------ Maintainer  : hans@hanshoglund.se--- Stability   : experimental--- Portability : non-portable (TF,GNTD)-----------------------------------------------------------------------------------------+        -- * Chord types and chords+        Function,+        functionFromSteps,+        functionIntervals,+        functionRepeat,+        Chord,+        chordTonic,+        chordFunction,+        complementInterval,        +        invertChord,               +        functionToChord,           +        chordToList,                -module Music.Pitch.Scale (-  Mode,-  Scale,-  majorScale,-  pureMinorScale,-  harmonicMinorScale,-  melodicMinorScale,-  aeolian,-  locrian,-  ionian,-  dorian,-  phrygian,-  lydian,-  mixolydian,-  majorPentaTonic,-  minorPentaTonic,-  bluesScale,-  bebopScale,-  wholeTone,-  octatonic,-  firstMode,-  secondMode,-  thirdMode,-  fourthMode,-  fifthMode,-  sixthMode,-  seventhMode,+        -- * Common modes+        -- ** Classical modes+        majorScale,+        pureMinorScale,+        harmonicMinorScale,+        melodicMinorScaleUp,+        -- ** Church modes+        aeolian,+        locrian,+        ionian,+        dorian,+        phrygian,+        lydian,+        mixolydian,+        majorPentaTonic,+        minorPentaTonic,+        bluesMinor,+        bluesMajor,+        bebopScale,+        +        -- ** Miscellaneous modes+        wholeTone,+        octatonic,+        +        -- ** Modes of limited transposition+        firstMode,+        secondMode,+        thirdMode,+        fourthMode,+        fifthMode,+        sixthMode,+        seventhMode, -  Function,-  _intervals,-  _repeat,-  Chord,-  _tonic,-  -  majorTriad,-  minorTriad,-  augmentedChord,-  diminishedChord,-  halfDiminishedChord,-  majorSeventhChord,+        -- * Common chords+        majorTriad,+        minorTriad,+        augmentedChord,+        diminishedChord,+        halfDiminishedChord,+        majorMinorSeventhChord,+        majorMajorSeventhChord,   -  ) where+) where  import Data.VectorSpace import Data.AffineSpace import Music.Pitch.Literal import Control.Lens-import Music.Pitch hiding (Mode) -- Test+import Music.Pitch.Literal+import Music.Pitch.Common hiding (Mode) ++-- | A mode is a list of intervals and a characteristic repeating interval.  data Mode a = Mode [Diff a] (Diff a) -- intervals, repeat (usually octave)-data Scale a = Scale a (Mode a) -- root, mode +-- |+-- > [Interval] -> Interval -> Mode Pitch+modeFromSteps :: [Diff a] -> Diff a -> Mode a+modeFromSteps = Mode++-- |+-- > Lens' (Mode Pitch) [Interval]+modeIntervals :: Lens' (Mode a) [Diff a]+modeIntervals f (Mode is r) = fmap (\is -> Mode is r) $ f is++-- |+-- > Lens' (Mode Pitch) Interval+modeRepeat :: Lens' (Mode a) (Diff a)+modeRepeat f (Mode is r) = fmap (\r -> Mode is r) $ f r++-- | A scale is a mode with a specified tonic.+data Scale a = Scale a (Mode a)      -- root, mode++modeToScale :: AffineSpace a => a -> Mode a -> Scale a+modeToScale = Scale++-- |+-- > Lens' (Scale Pitch) Pitch+scaleTonic :: Lens' (Scale a) a+scaleTonic f (Scale t xs) = fmap (\t -> Scale t xs) $ f t++-- |+-- > Lens' (Scale Pitch) (Mode Pitch)+scaleMode :: Lens' (Scale a) (Mode a)+scaleMode f (Scale t xs) = fmap (\xs -> Scale t xs) $ f xs++-- |+--+-- >>> leadingInterval majorScale +-- m2+-- >>> leadingInterval harmonicMinorScale +-- m2+-- >>> leadingInterval pureMinorScale +-- _M2+--+leadingInterval :: AffineSpace a => Mode a -> Diff a+leadingInterval (Mode steps repeating) = repeating ^-^ sumV steps++invertMode :: AffineSpace a => Int -> Mode a -> Mode a+invertMode 0 = id+invertMode n = invertMode (n-1) . invertMode1+  where+    invertMode1 :: AffineSpace a => Mode a -> Mode a+    invertMode1 mode@(Mode steps repeating) = Mode (tail steps ++ [leadingInterval mode]) repeating++scaleToList :: AffineSpace a => Scale a -> [a]+scaleToList (Scale tonic mode@(Mode steps repeating)) = offsetPoints tonic steps+  where+    -- TODO consolidate+    offsetPoints :: AffineSpace p => p -> [Diff p] -> [p]+    offsetPoints = scanl (.+^)++++ data Function a = Function [Diff a] (Diff a) -- intervals, repeat, repeat (usually octave)-data Chord a = Chord a (Function a) -- root, function  -_intervals :: Lens' (Function a) [Diff a]-_intervals f (Function is r) = fmap (\is -> Function is r) $ f is+-- |+-- > [Interval] -> Interval -> Function Pitch+functionFromSteps :: [Diff a] -> Diff a -> Function a+functionFromSteps = Function -_repeat :: Lens' (Function a) (Diff a)-_repeat f (Function is r) = fmap (\r -> Function is r) $ f r+-- |+-- > Lens' (Function Pitch) [Interval]+functionIntervals :: Lens' (Function a) [Diff a]+functionIntervals f (Function is r) = fmap (\is -> Function is r) $ f is -{--_pitches :: Lens' (Chord a) [a]-_pitches f (Chord t xs) = fmap (\xs -> Chord t (fmap (.-. t) xs)) $ f (fmap (.+^ t) $ xs) . _intervals--}+-- |+-- > Lens' (Function Pitch) Interval+functionRepeat :: Lens' (Function a) (Diff a)+functionRepeat f (Function is r) = fmap (\r -> Function is r) $ f r -_tonic :: Lens' (Chord a) a-_tonic f (Chord t xs) = fmap (\t -> Chord t xs) $ f t+data Chord a = Chord a (Function a)          -- root, function +functionToChord :: AffineSpace a => a -> Function a -> Chord a+functionToChord = Chord++-- |+-- > Lens' (Chord Pitch) Pitch+chordTonic :: Lens' (Chord a) a+chordTonic f (Chord t xs) = fmap (\t -> Chord t xs) $ f t++-- |+-- > Lens' (Chord Pitch) (Function Pitch)+chordFunction :: Lens' (Chord a) (Function a)+chordFunction f (Chord t xs) = fmap (\xs -> Chord t xs) $ f xs++-- |+--+-- >>> complementInterval majorTriad+-- _P4+-- >>> complementInterval minorTriad+-- _P4+-- >>> complementInterval majorMinorSeventhChord+-- _M2+--+-- > Lens' (Function Pitch) Interval+complementInterval :: AffineSpace a => Function a -> Diff a+complementInterval (Function leaps repeating) = repeating ^-^ sumV leaps++invertChord :: AffineSpace a => Int -> Function a -> Function a+invertChord 0 = id+invertChord n = invertChord (n-1) . invertChord1+  where+    invertChord1 :: AffineSpace a => Function a -> Function a+    invertChord1 function@(Function leaps repeating) = Function (tail leaps ++ [complementInterval function]) repeating++-- | Returns a single inversion of the given chord (no repeats!).+chordToList :: AffineSpace a => Chord a -> [a]+chordToList (Chord tonic mode@(Function leaps repeating)) = offsetPoints tonic leaps+-- TODO inversion?+  where+    -- TODO consolidate+    offsetPoints :: AffineSpace p => p -> [Diff p] -> [p]+    offsetPoints = scanl (.+^)+++++-- Common scales+ majorScale :: Mode Pitch-majorScale = Mode [_M2,_M2] _P8+majorScale = modeFromSteps [_M2,_M2,m2,_M2,_M2,_M2] _P8  pureMinorScale :: Mode Pitch-pureMinorScale = undefined+pureMinorScale = modeFromSteps [_M2,m2,_M2,_M2,m2,_M2] _P8  harmonicMinorScale :: Mode Pitch-harmonicMinorScale = undefined--melodicMinorScale :: Mode Pitch-melodicMinorScale = undefined--aeolian :: Mode Pitch-aeolian = Mode [_M2,_M2,m2,_M2,_M2,m2,_M2] _P8+harmonicMinorScale = modeFromSteps [_M2,m2,_M2,_M2,m2,_A2] _P8 -locrian :: Mode Pitch-locrian = undefined+melodicMinorScaleUp :: Mode Pitch+melodicMinorScaleUp = modeFromSteps [_M2,m2,_M2,_M2,_M2,_M2] _P8  ionian :: Mode Pitch-ionian = undefined+ionian = invertMode 0 majorScale  dorian :: Mode Pitch-dorian = undefined+dorian = invertMode 1 majorScale  phrygian :: Mode Pitch-phrygian = undefined+phrygian = invertMode 2 majorScale  lydian :: Mode Pitch-lydian = undefined+lydian = invertMode 3 majorScale  mixolydian :: Mode Pitch-mixolydian = undefined+mixolydian = invertMode 4 majorScale +aeolian :: Mode Pitch+aeolian = invertMode 5 majorScale++locrian :: Mode Pitch+locrian = invertMode 6 majorScale+ majorPentaTonic :: Mode Pitch-majorPentaTonic = undefined+majorPentaTonic = modeFromSteps [_M2,_M2,m3,_M2] _P8 -minorPentaTonic :: Mode Pitch-minorPentaTonic = undefined+bluesMinor :: Mode Pitch+bluesMinor = invertMode 2 majorPentaTonic -bluesScale :: Mode Pitch-bluesScale = undefined+bluesMajor :: Mode Pitch+bluesMajor = invertMode 3 majorPentaTonic +minorPentaTonic :: Mode Pitch+minorPentaTonic = invertMode 4 majorPentaTonic+ bebopScale :: Mode Pitch-bebopScale = undefined+bebopScale = modeFromSteps [_M2,_M2,m2,_M2,m2,m2,_M2] _P8  wholeTone :: Mode Pitch-wholeTone = undefined+wholeTone = firstMode  octatonic :: Mode Pitch-octatonic = undefined+octatonic = secondMode  firstMode :: Mode Pitch-firstMode = undefined+firstMode = modeFromSteps [_M2,_M2,_M2,_M2,_M2] _P8  secondMode :: Mode Pitch-secondMode = undefined+secondMode = modeFromSteps [m2,_M2,_A1,_M2,m2,_M2,m2] _P8  thirdMode :: Mode Pitch-thirdMode = undefined+thirdMode = modeFromSteps [_M2,m2,m2,_M2,m2,m2,_M2,m2] _P8  fourthMode :: Mode Pitch-fourthMode = undefined+fourthMode = modeFromSteps [m2,m2,m3,m2,m2,m2,m3] _P8  fifthMode :: Mode Pitch-fifthMode = undefined+fifthMode = modeFromSteps [m2,_M3,m2,m2,_M3] _P8  sixthMode :: Mode Pitch-sixthMode = undefined+sixthMode = modeFromSteps [_M2,_M2,m2,m2,_M2,_M2,m2] _P8  seventhMode :: Mode Pitch-seventhMode = undefined--+seventhMode = modeFromSteps [m2,m2,m2,_M2,m2,m2,m2,m2,_M2] _P8 +-- Common chords  majorTriad :: Function Pitch-majorTriad = undefined+majorTriad = Function [_M3,m3] _P8  minorTriad :: Function Pitch-minorTriad = undefined+minorTriad = Function [m3,_M3] _P8  augmentedChord :: Function Pitch-augmentedChord = undefined+augmentedChord = Function [_M3,_M3] _P8  diminishedChord :: Function Pitch-diminishedChord = undefined+diminishedChord = Function [m3,m3,_A2] _P8  halfDiminishedChord :: Function Pitch-halfDiminishedChord = undefined--majorSeventhChord :: Function Pitch-majorSeventhChord = undefined--+halfDiminishedChord = Function [m3,m3,_M3] _P8 +majorMinorSeventhChord :: Function Pitch+majorMinorSeventhChord = Function [_M3,m3,m3] _P8 +majorMajorSeventhChord :: Function Pitch+majorMajorSeventhChord = Function [_M3,m3,_M3] _P8  
− src/Music/Pitch/StaffLines.hs
@@ -1,79 +0,0 @@--{-# LANGUAGE ConstraintKinds            #-}-{-# LANGUAGE DeriveDataTypeable         #-}-{-# LANGUAGE DeriveFoldable             #-}-{-# LANGUAGE DeriveFunctor              #-}-{-# LANGUAGE DeriveTraversable          #-}-{-# LANGUAGE FlexibleContexts           #-}-{-# LANGUAGE FlexibleInstances          #-}-{-# LANGUAGE GADTs                      #-}-{-# LANGUAGE GeneralizedNewtypeDeriving #-}-{-# LANGUAGE MultiParamTypeClasses      #-}-{-# 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,-  ) where--import Numeric.Natural-import Data.Typeable---- TODO maybe parameterize stafflines on number of staves---- |--- For notation systems using staff lines (i.e. CMN), this type represents staff number.------ Rules:------ * Incrementing staff lines means moving upward.-------- * For staff systems with an odd number of lines, 0 is the middle staff.------ * For staff systems with an even number of lines, 0 is the staff below the middle space.------ I.e. in CMN the staff lines are @[-2..2]@, with negative numbers representing the lines--- below the middle line and positions numbers representing the lines above it.----newtype StaffLines = StaffLines { getStaffLines :: Integer }-  deriving (Eq, Ord, Read, Show, Enum,-           Num, Real, Integral, Typeable)---- |--- For notation systems using staff lines, this type represents the difference betwee two--- staff positions (i.e. one diatonic step in CMN).------ Rules:------ * Incrementing half spaces means moving upward.------ * For staff systems with an odd number of lines, 0 is the middle staff.------ * For staff systems with an even number of lines, 0 is the middle space.------ I.e. in CMN, the non-ledger positions are @[-5..5]@ with the even numbers representing--- lines and the odd representing spaces and with positive numbers representing positions--- above the middle line and negative numbers representing positions below.----newtype HalfSpaces = HalfSpaces { getHalfSpaces :: Integer }-  deriving (Eq, Ord, Read, Show, Enum,-           Num, Real, Integral, Typeable)----- staffLinesForNumber :: Int -> StaffLines--- staffLinesForNumber