Safe Haskell | Safe-Inferred |
---|
Notation for Carnatic solkattu.
This is actually a separate library that's independent of the rest of the sequencer. The only connection is that its final output can be stroke names for some instrument and thus easily inserted into a track.
Solkattu is a general form of rhythmic notation. Since the syllables (sollus) are independent of any particular instrument, they can express general rhythmic structures, which can then be realized in a form idiomatic to different instruments.
The system is split up in a somewhat complicated way to separate rhythmic handling from sollus, and separate realizations sollus to various instruments. The structure from low to high level is:
Solkattu.Tala - General Tala.Tala
type.
Solkattu.S - Generic rhythmic framework, where the
"payload" note type is abstract. This can express rhythms in terms of
S.Speed
and S.TempoChange
, check them against a Tala, and realize down to
S.Duration
tagged notes.
Solkattu.Solkattu - Fill in a Sequence's note with a Sollu type. This supports all of the notation in Solkattu.Dsl. As Sequence leaves the note type abstract, this leaves the instrument-dependent stroke type abstract.
Solkattu.Realize - This has an instrument-specific Stroke, which is the result of resolving the sollus. The stroke type is still abstract since it's polymorphic over the specific instrument.
Solkattu.Instrument.Mridangam, Solkattu.Instrument.KendangTunggal, etc. - These describe specific instruments for Realize.
Solkattu.Korvai - A Korvai unifies the instrument-specific Patterns and StrokeMaps together with Tala and a solkattu sequence. So I can support multiple instruments from one solkattu score, it merges the stroke types into a single type, and projects out the specific strokes depending on which instrument is being realized.
Solkattu.Dsl.Solkattu - Functions for creating solkattu scores. It defines (or replaces) various operators to make scores look nicer.
Solkattu.Score.Solkattu* - Instrument-independent korvais.
Solkattu.Dsl.Mridangam, Solkattu.Score.Mridangam* - These are similar to Dsl and Score.Solkattu*, except they use concrete mridangam strokes instead of abstract sollus.
The naming convention is that "Note" is the level-specific value,
which may have a "Note" constructor with the "next level" of value.
"SNote" is an alias for composing Note with Note
, and
"Sequence" is a newtype for a list of those, but is abstractly the monoid
where you can put together notation to form a score.
Synopsis
- class (Show a, Pretty a) => Notation a where
- notation :: a -> (Styled.Style, Text)
- extension :: a -> Char
- textNotation :: Text -> (Styled.Style, Text)
- notationText :: Notation a => a -> Text
- type Error = Text
- data Note sollu
- data Group
- = GReduction !Reduction
- | GMeta !Meta
- data Reduction = Reduction {}
- data Meta = Meta {}
- meta :: GroupType -> Meta
- data GroupType
- groupTypes :: [GroupType]
- data Side
- data Space
- data NoteT sollu = NoteT {}
- data Tag
- note :: sollu -> NoteT sollu
- noteOf :: Note sollu -> Maybe (NoteT sollu)
- solluOf :: Note sollu -> Maybe sollu
- modifyNote :: (NoteT a -> NoteT b) -> Note a -> Note b
- newtype Pattern = PatternM S.Matra
- pattern :: S.Matra -> Pattern
- data Karvai
- data Sollu
- parseSollus :: Text -> Either Error [Maybe Sollu]
- allSollus :: [(Text, Sollu)]
- parseSyllables :: Show sollu => [(Text, sollu)] -> Text -> Either Error [Maybe sollu]
- parseSyllablesWord :: [(Text, sollu)] -> Text -> [[Maybe sollu]]
- durationOf :: S.HasMatras a => S.Tempo -> S.Sequence Group a -> S.Duration
- matrasOf :: S.HasMatras a => S.Tempo -> S.Sequence Group a -> S.FMatra
- _durationOf :: (S.HasMatras a, Num dur, Ord dur) => (S.Tempo -> S.Duration -> dur) -> S.Tempo -> S.Sequence Group a -> dur
- flatDuration :: S.HasMatras a => S.Flat Group a -> S.Duration
- cancelKarvai :: [S.Flat g (Note sollu)] -> [S.Flat g (Note sollu)]
- type Variations = [(S.Matra, S.Matra, S.Matra)]
- vary :: (S.Matra -> Variations) -> S.Sequence g (Note sollu) -> [S.Sequence g (Note sollu)]
- variations :: [(S.Matra, S.Matra, S.Matra) -> Bool] -> S.Matra -> Variations
- ascending :: (S.Matra, S.Matra, S.Matra) -> Bool
- descending :: (S.Matra, S.Matra, S.Matra) -> Bool
- standard :: (S.Matra, S.Matra, S.Matra) -> Bool
- allVariations :: S.Matra -> Variations
- findTriads :: S.Sequence g (Note sollu) -> [(S.Matra, (Int, Int, Int))]
- newtype Exception = Exception Text
- throw :: CallStack.Stack => Text -> a
- applyModifications :: (a -> mod -> a) -> [(Int, mod)] -> [a] -> [a]
- permuteFst :: (a -> [b]) -> [(a, x)] -> [[(b, x)]]
- check :: CallStack.Stack => Either Error a -> a
- checkMsg :: CallStack.Stack => Text -> Either Error a -> a
Documentation
class (Show a, Pretty a) => Notation a where Source #
Render a concrete stroke to text representing it. This is used for ASCII output, so it should produce only a single character per matra duration. There could be exceptions for strokes which are both rare and almost always occur before a rest.
The Show and Pretty superclasses are to make debugging more convenient.
notation :: a -> (Styled.Style, Text) Source #
extension :: a -> Char Source #
Extend the note to fill its time with this character.
Instances
Notation Degree Source # | |
Notation Pitch Source # | |
Notation Bol Source # | |
Notation Stroke Source # | |
Notation Stroke Source # | |
Notation Stroke Source # | |
Notation Thoppi Source # | |
Notation Valantalai Source # | |
Defined in Solkattu.Instrument.Mridangam notation :: Valantalai -> (Styled.Style, Text) Source # extension :: Valantalai -> Char Source # | |
Notation Stroke Source # | |
Notation Stroke Source # | |
Notation Pattern Source # | |
Notation Sollu Source # | |
Notation stroke => Notation (Note stroke) Source # | |
Notation stroke => Notation (Stroke stroke) Source # | |
textNotation :: Text -> (Styled.Style, Text) Source #
notationText :: Notation a => a -> Text Source #
Instances
A Group is metadata stored alongside the nested sollus, but the actual
nesting happens in S.Group
. See NOTE [nested-groups] for how I arrived at
the design.
Instances
IsString Sequence Source # | |
Defined in Solkattu.Dsl.Bol fromString :: String -> Sequence # | |
IsString Sequence Source # | |
Defined in Solkattu.Dsl.Solkattu fromString :: String -> Sequence # | |
IsString SequenceM Source # | |
Defined in Solkattu.Dsl.Solkattu fromString :: String -> SequenceM # | |
Show Group Source # | |
Eq Group Source # | |
Ord Group Source # | |
Pretty Group Source # | |
Rest (SequenceT sollu) Source # | |
Defined in Solkattu.Dsl.Notation |
Meta | |
|
GGroup | A generic group, usually manually applied. |
GReductionT |
|
GFiller | A bit of decorative filler, should be highlighted subtly if at all. |
GPattern | A realized |
GExplicitPattern | A pattern with sollus already given. |
GSarva | |
GCheckDuration !S.Duration | Check that this group has the duration in |
groupTypes :: [GroupType] Source #
All GroupTypes that should be seen by render. GCheckDuration should
have been removed by checkDuration
. I could express that in the
type, but it seems too noisy for now.
Before means drop the strokes before the _split
split, After means
drop the ones after.
A note that can take up a variable amount of space. Since it doesn't have set strokes (or any, in the case of Rest), it can be arbitrarily divided.
Rest | |
Offset | This is not actual rest time in the performance, but inserted in the score for a start offset. |
Instances
Foldable NoteT Source # | |
Defined in Solkattu.Solkattu fold :: Monoid m => NoteT m -> m # foldMap :: Monoid m => (a -> m) -> NoteT a -> m # foldMap' :: Monoid m => (a -> m) -> NoteT a -> m # foldr :: (a -> b -> b) -> b -> NoteT a -> b # foldr' :: (a -> b -> b) -> b -> NoteT a -> b # foldl :: (b -> a -> b) -> b -> NoteT a -> b # foldl' :: (b -> a -> b) -> b -> NoteT a -> b # foldr1 :: (a -> a -> a) -> NoteT a -> a # foldl1 :: (a -> a -> a) -> NoteT a -> a # elem :: Eq a => a -> NoteT a -> Bool # maximum :: Ord a => NoteT a -> a # minimum :: Ord a => NoteT a -> a # | |
Traversable NoteT Source # | |
Functor NoteT Source # | |
Show sollu => Show (NoteT sollu) Source # | |
Eq sollu => Eq (NoteT sollu) Source # | |
Ord sollu => Ord (NoteT sollu) Source # | |
Defined in Solkattu.Solkattu | |
Pretty sollu => Pretty (NoteT sollu) Source # | |
A sollu can have a tag attached. This is used to map certain sets of sollus to a different realization. The idea is that even though the sollus are the same, they may be realized different ways in different contexts.
Tag !Int | |
Middle | Marks the middle karvai in a tirmanam. This is applied automatically, so it can have an alternate realization. |
Standard | Marks a standard pattern. This isolates the "standard pattern" use of common sollus like taka. |
NoSollu | a dummy sollu for rests in Konnakol |
Cham | |
Dheem | |
Dhom | |
Di | |
Dim | |
Din | |
Dit | |
Du | |
Ga | |
Gin | |
Gu | |
Jo | |
Ka | |
Ki | |
Ku | |
Kum | |
Lang | |
Mi | |
Na | |
Nam | |
Nang | |
Nu | |
Ri | |
Ta | |
Tam | |
Tang | |
Tong | |
Tat | |
Tha | |
Thom | |
Ti |
Instances
IsString Sequence Source # | |
Defined in Solkattu.Dsl.Solkattu fromString :: String -> Sequence # | |
Bounded Sollu Source # | |
Enum Sollu Source # | |
Show Sollu Source # | |
Eq Sollu Source # | |
Ord Sollu Source # | |
Expr.ToExpr Sollu Source # | |
Defined in Solkattu.Instrument.Konnakol | |
Notation Sollu Source # | |
Pretty Sollu Source # | |
Expr.ToExpr (Stroke Sollu) Source # | |
Defined in Solkattu.Instrument.Konnakol |
parseSollus
durations
durationOf :: S.HasMatras a => S.Tempo -> S.Sequence Group a -> S.Duration Source #
matrasOf :: S.HasMatras a => S.Tempo -> S.Sequence Group a -> S.FMatra Source #
_durationOf :: (S.HasMatras a, Num dur, Ord dur) => (S.Tempo -> S.Duration -> dur) -> S.Tempo -> S.Sequence Group a -> dur Source #
flatDuration :: S.HasMatras a => S.Flat Group a -> S.Duration Source #
Unfortunately, with Reduction and GSarva groups, the notes don't reflect
the actual durations, so for Group
-bearing S.Flat
, I need a special
function. I tried really hard to prevent this but failed. The sollus have
to go in the note field, and with reductions and sarva, they no longer
correspond exactly to realized strokes. I would have to two note slots,
one for a space-filling Group FMatras
, and another for the sollus, but
since groups can be nested, it gets really head-hurting for my tiny brain.
See NOTE [nested-groups] for chaotic details.
functions
cancelKarvai :: [S.Flat g (Note sollu)] -> [S.Flat g (Note sollu)] Source #
A Karvai Note followed by a Space will replace the rest, if followed by
a Note or Pattern, the Karvai will be dropped. Since a Karvai
note
logically has no duration, if it's the last note it will be dropped
vary
:: (S.Matra -> Variations) | variations allowed for this duration |
-> S.Sequence g (Note sollu) | |
-> [S.Sequence g (Note sollu)] |
Variation means replacing a triad of patterns of the same duration with a an increasing or decreasing sequence. For instance, 666 can become 567, 765, or 777 can become 678 or 579 or their inverses.
TODO Variation on a higher order is also possible, so for instance 777, 777, 777 may become 666, 777, 888
TODO Also we have 5, 55, 555 -> 55, 55, 55 -> 555, 55, 5. This actually applies to more than just Patterns, e.g. 3 as tadin_. I think this is orthogonal and could get a different function.
variations :: [(S.Matra, S.Matra, S.Matra) -> Bool] -> S.Matra -> Variations Source #
allVariations :: S.Matra -> Variations Source #
findTriads :: S.Sequence g (Note sollu) -> [(S.Matra, (Int, Int, Int))] Source #
Find triples of Patterns with the same length and return their indices. The indices are in ascending order.
exceptions
Yes, I use impure exceptions, because otherwise the DSL has to become monadic or at least applicative. But it seems less egregious because there isn't such a strong distinction between compiling and running anyway.
But it does mean I have to be careful to force and catch at the boundaries.
throw :: CallStack.Stack => Text -> a Source #
util
:: (a -> mod -> a) | |
-> [(Int, mod)] | modifications along with their indices, in ascending order |
-> [a] | |
-> [a] |
permuteFst :: (a -> [b]) -> [(a, x)] -> [[(b, x)]] Source #