Karya, built on 2023-08-29T07:47:28 (patch 7a412d5d6ba4968ca4155ef276a062ccdeb9109a)
Safe HaskellSafe-Inferred

Solkattu.S

Description

Low level support for rhythmic sequences in a Tala. The actual Note type is polymorphic, so this is purely rhythmic.

Synopsis

Documentation

data Note g a Source #

Constructors

Note !a 
TempoChange !TempoChange ![Note g a] 
Group !g ![Note g a] 

Instances

Instances details
Foldable (Note g) Source # 
Instance details

Defined in Solkattu.S

Methods

fold :: Monoid m => Note g m -> m #

foldMap :: Monoid m => (a -> m) -> Note g a -> m #

foldMap' :: Monoid m => (a -> m) -> Note g a -> m #

foldr :: (a -> b -> b) -> b -> Note g a -> b #

foldr' :: (a -> b -> b) -> b -> Note g a -> b #

foldl :: (b -> a -> b) -> b -> Note g a -> b #

foldl' :: (b -> a -> b) -> b -> Note g a -> b #

foldr1 :: (a -> a -> a) -> Note g a -> a #

foldl1 :: (a -> a -> a) -> Note g a -> a #

toList :: Note g a -> [a] #

null :: Note g a -> Bool #

length :: Note g a -> Int #

elem :: Eq a => a -> Note g a -> Bool #

maximum :: Ord a => Note g a -> a #

minimum :: Ord a => Note g a -> a #

sum :: Num a => Note g a -> a #

product :: Num a => Note g a -> a #

Traversable (Note g) Source # 
Instance details

Defined in Solkattu.S

Methods

traverse :: Applicative f => (a -> f b) -> Note g a -> f (Note g b) #

sequenceA :: Applicative f => Note g (f a) -> f (Note g a) #

mapM :: Monad m => (a -> m b) -> Note g a -> m (Note g b) #

sequence :: Monad m => Note g (m a) -> m (Note g a) #

Functor (Note g) Source # 
Instance details

Defined in Solkattu.S

Methods

fmap :: (a -> b) -> Note g a -> Note g b #

(<$) :: a -> Note g b -> Note g a #

Rest (SNote sollu) Source # 
Instance details

Defined in Solkattu.Dsl.Notation

Methods

__ :: SNote sollu Source #

(Show a, Show g) => Show (Note g a) Source # 
Instance details

Defined in Solkattu.S

Methods

showsPrec :: Int -> Note g a -> ShowS #

show :: Note g a -> String #

showList :: [Note g a] -> ShowS #

(Eq a, Eq g) => Eq (Note g a) Source # 
Instance details

Defined in Solkattu.S

Methods

(==) :: Note g a -> Note g a -> Bool #

(/=) :: Note g a -> Note g a -> Bool #

(Ord a, Ord g) => Ord (Note g a) Source # 
Instance details

Defined in Solkattu.S

Methods

compare :: Note g a -> Note g a -> Ordering #

(<) :: Note g a -> Note g a -> Bool #

(<=) :: Note g a -> Note g a -> Bool #

(>) :: Note g a -> Note g a -> Bool #

(>=) :: Note g a -> Note g a -> Bool #

max :: Note g a -> Note g a -> Note g a #

min :: Note g a -> Note g a -> Note g a #

(Pretty.Pretty a, Pretty.Pretty g) => Pretty.Pretty (Note g a) Source # 
Instance details

Defined in Solkattu.S

Methods

pretty :: Note g a -> Text Source #

format :: Note g a -> Doc Source #

formatList :: [Note g a] -> Doc Source #

data TempoChange Source #

Relative speed change. Each positive number doubles the number of Matras per akshara. Negative numbers halve them.

data Sequence g a Source #

Instances

Instances details
IsString Sequence Source # 
Instance details

Defined in Solkattu.Dsl.Bol

IsString Sequence Source # 
Instance details

Defined in Solkattu.Dsl.Solkattu

IsString SequenceM Source # 
Instance details

Defined in Solkattu.Dsl.Solkattu

Functor (Sequence g) Source # 
Instance details

Defined in Solkattu.S

Methods

fmap :: (a -> b) -> Sequence g a -> Sequence g b #

(<$) :: a -> Sequence g b -> Sequence g a #

Rest (SequenceT sollu) Source # 
Instance details

Defined in Solkattu.Dsl.Notation

Methods

__ :: SequenceT sollu Source #

Monoid (Sequence g a) Source # 
Instance details

