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

Cmd.ModifyNotes

Description

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.

Synopsis

Documentation

data Note Source #

This represents a single event on a note track.

Constructors

Note 

Fields

Instances

Instances details
Show Note Source # 
Instance details

Defined in Cmd.ModifyNotes

Methods

showsPrec :: Int -> Note -> ShowS #

show :: Note -> String #

showList :: [Note] -> ShowS #

Eq Note Source # 
Instance details

Defined in Cmd.ModifyNotes

Methods

(==) :: 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.

controls

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

Instances details
Show Control Source # 
Instance details

Defined in Cmd.ModifyNotes

Eq Control Source # 
Instance details

Defined in Cmd.ModifyNotes

Methods

(==) :: 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.

selection

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?

read

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.

write

data NoteTrack Source #

Instances

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 #

Arguments

:: 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.