Karya, built on 2022-03-21T01:30:44 (patch 89d1651424c35e564138d93424a157ff87457245)
Safe HaskellSafe-Inferred



Support for high level score modifications. This is companion to Cmd.ModifyEvents, which is for low level transformations.

The main interface to this is Cmd.Repl.LNote.

The score language is code to to be interpreted, not data to be manipulated. This is good for flexibility, but bad for direct transformation. Therefore, all the functions in here rely on a certain amount of conventional structure to tame the flexibility.

The lowest level, represented by a list of Notes, assumes that each note track has a single "branch" of control tracks underneath it, and each note event has control values within its extent, so each note can be sliced out and treated as a unit. So it doesn't support note tracks with multiple parallel children, and it doesn't support order-dependent control tracks, which means that relative controls are out too (TODO actually a relative control track is fine as long as there's only one). Also, since notes only carry along the controls directly underneath them, they can wind up with different control values when they are placed on a different track (TODO it would be possible to deal with this too, by copying the events forward).

I initially attempted to support trees of control tracks in full generality, or even just an ordered list of controls, but there's a problem when different Notes have different controls: where do the control tracks get merged into a tree, relative to each other? Not only do I have to invent an order, but it has to be linear, since there's also no information to merge into a branching skeleton. Since I can't create one with Notes, I felt Notes shouldn't be able to parse them either.

The Notes can be annotated with additional data, such as pitch, but of course will make it more specialized and reliant on convention. For instance, the pitches have to be extracted from the pitch events, which will fail unless there's an easily parseable pitch in there.

TODO it should be possible to get the pitch out of the derivation by finding the corresponding Score.Event by looking for its stack.



data Note Source #

This represents a single event on a note track.





Instances details
Show Note Source # 
Instance details

Defined in Cmd.ModifyNotes


showsPrec :: Int -> Note -> ShowS #

show :: Note -> String #

showList :: [Note] -> ShowS #

Eq Note Source # 
Instance details

Defined in Cmd.ModifyNotes


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

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

Pretty.Pretty Note Source # 
Instance details

Defined in Cmd.ModifyNotes

type Index = Int Source #

Each note has an Index, which indicates which of the selected note tracks it came from, or should be written to.


data Control Source #

A simplified version of ParseTitle.ControlType, since Notes don't support all the forms of control tracks. Put Pitch first so it sorts first, to support the convention of putting the pitch track right after the note track.


Instances details
Show Control Source # 
Instance details

Defined in Cmd.ModifyNotes

Eq Control Source # 
Instance details

Defined in Cmd.ModifyNotes


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

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

Ord Control Source # 
Instance details

Defined in Cmd.ModifyNotes

Pretty.Pretty Control Source # 
Instance details

Defined in Cmd.ModifyNotes

sorted_controls :: Controls -> [(Control, Events.Events)] Source #

Put the pitch tracks next to the note, the rest go in alphabetical order.


type ModifyNotes m = BlockId -> [(Note, TrackId)] -> m [Note] Source #

Modify notes.

notes :: Monad m => ([Note] -> [Note]) -> ModifyNotes m Source #

note :: Monad m => (Note -> Note) -> ModifyNotes m Source #

Modify a single note.

selection :: Cmd.M m => ModifyNotes m -> m () Source #

Modify notes on the selected tracks. Only the top level note tracks are affected, so you can select an entire block and not worry about mangling parent controls.

This may add new tracks, but will not delete tracks that are made empty. It could, but it seems easy enough to delete the tracks by hand once I verify that the transformation worked. TODO revisit this if it's annoying

selected_notes :: Cmd.M m => m [(Note, TrackId)] Source #

Find the top-level note tracks in the selection, and reduce them down to Notes.

annotated transformations

type Annotated a m = [(Note, a)] -> m [Note] Source #

find_controls :: [(Note, TrackId)] -> Vector.Vector Score.Event -> [(Note, (Maybe Transposed, ScoreT.ControlValMap))] Source #

This finds the controls of each note by looking for its corresponding event in the performance. TODO matching by stack seems like it could be inaccurate, and inefficient too. Shouldn't I look up the signal directly from the performance?


slice_note :: Index -> [Tree.Tree (Ui.TrackInfo, Events.Events)] -> Event.Event -> Either Error Note Source #

The whole thing fails if a title is unparseable or the control tracks have a fork in the skeleton.

This is similar to slice and I initially spent some time trying to reuse it, but it's different enough that most of the work that slice does doesn't apply here.


data NoteTrack Source #


Instances details
Monoid NoteTrack Source # 
Instance details

Defined in Cmd.ModifyNotes

Semigroup NoteTrack Source # 
Instance details

Defined in Cmd.ModifyNotes

Show NoteTrack Source # 
Instance details

Defined in Cmd.ModifyNotes

Eq NoteTrack Source # 
Instance details

Defined in Cmd.ModifyNotes

write_tracks Source #


:: Ui.M m 
=> BlockId 
-> [TrackId]

The TrackIds are expected to line up with NoteTracks. If there are more NoteTracks than TrackIds, new tracks will be created.

-> [NoteTrack] 
-> m () 

Write NoteTracks to the given block. It may create new tracks, but won't delete ones that are made empty.

tracknum_after :: Ui.M m => BlockId -> [TrackId] -> m Types.TrackNum Source #

Get the tracknum after the given tracks.

bottom_track :: Ui.M m => BlockId -> TrackId -> m (Maybe Ui.TrackInfo) Source #

Get the bottom track below the given TrackId. If there are more than one, pick the one with the highest TrackNum.