Defined in Solkattu.S

Methods

mempty :: Sequence g a #

mappend :: Sequence g a -> Sequence g a -> Sequence g a #

mconcat :: [Sequence g a] -> Sequence g a #

Semigroup (Sequence g a) Source # 
Instance details

Defined in Solkattu.S

Methods

(<>) :: Sequence g a -> Sequence g a -> Sequence g a #

sconcat :: NonEmpty (Sequence g a) -> Sequence g a #

stimes :: Integral b => b -> Sequence g a -> Sequence g a #

(Show a, Show g) => Show (Sequence g a) Source # 
Instance details

Defined in Solkattu.S

Methods

showsPrec :: Int -> Sequence g a -> ShowS #

show :: Sequence g a -> String #

showList :: [Sequence g a] -> ShowS #

(Eq a, Eq g) => Eq (Sequence g a) Source # 
Instance details

Defined in Solkattu.S

Methods

(==) :: Sequence g a -> Sequence g a -> Bool #

(/=) :: Sequence g a -> Sequence g a -> Bool #

(Pretty.Pretty a, Pretty.Pretty g) => Pretty.Pretty (Sequence g a) Source # 
Instance details

Defined in Solkattu.S

fromList :: [Note g a] -> Sequence g a Source #

toList :: Sequence g a -> [Note g a] Source #

mapS :: (Note g1 a1 -> Note g2 a2) -> Sequence g1 a1 -> Sequence g2 a2 Source #

apply :: ([Note g1 a1] -> [Note g2 a2]) -> Sequence g1 a1 -> Sequence g2 a2 Source #

replace :: (Eq g, Eq a) => Sequence g a -> Sequence g a -> Sequence g a -> Sequence g a Source #

data Duration Source #

A single Duration unit is equivalent to 1 Akshara. Unlike FMatra and Matra, this is an absolute duration, so it doesn't depend on _nadai or _speed.

Instances

Instances details
Num Duration Source # 
Instance details

Defined in Solkattu.S

Fractional Duration Source # 
Instance details

Defined in Solkattu.S

Real Duration Source # 
Instance details

Defined in Solkattu.S

RealFrac Duration Source # 
Instance details

Defined in Solkattu.S

Methods

properFraction :: Integral b => Duration -> (b, Duration) #

truncate :: Integral b => Duration -> b #

round :: Integral b => Duration -> b #

ceiling :: Integral b => Duration -> b #

floor :: Integral b => Duration -> b #

Show Duration Source # 
Instance details

Defined in Solkattu.S

Eq Duration Source # 
Instance details

Defined in Solkattu.S

Ord Duration Source # 
Instance details

Defined in Solkattu.S

Pretty.Pretty Duration Source # 
Instance details

Defined in Solkattu.S

data FMatra Source #

This is a fractional Matra. The reason to need a fraction matra is if there are speed changes below, so often this is used to mean toplevel matra, which is to say duration / nadai, in which case it's relative to nadai, not speed. But not always! Sometimes it's used to name a number of Matras where it's assumed they have speed changes to accommodate the fraction.

Instances

Instances details
Num FMatra Source # 
Instance details

Defined in Solkattu.S

Fractional FMatra Source # 
Instance details

Defined in Solkattu.S

Real FMatra Source # 
Instance details

Defined in Solkattu.S

RealFrac FMatra Source # 
Instance details

Defined in Solkattu.S

Methods

properFraction :: Integral b => FMatra -> (b, FMatra) #

truncate :: Integral b => FMatra -> b #

round :: Integral b => FMatra -> b #

ceiling :: Integral b => FMatra -> b #

floor :: Integral b => FMatra -> b #

Show FMatra Source # 
Instance details

Defined in Solkattu.S

Eq FMatra Source # 
Instance details

Defined in Solkattu.S

Methods

(==) :: FMatra -> FMatra -> Bool #

(/=) :: FMatra -> FMatra -> Bool #

Ord FMatra Source # 
Instance details

Defined in Solkattu.S

Pretty.Pretty FMatra Source # 
Instance details

Defined in Solkattu.S

type Matra = Int Source #

A matra is an akshara divided by the nadai. It corresponds to a single sollu in first speed, which means the actual duration is dependent on Nadai and Speed.

Matra being integral is important, since together with TempoChange, it can encode the invariant that durations are always a power of two rational, once you multiply out the nadai.

type Speed = Int Source #

0 means nadai matras per akshara. Positive numbers double that and negative ones halve it.

type Nadai = Int Source #

