packages feed

music-parts 1.7.1 → 1.7.2

raw patch · 8 files changed

+697/−194 lines, 8 filesdep +music-pitchdep −randomdep −timedep ~lensPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

Dependencies added: music-pitch

Dependencies removed: random, time

Dependency ranges changed: lens

API changes (from Hackage documentation)

- Music.Parts: OtherInstrument :: String -> Instrument
- Music.Parts: Solo :: Solo
- Music.Parts: StdInstrument :: Int -> Instrument
- Music.Parts: Tutti :: Solo
- Music.Parts: containsSubpart :: Subpart -> Subpart -> Bool
- Music.Parts: data BasicPart
- Music.Parts: data Division
- Music.Parts: data Instrument
- Music.Parts: data Solo
- Music.Parts: data Subpart
- Music.Parts: divisions :: Int -> [Division]
- Music.Parts: getDivision :: Division -> (Int, Int)
- Music.Parts: instance Default BasicPart
- Music.Parts: instance Default Division
- Music.Parts: instance Default Instrument
- Music.Parts: instance Default Solo
- Music.Parts: instance Default Subpart
- Music.Parts: instance Enum BasicPart
- Music.Parts: instance Enum Instrument
- Music.Parts: instance Enum Solo
- Music.Parts: instance Enum a => Enum (Option a)
- Music.Parts: instance Eq BasicPart
- Music.Parts: instance Eq Division
- Music.Parts: instance Eq Instrument
- Music.Parts: instance Eq Solo
- Music.Parts: instance Eq Subpart
- Music.Parts: instance Integral BasicPart
- Music.Parts: instance Integral a => Integral (First a)
- Music.Parts: instance Integral a => Integral (Option a)
- Music.Parts: instance Monoid BasicPart
- Music.Parts: instance Monoid Subpart
- Music.Parts: instance Num BasicPart
- Music.Parts: instance Num a => Num (First a)
- Music.Parts: instance Num a => Num (Option a)
- Music.Parts: instance Ord BasicPart
- Music.Parts: instance Ord Division
- Music.Parts: instance Ord Instrument
- Music.Parts: instance Ord Solo
- Music.Parts: instance Ord Subpart
- Music.Parts: instance Real BasicPart
- Music.Parts: instance Real a => Real (First a)
- Music.Parts: instance Real a => Real (Option a)
- Music.Parts: instance Semigroup BasicPart
- Music.Parts: instance Semigroup Subpart
- Music.Parts: instance Show BasicPart
- Music.Parts: instance Show Division
- Music.Parts: instance Show Instrument
- Music.Parts: instance Show Solo
- Music.Parts: instance Show Subpart
- Music.Parts: instance Typeable BasicPart
+ Data.Semigroup.Option.Instances: instance Enum a => Enum (Option a)
+ Data.Semigroup.Option.Instances: instance Integral a => Integral (First a)
+ Data.Semigroup.Option.Instances: instance Integral a => Integral (Option a)
+ Data.Semigroup.Option.Instances: instance Num a => Num (First a)
+ Data.Semigroup.Option.Instances: instance Num a => Num (Option a)
+ Data.Semigroup.Option.Instances: instance Real a => Real (First a)
+ Data.Semigroup.Option.Instances: instance Real a => Real (Option a)
+ Music.Parts.Basic: data BasicPart
+ Music.Parts.Basic: instance Default BasicPart
+ Music.Parts.Basic: instance Enum BasicPart
+ Music.Parts.Basic: instance Eq BasicPart
+ Music.Parts.Basic: instance Integral BasicPart
+ Music.Parts.Basic: instance Monoid BasicPart
+ Music.Parts.Basic: instance Num BasicPart
+ Music.Parts.Basic: instance Ord BasicPart
+ Music.Parts.Basic: instance Real BasicPart
+ Music.Parts.Basic: instance Semigroup BasicPart
+ Music.Parts.Basic: instance Show BasicPart
+ Music.Parts.Basic: instance Typeable BasicPart
+ Music.Parts.Division: data Division
+ Music.Parts.Division: divisions :: Int -> [Division]
+ Music.Parts.Division: getDivision :: Division -> (Int, Int)
+ Music.Parts.Division: instance Default Division
+ Music.Parts.Division: instance Eq Division
+ Music.Parts.Division: instance Ord Division
+ Music.Parts.Division: instance Show Division
+ Music.Parts.Division: showDivision :: Division -> String
+ Music.Parts.Division: showDivisionR :: Division -> String
+ Music.Parts.Instrument: OtherInstrument :: String -> Instrument
+ Music.Parts.Instrument: StdInstrument :: Int -> Instrument
+ Music.Parts.Instrument: data Instrument
+ Music.Parts.Instrument: instance Default Instrument
+ Music.Parts.Instrument: instance Enum Instrument
+ Music.Parts.Instrument: instance Eq Instrument
+ Music.Parts.Instrument: instance Ord Instrument
+ Music.Parts.Instrument: instance Show Instrument
+ Music.Parts.Solo: Solo :: Solo
+ Music.Parts.Solo: Tutti :: Solo
+ Music.Parts.Solo: data Solo
+ Music.Parts.Solo: instance Default Solo
+ Music.Parts.Solo: instance Enum Solo
+ Music.Parts.Solo: instance Eq Solo
+ Music.Parts.Solo: instance Ord Solo
+ Music.Parts.Solo: instance Show Solo
+ Music.Parts.Subpart: Subpart :: [Division] -> Subpart
+ Music.Parts.Subpart: containsSubpart :: Subpart -> Subpart -> Bool
+ Music.Parts.Subpart: instance Default Subpart
+ Music.Parts.Subpart: instance Eq Subpart
+ Music.Parts.Subpart: instance Monoid Subpart
+ Music.Parts.Subpart: instance Ord Subpart
+ Music.Parts.Subpart: instance Semigroup Subpart
+ Music.Parts.Subpart: instance Show Subpart
+ Music.Parts.Subpart: newtype Subpart

