module Music.Time.Aligned (
Alignable(..),
Aligned,
aligned,
realign,
renderAligned,
renderAlignedVoice,
renderAlignedNote,
renderAlignedDuration,
) where
import Control.Applicative
import Control.Comonad
import Control.Lens hiding (Indexable, Level, above, below,
index, inside, parts, reversed,
transform, (<|), (|>))
import Data.AffineSpace
import Data.AffineSpace.Point
import Data.Bifunctor
import Data.Foldable (Foldable)
import qualified Data.Foldable as Foldable
import Data.Functor.Adjunction (unzipR)
import Data.Functor.Couple
import Data.String
import Data.Typeable
import Data.VectorSpace
import Data.Aeson (ToJSON (..))
import qualified Data.Aeson as JSON
import Music.Dynamics.Literal
import Music.Pitch.Literal
import Music.Time.Event
import Music.Time.Juxtapose
import Music.Time.Note
import Music.Time.Score
import Music.Time.Voice
class Alignable a where
align :: Alignment -> a -> a
instance Alignable a => Alignable [a] where
align l = fmap (align l)
instance Alignable (Aligned a) where
align l (Aligned ((t, _), a)) = Aligned ((t, l), a)
newtype Aligned v = Aligned { getAligned :: ((Time, Alignment), v) }
deriving (Functor, Eq, Ord, Foldable, Traversable)
instance Wrapped (Aligned v) where
type Unwrapped (Aligned v) = ((Time, Alignment), v)
_Wrapped' = iso getAligned Aligned
instance Rewrapped (Aligned a) (Aligned b)
aligned :: Time -> Alignment -> v -> Aligned v
aligned t d a = Aligned ((t, d), a)
instance Show a => Show (Aligned a) where
show (Aligned ((t,d),v)) = "aligned ("++show t++") ("++show d++") ("++ show v++")"
instance ToJSON a => ToJSON (Aligned a) where
toJSON (Aligned ((t,d),v)) = JSON.object [ ("alignment", toJSON d), ("origin", toJSON t), ("value", toJSON v) ]
instance Transformable v => Transformable (Aligned v) where
transform s (Aligned ((t, d), v)) = Aligned ((transform s t, d), transform s v)
instance (HasDuration v, Transformable v) => HasDuration (Aligned v) where
_duration (Aligned (_, v)) = v^.duration
instance (HasDuration v, Transformable v) => HasPosition (Aligned v) where
_era (Aligned ((position, alignment), v)) =
(position .-^ (size * alignment)) <-> (position .+^ (size * (1alignment)))
where
size = v^.duration
realign :: (HasDuration a, Transformable a) => Alignment -> Aligned a -> Aligned a
realign l a@(Aligned ((t,_),x)) = Aligned ((a^.position l,l),x)
renderAligned :: (HasDuration a, Transformable a) => (Span -> a -> b) -> Aligned a -> b
renderAligned f a@(Aligned (_, v)) = f (_era a) v
voiceToScoreInEra :: Span -> Voice a -> Score a
voiceToScoreInEra e = set era e . scat . map (uncurry stretch) . view pairs . fmap pure
noteToEventInEra :: Span -> Note a -> Event a
noteToEventInEra e = set era e . view notee . fmap pure
durationToSpanInEra :: Span -> Duration -> Span
durationToSpanInEra = const
renderAlignedVoice :: Aligned (Voice a) -> Score a
renderAlignedVoice = renderAligned voiceToScoreInEra
renderAlignedNote :: Aligned (Note a) -> Event a
renderAlignedNote = renderAligned noteToEventInEra
renderAlignedDuration :: Aligned Duration -> Span
renderAlignedDuration = renderAligned durationToSpanInEra