type Stride = Int Source #

This could be Duration, but it would make normalizeSpeed tricky.

changeSpeed :: Speed -> [Note g a] -> Note g a Source #

class HasMatras a where Source #

Methods

matrasOf :: a -> Matra Source #

hasSustain :: a -> Bool Source #

True if this note has a duration in time. Otherwise, it's a single stroke, which logically has zero duration. This only affects how the note is drawn and whether it becomes a tracklang event with duration.

Instances

Instances details
HasMatras Pattern Source # 
Instance details

Defined in Solkattu.Solkattu

HasMatras (Note stroke) Source # 
Instance details

Defined in Solkattu.Realize

Methods

matrasOf :: Note stroke -> Matra Source #

hasSustain :: Note stroke -> Bool Source #

HasMatras (Note sollu) Source # 
Instance details

Defined in Solkattu.Solkattu

Methods

matrasOf :: Note sollu -> Matra Source #

hasSustain :: Note sollu -> Bool Source #

transform

mapGroup :: (g -> h) -> Note g a -> Note h a Source #

flattenGroups :: [Note g a] -> [Note h a] Source #

simplify :: [Note g a] -> [Note g a] Source #

Drop empty TempoChanges, combine nested ones. Drop empty groups.

map1 :: (a -> a) -> Note g a -> Note g a Source #

Transform only the first Note.

filterNotes :: (a -> Bool) -> Sequence g a -> Sequence g a Source #

dropEndWhile :: (a -> Bool) -> Sequence g a -> Sequence g a Source #

tempo

data Tempo Source #

Constructors

Tempo 

Fields

Instances

Instances details
Show Tempo Source # 
Instance details

Defined in Solkattu.S

Methods

showsPrec :: Int -> Tempo -> ShowS #

show :: Tempo -> String #

showList :: [Tempo] -> ShowS #

Eq Tempo Source # 
Instance details

Defined in Solkattu.S

Methods

(==) :: Tempo -> Tempo -> Bool #

(/=) :: Tempo -> Tempo -> Bool #

Pretty.Pretty Tempo Source # 
Instance details

Defined in Solkattu.S

decompose :: Duration -> Either Text [Speed] Source #

Given a duration, return the speeds of 1 duration notes needed to add up to that duration. Error if the speed went past 4, which means the duration probably isn't binary.

flatten

data Flat g a Source #

This is an intermediate structure where TempoChange has been flattened out. A flat list is easier to deal with, especially since I need to match and replace sections of notes, which may overlap tempo groups arbitrarily.

However, FGroup is actually nested, not flat. Oops. Originally it was flat too, with a count to indicate the scope, with Tempo in a Meta type. I still needed to express the tempo and group order, so I added a separate FGroup, and then it got complicated to keep the count up to date when the children changed size, and process things recursively and it seemed like recursive data would make that simpler again. I only replace sections of notes within group boundaries, so it doesn't need to be flat like TempoChange does.

It turns out it's still annoying to modify trees though, evidence in cancelKarvai.

Another way to look at this, is that each FNote is one Matra.

Constructors

FGroup !Tempo !g ![Flat g a] 
FNote !Tempo !a 

Instances

Instances details
Functor (Flat g) Source # 
Instance details

Defined in Solkattu.S

Methods

fmap :: (a -> b) -> Flat g a -> Flat g b #

(<$) :: a -> Flat g b -> Flat g a #

(Show g, Show a) => Show (Flat g a) Source # 
Instance details

Defined in Solkattu.S

Methods

showsPrec :: Int -> Flat g a -> ShowS #

show :: Flat g a -> String #

showList :: [Flat g a] -> ShowS #

(Eq g, Eq a) => Eq (Flat g a) Source # 
Instance details

Defined in Solkattu.S

Methods

(==) :: Flat g a -> Flat g a -> Bool #

(/=) :: Flat g a -> Flat g a -> Bool #

(Pretty.Pretty g, Pretty.Pretty a) => Pretty.Pretty (Flat g a) Source # 
Instance details

Defined in Solkattu.S

Methods

pretty :: Flat g a -> Text Source #

format :: Flat g a -> Doc Source #

formatList :: [Flat g a] -> Doc Source #

filterFlat :: (a -> Bool) -> [Flat g a] -> [Flat g a] Source #

mapGroupFlat :: (g -> h) -> [Flat g a] -> [Flat h a] Source #

notes :: [Note g a] -> [a] Source #

flatten :: [Note g a] -> [Flat g a] Source #