Files

music-parts.cabal view
@@ -1,11 +1,11 @@  name:                   music-parts-version:                1.7.1+version:                1.7.2 author:                 Hans Hoglund maintainer:             Hans Hoglund license:                BSD3 license-file:           COPYING-synopsis:               To be written.+synopsis:               Musical instruments, parts and playing techniques. category:               Music tested-with:            GHC build-type:             Simple@@ -23,20 +23,51 @@ library                         build-depends:      base                    >= 4 &&   < 5,                         aeson                   >= 0.7.0.6 && < 1,-                        lens				            >= 4.3 && < 4.4,+                        lens				            >= 4.3.3 && < 4.4,                         semigroups              >= 0.13.0.1 && < 1,-                        time,-                        random,                         semigroupoids,                         data-default,                         adjunctions             >= 4.1 && < 5,-                        roman-numerals-    exposed-modules:    Music.Parts+                        roman-numerals,+                        music-pitch             == 1.7.2+    exposed-modules:    Data.Semigroup.Option.Instances+                        +                        Music.Parts+                        +                        Music.Parts.Basic+                        +                        -- -- TODO choral voicings etc+                        -- -- TODO use single type or many? How to do "subtyping"+                        -- -- Prisms, TFs, something else?+                        -- +                        -- -- TODO require pitch dep+                        -- Music.Parts.Range++                        Music.Parts.Division+                        Music.Parts.Subpart+                        Music.Parts.Solo+                        +                        -- TODO "ensembles", essentially echoing the instrument hierarchy but in plural, i.e. (flute :: Instrument, flutes :: Part)+                        -- TODO write something nice about how division works, why we don't usually export flute1 etc.                         -- Music.Parts.Strings                         -- Music.Parts.Woodwind                         -- Music.Parts.Brass                         -- Music.Parts.Percussion                         -- Music.Parts.Rhythm                         -- Music.Parts.Other+                        +                        Music.Parts.Instrument+                        -- Music.Parts.Instrument.Strings+                        -- Music.Parts.Instrument.Woodwind+                        -- Music.Parts.Instrument.Brass+                        -- Music.Parts.Instrument.Percussion+                        -- Music.Parts.Instrument.Rhythm+                        -- Music.Parts.Instrument.Other+                        +                        -- TODO a way to classify parts+                        -- so we know what goes on which staff, what kind of bracket to generate etc+                        +                        -- TODO some sub-subdivision (not for player allocation, but hand/finger)+                             hs-source-dirs:     src     default-language:   Haskell2010
+ src/Data/Semigroup/Option/Instances.hs view
@@ -0,0 +1,49 @@++module Data.Semigroup.Option.Instances where++import           Control.Applicative+import           Control.Lens            (toListOf)+import           Data.Default+import           Data.Functor.Adjunction (unzipR)+import qualified Data.List+import           Data.Maybe+import           Data.Semigroup+import           Data.Traversable        (traverse)+import           Data.Typeable+import           Text.Numeral.Roman      (toRoman)++-- TODO move++instance Num a => Num (Option a) where+  (+)       = liftA2 (+)+  (-)       = liftA2 (-)+  (*)       = liftA2 (*)+  abs       = fmap abs+  signum    = fmap signum+  fromInteger = pure . fromInteger+instance Integral a => Integral (Option a) where+  quotRem x y = unzipR $ liftA2 quotRem x y+  toInteger = toInteger . get where get = (head.toListOf traverse)+instance Real a => Real (Option a) where+  toRational = toRational . get where get = (head.toListOf traverse)+instance Enum a => Enum (Option a) where+  fromEnum = fromEnum . get where get = (head.toListOf traverse)+  toEnum = pure . toEnum++-- TODO move++instance Num a => Num (First a) where+  (+)       = liftA2 (+)+  (-)       = liftA2 (-)+  (*)       = liftA2 (*)+  abs       = fmap abs+  signum    = fmap signum+  fromInteger = pure . fromInteger+instance Integral a => Integral (First a) where+  quotRem x y = unzipR $ liftA2 quotRem x y+  toInteger = toInteger . get where get = (head.toListOf traverse)+instance Real a => Real (First a) where+  toRational = toRational . get where get = (head.toListOf traverse)+-- instance Enum a => Enum (First a) where+  -- toEnum = toEnum . get where get = (head.toListOf traverse)+  -- fromEnum = pure . fromEnum
src/Music/Parts.hs view
@@ -1,12 +1,11 @@ -{-# LANGUAGE-    GeneralizedNewtypeDeriving,-    DeriveDataTypeable,-    TypeFamilies #-}+{-# LANGUAGE DeriveDataTypeable         #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE TypeFamilies               #-}  ------------------------------------------------------------------------------------ -- |--- Copyright   : (c) Hans Hoglund 2012+-- Copyright   : (c) Hans Hoglund 2012-2015 -- -- License     : BSD-style --@@ -14,7 +13,7 @@ -- Stability   : experimental -- Portability : non-portable (TF,GNTD) ----- Part representation.+-- Provides various representaitons of musical instruments, subdivisions and parts. -- ------------------------------------------------------------------------------------- @@ -22,36 +21,34 @@         -- * Terminology         -- $terminology -        +         -- * Subparts-        Division,-        divisions,-        getDivision,-        Subpart,+        module Music.Parts.Division,+        module Music.Parts.Subpart, +        -- * Solo vs. tutti+        module Music.Parts.Solo,+                 -- * Instruments-        Instrument(..),-        -- TODO hide impl+        module Music.Parts.Instrument,          -- * Parts-        Solo(..),         Part(..),         divide,         containsPart,-        containsSubpart,         solo,         tutti,-        +         -- ** Instruments etc         piccoloFlute,         flute,         altoFlute,         bassFlute,-        +         oboe,         corAnglais,         heckelphone,-        +         ebClarinet,         clarinet,         aClarinet,@@ -61,10 +58,10 @@         altoSax,         tenorSax,         baritoneSax,-        +         bassoon,         contraBassoon,-        +         horn,         piccoloTrumpet,         trumpet,@@ -74,10 +71,10 @@         trombone,         bassTrombone,         tuba,-        +         timpani,         piano,-        +         celesta,         glockenspiel,         vibraphone,@@ -86,10 +83,10 @@         xylorimba,         tubularBells,         dulcimer,-        +         accordion,         harmonica,-        +         violin,         viola,         cello,@@ -116,7 +113,7 @@         trombones,         trumpets1,         trumpets2,-        trombones1, +        trombones1,         trombones2,         tubas, @@ -137,22 +134,28 @@           -- * Basic-        -- TODO move-        BasicPart,+        module Music.Parts.Basic    ) where -import Data.Default-import Data.Semigroup-import Data.Typeable-import Data.Maybe-import Data.Traversable (traverse)-import Control.Lens (toListOf)-import Data.Functor.Adjunction (unzipR)-import Control.Applicative-import Text.Numeral.Roman (toRoman)+import           Control.Applicative+import           Control.Lens                    (toListOf)+import           Data.Default+import           Data.Functor.Adjunction         (unzipR) import qualified Data.List+import           Data.Maybe+import           Data.Semigroup+import           Data.Semigroup.Option.Instances+import           Data.Traversable                (traverse)+import           Data.Typeable+import           Text.Numeral.Roman              (toRoman) +import           Music.Parts.Basic+import           Music.Parts.Subpart+import           Music.Parts.Division+import           Music.Parts.Solo+import           Music.Parts.Instrument+ {- $terminology  Parts represent a subset of a group of performers. It is mainly used for instrumental and@@ -170,92 +173,11 @@     separately, so i.e. /Violin solo II/ (as in a double concerto) is distinct from /Violin II/.  -}-      -{--    For each part we want to know:-        - Classification:-            - Type: (i.e. woodwind)-            - Family: (i.e. saxophone)-            - Range: (i.e. tenor)            -        - Range (i.e. [c_:e'])-        - Transposition:-            sounding = written .+^ transp -        - Suggested clefs--} --- |--- A division represents a subset of a finite group of performers.------ For example a group may be divided into three equal divisions,--- designated @(0, 3)@, @(1, 3)@ and @(2, 3)@ respectively.----newtype Division = Division { getDivision :: (Int, Int) }-    deriving (Eq, Ord, Show)-instance Default Division where-    def = Division (0,1) -showDivisionR :: Division -> String-showDivisionR = toRoman . succ . fst . getDivision -showDivision :: Division -> String-showDivision  = show . succ . fst . getDivision---- | Get all possible divisions for a given divisor in ascending order.-divisions :: Int -> [Division]-divisions n = [Division (x,n) | x <- [0..n-1]]---- | Divide a part into @n@ subparts.-divide :: Int -> Part -> [Part]-divide n (Part solo instr subp) = fmap (\x -> Part solo instr (subp <> Subpart [x])) $ divisions n---- |--- A subpart is a potentially infinite sequence of divisions, each typically--- designated using a new index type, i.e. @I.1.2@.------ The empty subpart (also known as 'def') represents all the players of the group,--- or in the context of 'Part', all players of the given instrument.--- -newtype Subpart = Subpart [Division]-    deriving (Eq, Ord, Default, Semigroup, Monoid)--instance Show Subpart where-    show (Subpart ps) = Data.List.intercalate "." $ mapFR showDivisionR showDivision $ ps-        where-            mapFR f g []     = []-            mapFR f g (x:xs) = f x : fmap g xs---- | An 'Instrument' represents the set of all instruments of a given type.-data Instrument -    = StdInstrument Int-    | OtherInstrument String-    deriving (Eq)--instance Show Instrument where      -    show (StdInstrument x) = fromMaybe "(unknown)" $ gmInstrName x-    show (OtherInstrument str) = str-instance Enum Instrument where-    toEnum = StdInstrument-    fromEnum (StdInstrument x) = x-    fromEnum (OtherInstrument _) = error "Instrument.fromEnum used on unknown instrument"--instance Ord Instrument where-    StdInstrument x `compare` StdInstrument y = gmScoreOrder x `compare` gmScoreOrder y---- | This instance is quite arbitrary but very handy.-instance Default Instrument where-    def = StdInstrument 0--data Solo-    = Solo-    | Tutti-    deriving (Eq, Show, Ord, Enum)--instance Default Solo where-    def = Tutti -- -- | A part is a subdivided group of instruments of a given type. -- data Part = Part Solo Instrument Subpart@@ -285,17 +207,18 @@ instance Default Part where   def = Part def def def --- | --- @a \`containsPart\` b@ holds if the set of players represented by a is an improper subset of the +-- |+-- @a \`containsPart\` b@ holds if the set of players represented by a is an improper subset of the -- set of players represented by b. containsPart :: Part -> Part -> Bool-Part solo1 instr1 subp1 `containsPart` Part solo2 instr2 subp2 = -        solo1 == solo2 +Part solo1 instr1 subp1 `containsPart` Part solo2 instr2 subp2 =+        solo1 == solo2         && instr1 == instr2         && subp1 `containsSubpart` subp2 -containsSubpart :: Subpart -> Subpart -> Bool-Subpart x `containsSubpart` Subpart y = y `Data.List.isPrefixOf` x+-- | Divide a part into @n@ subparts.+divide :: Int -> Part -> [Part]+divide n (Part solo instr subp) = fmap (\x -> Part solo instr (subp <> Subpart [x])) $ divisions n  solo instr      = Part Solo instr def tutti instr     = Part Tutti instr def@@ -398,8 +321,8 @@ {-     Score order:         Woodwinds:      1-        Brass:          2 -        Timpani:        3 +        Brass:          2+        Timpani:        3         Percussion:     4         Keyboard/Harp   5         Singers         6@@ -408,7 +331,8 @@ -} gmInstrs :: [(Int, (Int, Double, Int, String))] gmInstrs = [-    (0, (0,  5.0, 0,  "Acoustic Grand Piano")),+    -- (0, (0,  5.0, 0,  "Acoustic Grand Piano")),+    (0, (0,  5.0, 0,  "Piano")),     (1, (0,  5.0, 0,  "Bright Acoustic Piano")),     (2, (0,  5.0, 0,  "Electric Grand Piano")),     (3, (0,  5.0, 0,  "Honky-tonk Piano")),@@ -612,7 +536,7 @@   --- +-- -- data Section --     = Woodwind --     | Brass@@ -620,16 +544,16 @@ --     | Keyboard --     | Voices --     | Strings--- +-- -- data VoicePart --     = Soprano --     | MezzoSoprano---     | Alto+--     | Alto --     | Tenor --     | Baritone --     | Bass--- --- +--+-- -- data GMInstrumentType --     = GMPiano --     | GMChromaticPercussion@@ -644,22 +568,22 @@ --     | GMSynthLead --     | GMSynthPad --     | GMSynthEffects---     | GMEthnic+--     | GMEthnic --     | GMPercussive---     | GMSoundEffects   +--     | GMSoundEffects  -    + {-     ## Terminology: Voice vs Part-    +     A voice is a container of notes (non-overlapping)-    +     A part is an identifier for a set of singers/musicians AND all the notes in a score     designated for this set of performers. Part extraction has the type-    +         extractParts :: HasPart a => Score a -> [Score a]-    +     I.e. in a score for piano and ensemble, certain notes may be *in the piano part*, i.e.     designated for the piano. Typically, a part is monophonic or polyphonic. A monophonic     part is a voice, i.e.@@ -669,10 +593,10 @@          -- | Fails for polyphonic scores.         scoreToVoice :: Score a -> Voice (Maybe a)-    +     A polyphonic score contains several voices, i.e. -        scoreToVoices :: Score a -> [Voice (Maybe a)]  +        scoreToVoices :: Score a -> [Voice (Maybe a)]       A part is any type a that satisfies (Ord a, Show a).@@ -681,8 +605,8 @@         class HasPartName a where             partName :: a -> String             partAbbr :: a -> String-    -    ++     These contraints are used when printing scores (to get the order of the parts and their name).          Vln1, Vln2 etc.@@ -709,57 +633,48 @@      partGroup :: (Part -> [Group] -> a) -> Group -> a     tree :: (a -> [Tree a] -> b) -> Tree a -> b-    -    ++     data MyPart         = Fl-        | Sop+        | Sop         | Vl1-        | Vl2+        | Vl2         | Pno  -} -- TODO move-instance Num a => Num (Option a) where-  (+)       = liftA2 (+)-  (-)       = liftA2 (-)-  (*)       = liftA2 (*)-  abs       = fmap abs-  signum    = fmap signum-  fromInteger = pure . fromInteger-instance Integral a => Integral (Option a) where-  quotRem x y = unzipR $ liftA2 quotRem x y-  toInteger = toInteger . get where get = (head.toListOf traverse)-instance Real a => Real (Option a) where-  toRational = toRational . get where get = (head.toListOf traverse)-instance Enum a => Enum (Option a) where-  fromEnum = fromEnum . get where get = (head.toListOf traverse)-  toEnum = pure . toEnum--instance Num a => Num (First a) where-  (+)       = liftA2 (+)-  (-)       = liftA2 (-)-  (*)       = liftA2 (*)-  abs       = fmap abs-  signum    = fmap signum-  fromInteger = pure . fromInteger-instance Integral a => Integral (First a) where-  quotRem x y = unzipR $ liftA2 quotRem x y-  toInteger = toInteger . get where get = (head.toListOf traverse)-instance Real a => Real (First a) where-  toRational = toRational . get where get = (head.toListOf traverse)--- instance Enum a => Enum (First a) where-  -- toEnum = toEnum . get where get = (head.toListOf traverse)-  -- fromEnum = pure . fromEnum--newtype BasicPart = BasicPart { getBasicPart :: Option (First Integer) }-    deriving (Eq, Ord, Num, Integral, Real, Enum, Typeable, Semigroup, Monoid)--instance Default BasicPart where-  def = mempty--instance Show BasicPart where-    show _ = ""+-- instance Num a => Num (Option a) where+--   (+)       = liftA2 (+)+--   (-)       = liftA2 (-)+--   (*)       = liftA2 (*)+--   abs       = fmap abs+--   signum    = fmap signum+--   fromInteger = pure . fromInteger+-- instance Integral a => Integral (Option a) where+--   quotRem x y = unzipR $ liftA2 quotRem x y+--   toInteger = toInteger . get where get = (head.toListOf traverse)+-- instance Real a => Real (Option a) where+--   toRational = toRational . get where get = (head.toListOf traverse)+-- instance Enum a => Enum (Option a) where+--   fromEnum = fromEnum . get where get = (head.toListOf traverse)+--   toEnum = pure . toEnum+--+-- instance Num a => Num (First a) where+--   (+)       = liftA2 (+)+--   (-)       = liftA2 (-)+--   (*)       = liftA2 (*)+--   abs       = fmap abs+--   signum    = fmap signum+--   fromInteger = pure . fromInteger+-- instance Integral a => Integral (First a) where+--   quotRem x y = unzipR $ liftA2 quotRem x y+--   toInteger = toInteger . get where get = (head.toListOf traverse)+-- instance Real a => Real (First a) where+--   toRational = toRational . get where get = (head.toListOf traverse)+-- -- instance Enum a => Enum (First a) where+--   -- toEnum = toEnum . get where get = (head.toListOf traverse)+--   -- fromEnum = pure . fromEnum   piccoloFlutes = tutti piccoloFlute@@ -1680,4 +1595,4 @@   <sound id="wood.tonetang"/>   <sound id="wood.wood-block"/> -}- +
+ src/Music/Parts/Basic.hs view
@@ -0,0 +1,44 @@++{-# LANGUAGE DeriveDataTypeable         #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE TypeFamilies               #-}++------------------------------------------------------------------------------------+-- |+-- Copyright   : (c) Hans Hoglund 2012-2015+--+-- License     : BSD-style+--+-- Maintainer  : hans@hanshoglund.se+-- Stability   : experimental+-- Portability : non-portable (TF,GNTD)+--+-- Provides various representaitons of musical instruments, subdivisions and parts.+--+-------------------------------------------------------------------------------------++module Music.Parts.Basic (+        BasicPart+  ) where++import           Control.Applicative+import           Control.Lens            (toListOf)+import           Data.Default+import           Data.Functor.Adjunction (unzipR)+import qualified Data.List+import           Data.Maybe+import           Data.Semigroup+import           Data.Traversable        (traverse)+import           Data.Typeable+import           Text.Numeral.Roman      (toRoman)+import           Data.Semigroup.Option.Instances++newtype BasicPart = BasicPart { getBasicPart :: Option (First Integer) }+    deriving (Eq, Ord, Num, Integral, Real, Enum, Typeable, Semigroup, Monoid)++instance Default BasicPart where+  def = mempty++instance Show BasicPart where+    show _ = ""+
+ src/Music/Parts/Division.hs view
@@ -0,0 +1,75 @@++{-# LANGUAGE DeriveDataTypeable         #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE TypeFamilies               #-}++------------------------------------------------------------------------------------+-- |+-- Copyright   : (c) Hans Hoglund 2012-2015+--+-- License     : BSD-style+--+-- Maintainer  : hans@hanshoglund.se+-- Stability   : experimental+-- Portability : non-portable (TF,GNTD)+--+-------------------------------------------------------------------------------------++module Music.Parts.Division (+        Division,+        divisions,+        getDivision,+        showDivision,+        showDivisionR,+  ) where++import           Control.Applicative+import           Control.Lens                    (toListOf)+import           Data.Default+import           Data.Functor.Adjunction         (unzipR)+import qualified Data.List+import           Data.Maybe+import           Data.Semigroup+import           Data.Semigroup.Option.Instances+import           Data.Traversable                (traverse)+import           Data.Typeable+import           Text.Numeral.Roman              (toRoman)++++{-+    For each part we want to know:+        - Classification:+            - Type: (i.e. woodwind)+            - Family: (i.e. saxophone)+            - Range: (i.e. tenor)+        - Range (i.e. [c_:e'])+        - Transposition:+            sounding = written .+^ transp+        - Suggested clefs+-}++-- |+-- A division represents a subset of a finite group of performers.+--+-- For example a group may be divided into three equal divisions,+-- designated @(0, 3)@, @(1, 3)@ and @(2, 3)@ respectively.+--+newtype Division = Division { getDivision :: (Int, Int) }+    deriving (Eq, Ord, Show)++instance Default Division where+    def = Division (0,1)++-- | Show division in roman numerals.+showDivisionR :: Division -> String+showDivisionR = toRoman . succ . fst . getDivision++-- | Show division in ordinary numerals.+showDivision :: Division -> String+showDivision  = show . succ . fst . getDivision++-- | Get all possible divisions for a given divisor in ascending order.+divisions :: Int -> [Division]+divisions n = [Division (x,n) | x <- [0..n-1]]+
+ src/Music/Parts/Instrument.hs view
@@ -0,0 +1,293 @@++{-# LANGUAGE DeriveDataTypeable         #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE TypeFamilies               #-}++------------------------------------------------------------------------------------+-- |+-- Copyright   : (c) Hans Hoglund 2012-2015+--+-- License     : BSD-style+--+-- Maintainer  : hans@hanshoglund.se+-- Stability   : experimental+-- Portability : non-portable (TF,GNTD)+--+-------------------------------------------------------------------------------------++module Music.Parts.Instrument +(+Instrument(..),+-- TODO hide impl+)+where++import           Control.Applicative+import           Control.Lens                    (toListOf)+import           Data.Default+import           Data.Functor.Adjunction         (unzipR)+import qualified Data.List+import           Data.Maybe+import           Data.Semigroup+import           Data.Semigroup.Option.Instances+import           Data.Traversable                (traverse)+import           Data.Typeable+import           Text.Numeral.Roman              (toRoman)++-- | An 'Instrument' represents the set of all instruments of a given type.+data Instrument+    = StdInstrument Int+    | OtherInstrument String+    deriving (Eq)++instance Show Instrument where+    show (StdInstrument x) = fromMaybe "(unknown)" $ gmInstrName x+    show (OtherInstrument str) = str+instance Enum Instrument where+    toEnum = StdInstrument+    fromEnum (StdInstrument x) = x+    fromEnum (OtherInstrument _) = error "Instrument.fromEnum used on unknown instrument"++instance Ord Instrument where+    StdInstrument x `compare` StdInstrument y = gmScoreOrder x `compare` gmScoreOrder y++-- | This instance is quite arbitrary but very handy.+instance Default Instrument where+    def = StdInstrument 0+++-- TODO consolidate++gmClef :: Int -> Int+gmMidiChannel :: Int -> Int+gmScoreOrder :: Int -> Double++gmMidiChannel = fromMaybe 0 . fmap get . (`lookup` gmInstrs)+    where get (x,_,_,_) = x++gmScoreOrder = fromMaybe 0 . fmap get . (`lookup` gmInstrs)+    where get (_,x,_,_) = x++gmClef = fromMaybe 0 . fmap get . (`lookup` gmInstrs)+    where get (_,_,x,_) = x+++gmInstrName :: Int -> Maybe String+gmInstrName = fmap get . (`lookup` gmInstrs)+    where get (_,_,_,x) = x++-- (midi program, (def midi ch, score order, def clef 0=g/1=c/2=f, name))+{-+    Score order:+        Woodwinds:      1+        Brass:          2+        Timpani:        3+        Percussion:     4+        Keyboard/Harp   5+        Singers         6+        Strings:        7+        Bass:           8+-}+gmInstrs :: [(Int, (Int, Double, Int, String))]+gmInstrs = [+    -- (0, (0,  5.0, 0,  "Acoustic Grand Piano")),+    (0, (0,  5.0, 0,  "Piano")),+    (1, (0,  5.0, 0,  "Bright Acoustic Piano")),+    (2, (0,  5.0, 0,  "Electric Grand Piano")),+    (3, (0,  5.0, 0,  "Honky-tonk Piano")),+    (4, (0,  5.0, 0,  "Electric Piano 1")),+    (5, (0,  5.0, 0,  "Electric Piano 2")),+    (6, (0,  5.0, 0,  "Harpsichord")),+    (7, (0,  5.0, 0,  "Clavinet")),++    (8, (0,  5.0, 0,  "Celesta")),+    (9, (0,  5.0, 0,  "Glockenspiel")),+    (9, (0,  5.0, 0,  "Music Box")),+    (11, (0,  4.0, 0,  "Vibraphone")),+    (12, (0,  4.0, 0,  "Marimba")),+    (13, (0,  4.0, 0,  "Xylophone")),+    (14, (0,  4.0, 0,  "Tubular Bells")),+    (15, (0,  4.0, 0,  "Dulcimer")),++    (16, (0,  5.0, 0,  "Drawbar Organ")),+    (17, (0,  5.0, 0,  "Percussive Organ")),+    (18, (0,  5.0, 0,  "Rock Organ")),+    (19, (0,  5.0, 0,  "Church Organ")),+    (20, (0,  5.0, 0,  "Reed Organ")),+    (21, (0,  5.0, 0,  "Accordion")),+    (22, (0,  5.0, 0,  "Harmonica")),+    (23, (0,  5.0, 0,  "Tango Accordion")),++    (24, (0,  5.0, 0,  "Acoustic Guitar (nylon)")),+    (25, (0,  5.0, 0,  "Acoustic Guitar (steel)")),+    (26, (0,  5.0, 0,  "Electric Guitar (jazz)")),+    (27, (0,  5.0, 0,  "Electric Guitar (clean)")),+    (28, (0,  5.0, 0,  "Electric Guitar (muted)")),+    (29, (0,  5.0, 0,  "Overdriven Guitar")),+    (30, (0,  5.0, 0,  "Distortion Guitar")),+    (31, (0,  5.0, 0,  "Guitar Harmonics")),++    (32, (0,  8.0, 2,  "Acoustic Bass")),+    (33, (0,  8.0, 2,  "Electric Bass (finger)")),+    (34, (0,  8.0, 2,  "Electric Bass (pick)")),+    (35, (0,  8.0, 2,  "Fretless Bass")),+    (36, (0,  8.0, 2,  "Slap Bass 1")),+    (37, (0,  8.0, 2,  "Slap Bass 2")),+    (38, (0,  8.0, 2,  "Synth Bass 1")),+    (39, (0,  8.0, 2,  "Synth Bass 2")),++    (40, (12,  7.1, 0,  "Violin")),+    (41, (13,  7.2, 1,  "Viola")),+    -- (42, (0,  1.0, 0,  "Cello")),+    (42, (14,  7.3, 2,  "Violoncello")),+    (43, (15,  7.4, 2,  "Contrabass")),+    (44, (0,  7.0, 0,  "Tremolo Strings")),+    (45, (0,  7.0, 0,  "Pizzicato Strings")),+    (46, (11,  5.9, 0,  "Orchestral Harp")),++    (47, (8,  2.5, 2,  "Timpani")),++    (48, (0,  7.0, 0,  "String Ensemble 1")),+    (49, (0,  7.0, 0,  "String Ensemble 2")),+    (50, (0,  7.0, 0,  "Synth Strings 1")),+    (51, (0,  7.0, 0,  "Synth Strings 2")),++    (52, (0,  1.0, 0,  "Choir Aahs")),+    (53, (0,  1.0, 0,  "Voice Oohs")),+    (54, (0,  1.0, 0,  "Synth Choir")),+    (55, (0,  1.0, 0,  "Orchestra Hit")),++    (56, (5,  2.2, 0,  "Trumpet in Bb")),+    (57, (6,  2.3, 2,  "Trombone")),+    (58, (7,  2.4, 2,  "Tuba")),+    (59, (0,  2.2, 0,  "Muted Trumpet")),+    -- (60, (4,  2.1, 0,  "French Horn")),+    (60, (4,  2.1, 0,  "Horn in F")),+    (61, (0,  2.0, 0,  "Brass Section")),+    (62, (0,  2.0, 0,  "Synth Brass 1")),+    (63, (0,  2.0, 0,  "Synth Brass 2")),++    (64, (0,  1.51, 0,  "Soprano Sax")),+    (65, (0,  1.52, 0,  "Alto Sax")),+    (66, (0,  1.53, 0,  "Tenor Sax")),+    (67, (0,  1.54, 0,  "Baritone Sax")),+    (68, (1,  1.3, 0,  "Oboe")),+    (69, (1,  1.4, 0,  "English Horn")),+    (70, (3,  1.7, 2,  "Bassoon")),+    (71, (2,  1.6, 0,  "Clarinet in Bb")),++    (72, (0,  1.1, 0,  "Piccolo")),+    (73, (0,  1.2, 0,  "Flute")),+    (74, (0,  1.0, 0,  "Recorder")),+    (75, (0,  1.0, 0,  "Pan Flute")),+    (76, (0,  1.0, 0,  "Blown bottle")),+    (77, (0,  1.0, 0,  "Shakuhachi")),+    (78, (0,  1.0, 0,  "Whistle")),+    (79, (0,  1.0, 0,  "Ocarina")),++    (80, (0,  1.0, 0,  "Lead 1 (square)")),+    (81, (0,  1.0, 0,  "Lead 2 (sawtooth)")),+    (82, (0,  1.0, 0,  "Lead 3 (calliope)")),+    (83, (0,  1.0, 0,  "Lead 4 (chiff)")),+    (84, (0,  1.0, 0,  "Lead 5 (charang)")),+    (85, (0,  1.0, 0,  "Lead 6 (voice)")),+    (86, (0,  1.0, 0,  "Lead 7 (fifths)")),+    (87, (0,  1.0, 0,  "Lead 8 (bass + lead)")),++    (88, (0,  1.0, 0,  "Pad 1 (new age)")),+    (89, (0,  1.0, 0,  "Pad 2 (warm)")),+    (90, (0,  1.0, 0,  "Pad 3 (polysynth)")),+    (91, (0,  1.0, 0,  "Pad 4 (choir)")),+    (92, (0,  1.0, 0,  "Pad 5 (bowed)")),+    (93, (0,  1.0, 0,  "Pad 6 (metallic)")),+    (94, (0,  1.0, 0,  "Pad 7 (halo)")),+    (95, (0,  1.0, 0,  "Pad 8 (sweep)")),++    (96, (0,  1.0, 0,  "FX 1 (rain)")),+    (97, (0,  1.0, 0,  "FX 2 (soundtrack)")),+    (98, (0,  1.0, 0,  "FX 3 (crystal)")),+    (99, (0,  1.0, 0,  "FX 4 (atmosphere)")),+    (100, (0,  1.0, 0,  "FX 5 (brightness)")),+    (101, (0,  1.0, 0,  "FX 6 (goblins)")),+    (102, (0,  1.0, 0,  "FX 7 (echoes)")),+    (103, (0,  1.0, 0,  "FX 8 (sci-fi)")),++    (104, (0,  1.0, 0,  "Sitar")),+    (105, (0,  1.0, 0,  "Banjo")),+    (106, (0,  1.0, 0,  "Shamisen")),+    (107, (0,  1.0, 0,  "Koto")),+    (108, (0,  1.0, 0,  "Kalimba")),+    (109, (0,  1.0, 0,  "Bagpipe")),+    (110, (0,  1.0, 0,  "Fiddle")),+    (111, (0,  1.0, 0,  "Shanai")),++    (112, (0,  1.0, 0,  "Tinkle Bell")),+    (113, (0,  1.0, 0,  "Agogo")),+    (114, (0,  1.0, 0,  "Steel Drums")),+    (115, (0,  1.0, 0,  "Woodblock")),+    (116, (0,  1.0, 0,  "Taiko Drum")),+    (117, (0,  1.0, 0,  "Melodic Tom")),+    (118, (0,  1.0, 0,  "Synth Drum")),+    (119, (0,  1.0, 0,  "Reverse Cymbal")),++    (120, (0,  1.0, 0,  "Guitar Fret Noise")),+    (121, (0,  1.0, 0,  "Breath Noise")),+    (122, (0,  1.0, 0,  "Seashore")),+    (123, (0,  1.0, 0,  "Bird Tweet")),+    (124, (0,  1.0, 0,  "Telephone Ring")),+    (125, (0,  1.0, 0,  "Helicopter")),+    (126, (0,  1.0, 0,  "Applause")),+    (127, (0,  1.0, 0,  "Gunshot"))+    ]++gmPerc :: [(Int, String)]+gmPerc = [+    (35, "Bass Drum 2"),+    (36, "Bass Drum 1"),+    (37, "Side Stick/Rimshot"),+    (38, "Snare Drum 1"),+    (39, "Hand Clap"),+    (40, "Snare Drum 2"),+    (41, "Low Tom 2"),+    (42, "Closed Hi-hat"),+    (43, "Low Tom 1"),+    (44, "Pedal Hi-hat"),+    (45, "Mid Tom 2"),+    (46, "Open Hi-hat"),+    (47, "Mid Tom 1"),+    (48, "High Tom 2"),+    (49, "Crash Cymbal 1"),+    (50, "High Tom 1"),+    (51, "Ride Cymbal 1"),+    (52, "Chinese Cymbal"),+    (53, "Ride Bell"),+    (54, "Tambourine"),+    (55, "Splash Cymbal"),+    (56, "Cowbell"),+    (57, "Crash Cymbal 2"),+    (58, "Vibra Slap"),+    (59, "Ride Cymbal 2"),+    (60, "High Bongo"),+    (61, "Low Bongo"),+    (62, "Mute High Conga"),+    (63, "Open High Conga"),+    (64, "Low Conga"),+    (65, "High Timbale"),+    (66, "Low Timbale"),+    (67, "High Agogô"),+    (68, "Low Agogô"),+    (69, "Cabasa"),+    (70, "Maracas"),+    (71, "Short Whistle"),+    (72, "Long Whistle"),+    (73, "Short Güiro"),+    (74, "Long Güiro"),+    (75, "Claves"),+    (76, "High Wood Block"),+    (77, "Low Wood Block"),+    (78, "Mute Cuíca"),+    (79, "Open Cuíca"),+    (80, "Mute Triangle"),+    (81, "Open Triangle")+    ]+             
+ src/Music/Parts/Solo.hs view
@@ -0,0 +1,41 @@++{-# LANGUAGE DeriveDataTypeable         #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE TypeFamilies               #-}++------------------------------------------------------------------------------------+-- |+-- Copyright   : (c) Hans Hoglund 2012-2015+--+-- License     : BSD-style+--+-- Maintainer  : hans@hanshoglund.se+-- Stability   : experimental+-- Portability : non-portable (TF,GNTD)+--+-------------------------------------------------------------------------------------++module Music.Parts.Solo (+          Solo(..),+  ) where++import           Control.Applicative+import           Control.Lens                    (toListOf)+import           Data.Default+import           Data.Functor.Adjunction         (unzipR)+import qualified Data.List+import           Data.Maybe+import           Data.Semigroup+import           Data.Semigroup.Option.Instances+import           Data.Traversable                (traverse)+import           Data.Typeable+import           Text.Numeral.Roman              (toRoman)++data Solo+    = Solo+    | Tutti+    deriving (Eq, Show, Ord, Enum)++instance Default Solo where+    def = Tutti+
+ src/Music/Parts/Subpart.hs view
@@ -0,0 +1,55 @@++{-# LANGUAGE DeriveDataTypeable         #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE TypeFamilies               #-}++------------------------------------------------------------------------------------+-- |+-- Copyright   : (c) Hans Hoglund 2012-2015+--+-- License     : BSD-style+--+-- Maintainer  : hans@hanshoglund.se+-- Stability   : experimental+-- Portability : non-portable (TF,GNTD)+--+-------------------------------------------------------------------------------------++module Music.Parts.Subpart (+          Subpart(..),+          containsSubpart,+  ) where++import           Control.Applicative+import           Control.Lens                    (toListOf)+import           Data.Default+import           Data.Functor.Adjunction         (unzipR)+import qualified Data.List+import           Data.Maybe+import           Data.Semigroup+import           Data.Semigroup.Option.Instances+import           Data.Traversable                (traverse)+import           Data.Typeable+import           Text.Numeral.Roman              (toRoman)++import Music.Parts.Division++-- |+-- A subpart is a potentially infinite sequence of divisions, each typically+-- designated using a new index type, i.e. @I.1.2@.+--+-- The empty subpart (also known as 'mempty') represents all the players of the group,+-- or in the context of 'Part', all players of the given instrument.+--+newtype Subpart = Subpart [Division]+    deriving (Eq, Ord, Default, Semigroup, Monoid)++instance Show Subpart where+    show (Subpart ps) = Data.List.intercalate "." $ mapFR showDivisionR showDivision $ ps+        where+            mapFR f g []     = []+            mapFR f g (x:xs) = f x : fmap g xs++containsSubpart :: Subpart -> Subpart -> Bool+Subpart x `containsSubpart` Subpart y = y `Data.List.isPrefixOf` x+