Aoide-2.0.0.0: Composition/Score.hs
{-|
Scores that can be converted to Lilypond and MIDI files.
-}
module Composition.Score (
Clef (..),
Clef_name (..),
Header_field (..),
Initial_position (..),
Instrument_and_staves (..),
Key,
MIDI_instrument,
Part (..),
Score (..),
Stave (..),
Tempo,
Time (..),
Time_numerator_factor (..),
Tracks (..),
Velocity,
int_to_time_numerator_factor,
max_velocity,
time_numerator_factor_to_int,
time_numerator_to_int) where
import Composition.Notes
import Composition.Theory
import Data.List as List
import Data.Map.Strict
import Data.Maybe
import Data.Set as Set
import Data.Tuple
import Data.Word
-- | Clefs (with transposition).
data Clef note_type where
Pitched_clef :: {clef_name :: Clef_name, transposition :: Steps} -> Clef Pitched
Percussion_clef :: Clef Unpitched
-- | Clef names.
data Clef_name = Subbass | Bass | Baritone_F | Baritone_C | Tenor | Alto | Mezzosoprano | Soprano | Treble | French
-- | Score header fields.
data Header_field = Left_text | Overtitle | Right_text | Subtitle | Subsubtitle | Title
-- | The timing of the first event relative to the start of the measure. For example, if the piece is in 3/4 and starts with a
-- 1/4 partial bar the initial position can be written as @Initial_position 1 Half@ or @Initial_position 2 Quarter@. If the
-- piece starts with a full bar the numerator is 0 (and you can use any length as the denominator).
data Initial_position = Initial_position Int Basic_length
-- | Group of staves for one instrument.
data Instrument_and_staves note_type =
Instrument_and_staves {
instrument_name :: String,
short_instrument_name :: String,
midi_instrument :: MIDI_instrument,
velocity :: Velocity,
staves :: [Stave note_type]}
-- | A set of note names that serves as a key signature. For example, the key signature of C minor would be @[E_flat, A_flat,
-- B_flat]@. Conflicting accidentals will result in an error.
type Key = Set Note_name
-- | MIDI instrument code.
type MIDI_instrument = Word8
-- | Each part can have a different key, time signature and instrumentation.
data Part =
Part {
title :: String,
key :: Key,
time :: Time,
initial_position :: Initial_position,
tempo :: Tempo,
stave_groups :: [[Pitched_or_unpitched Instrument_and_staves]]}
-- | Score that can be converted to Lilypond and MIDI files.
data Score = Score {header :: Map Header_field String, parts :: [Part]}
-- | Stave with clef.
data Stave note_type = Stave {clef :: Clef note_type, tracks :: Tracks note_type}
-- | Tempo in beats per minute.
type Tempo = Int
-- | Time signature numerators are written as a list of factors. For example, 2 is written as @[Two]@, 3 as @[Three]@, 4 as
-- @[Two Two]@, 6 as @[Two Three]@, 8 as @[Two Two Two]@, 9 as @[Three Three]@, 12 as @[Two Two Three]@, and so on. Note that
-- in some applications the order matters. For example, 18 as @[Three Two Three]@ means that the bar is divided into three
-- parts, each part is divided in half and then each half is divided into three parts. But 18 as @[Two Three Three]@ means
-- that the bar is divided in half, each half is divided into three parts and then each part is divided into three parts. This
-- will affect the placement of ties in keyboard transcriptions.
data Time_numerator_factor = Two | Three
-- | Time signatures. For example, 2/2 is written as @Time [Two] Half@, 3/2 as @Time [Three] Half@, 2/4 as @Time [Two]
-- Quarter@, and so on.
data Time = Time [Time_numerator_factor] Basic_length
-- | One stave can fit up to two rhythmically independent tracks.
data Tracks note_type = One_track [Event note_type] | Two_tracks [Event note_type] [Event note_type]
-- | MIDI volume ranges from 0 to 127.
type Velocity = Word8
deriving instance Eq Clef_name
deriving instance Eq Header_field
deriving instance Eq Time_numerator_factor
deriving instance Ord Clef_name
deriving instance Ord Header_field
deriving instance Read Clef_name
deriving instance Read Header_field
deriving instance Show (Clef note_type)
deriving instance Show Clef_name
deriving instance Show Header_field
deriving instance Show Initial_position
deriving instance Show (Instrument_and_staves note_type)
deriving instance Show Part
deriving instance Show Score
deriving instance Show (Stave note_type)
deriving instance Show Time
deriving instance Show Time_numerator_factor
deriving instance Show (Tracks note_type)
-- | Convert int to time numerator factor. Mostly for internal use.
int_to_time_numerator_factor :: Int -> Maybe Time_numerator_factor
int_to_time_numerator_factor time_numerator_factor = List.lookup time_numerator_factor (swap <$> time_numerator_factors)
-- | Maximum MIDI volume.
max_velocity :: Velocity
max_velocity = 127
-- | Convert time numerator factor to int. Mostly for internal use.
time_numerator_factor_to_int :: Time_numerator_factor -> Int
time_numerator_factor_to_int time_numerator_factor = fromJust (List.lookup time_numerator_factor time_numerator_factors)
time_numerator_factors :: [(Time_numerator_factor, Int)]
time_numerator_factors = [(Two, 2), (Three, 3)]
-- | Convert time numerator to int. Mostly for internal use.
time_numerator_to_int :: [Time_numerator_factor] -> Int
time_numerator_to_int num = product (time_numerator_factor_to_int <$> num)