flattenWith :: Tempo -> [Note g a] -> [Flat g a] Source #

flattenedNotes :: [Flat g a] -> [a] Source #

flatToState :: (Flat g a -> Duration) -> Tala.Akshara -> State -> [Flat g a] -> (State, [(State, Flat g a)]) Source #

Convert events with Tempo into events with absolute positions in State.

I need to look in the group to know what the actual duration is, unfortunately.

withDurations :: HasMatras a => [Flat g a] -> [Flat g (Duration, a)] Source #

Calculate Duration for each note.

TODO this is wrong in general because unfortunately groups can affect duration, as in flatToState. I think I only call it after Koravi.realize, at which point the notes do reflect the duration, but of course that's not reflected in the types. flatDuration has some details.

tempoNotes :: [Flat g a] -> [(Tempo, a)] Source #

maxSpeed :: [Flat g a] -> Speed Source #

tempoToState Source #

Arguments

:: HasMatras a 
=> Tala.Akshara 
-> Duration

start time

-> [(Tempo, a)] 
-> (State, [(State, a)]) 

Convert events with Tempo into events with absolute positions in State.

This is only correct when the group doesn't affect duration. Since there's no group in here, presumably it's already been stripped out, which of you should only have done if it's no longer needed, which is the case post realize.

data Stroke a Source #

Constructors

Attack a 
Sustain a 
Rest 

Instances

Instances details
Show a => Show (Stroke a) Source # 
Instance details

Defined in Solkattu.S

Methods

showsPrec :: Int -> Stroke a -> ShowS #

show :: Stroke a -> String #

showList :: [Stroke a] -> ShowS #

Eq a => Eq (Stroke a) Source # 
Instance details

Defined in Solkattu.S

Methods

(==) :: Stroke a -> Stroke a -> Bool #

(/=) :: Stroke a -> Stroke a -> Bool #

Pretty.Pretty a => Pretty.Pretty (Stroke a) Source # 
Instance details

Defined in Solkattu.S

normalizeSpeed :: HasMatras a => Speed -> Tala.Akshara -> [Flat g a] -> [Flat g (State, Stroke a)] Source #

Normalize to the fastest speed. Fill slower strokes in with rests. Speed 0 always gets at least one Stroke, even if it's not the slowest.

This normalizes speed, not nadai, because Realize.format lays out notation by nadai, not in absolute time.

flattenSpeed :: HasMatras a => Speed -> [Note g a] -> Either Text [Note g (Stroke a)] Source #

This is similar to normalizeSpeed, but working on Notes instead of Flats. Expand speed to the given toSpeed, or error if there's a speed above it, or if I run into a nadai change. This will eliminate all Notes.

State

data State Source #

Keep track of timing and tala position.

Constructors

State 

Fields

  • stateAvartanam :: !Int
     
  • stateAkshara :: !Tala.Akshara
     
  • stateMatra :: !Duration

    Time through this akshara, so this is always < 1. TODO actually this is not matras, but fraction of the way through the akshara. Is there a better term?

  • stateTempo :: !Tempo

    The tempo at the time of the State. This is not needed internally, but it's easier to record this explicitly than try to figure it out based on the difference between this state and the next.

    TODO this is a bit error prone, because while the rest of the fields are about the current state, this is about the next time step. That means advanceStateBy is too late to set it, and it has to be set by whoever calls advanceStateBy. Ugh.

Instances

Instances details
Show State Source # 
Instance details

Defined in Solkattu.S

Methods

showsPrec :: Int -> State -> ShowS #

show :: State -> String #

showList :: [State] -> ShowS #

Pretty.Pretty State Source # 
Instance details

Defined in Solkattu.S

stateMatraPosition :: State -> Duration Source #

Number of aksharas relative to the avartanam.

stateAbsoluteAkshara :: Tala.Akshara -> State -> Duration Source #

Absolute number of aksharas from the beginning of the sequence.

showPosition :: State -> Text Source #

Show avartanam, akshara, and matra as avartanam:akshara+n/d.

functions

durationOf :: HasMatras a => Tempo -> Note g a -> Duration Source #

Flatten the note and return its Duration.

matraFMatra :: Tempo -> Matra -> FMatra Source #

Convert a tempo-relative Matra to a toplevel FMatra, which should only be nadai-relative.

matraDuration :: Tempo -> Duration Source #

Duration of one matra in the given tempo. This doesn't include _stride, because stride adds matras to the note duration, it doesn't change the duration of a matra itself.