Karya, built on Mon Jul 24 11:39:07 PDT 2017 (patch 33511aca01257b76b88de7c7a2763b7a965c084e)

Safe HaskellNone

Derive.Call.Post.Postproc

Contents

Description

Postprocs that change note start and duration.

Synopsis

Documentation

cancel

type Cancel = [Score.Event] -> Either Text [Score.Event] Source #

Given a set of coincident notes, return either an error, or merge them into a set of output notes.

type Key key = Score.Event -> key Source #

The key identifies another event which is in the same voice. This could be Post.hand_key, but it could also match polos to sangsih, since they form a composite part.

cancel_strong_weak :: (Score.Event -> [Score.Event] -> Score.Event) -> [Score.Event] -> Either Text [Score.Event] Source #

Merge notes with Flags.strong and Flags.weak. The rules are that strong notes merge with weaker ones, in the order strong, normal, weak.

Previously I considered multiple weaks or strongs ambiguous, but it turns out I get multiple strongs with two hand strokes at the end of a block, and I might as well allow the rest too, for simplicity.

infer_duration_merged :: Score.Event -> [Score.Event] -> Score.Event Source #

Handle Flags.infer_duration for notes merged together. This is the case where a final note replaces a coincident initial note. The strong note gets the duration of the longest weak notes, if there are any. If there are no weaks, then there are no coincedent notes to merge, so return the event unchanged so infer_duration_single can handle it.

infer_duration_single :: Eq key => Key key -> RealTime.RealTime -> Stream.Stream Score.Event -> Stream.Stream Score.Event Source #

Handle Flags.infer_duration for a note by itself. When there is no coincedent note to replace, the duration extends to the start of the next matching event, according to the Key.

This actually finds the next matching event which starts later than this one. Normally notes of the same key are not expected to occur simultaneously, but may still do so, for example pasang parts which are normally considered a single voice but may still contain unison or kempyung.

group_coincident :: Ord key => (Score.Event -> key) -> Events -> [Either [LEvent.LEvent Score.Event] [Score.Event]] Source #

Group events with the same start time. Events in Left are not grouped.

suppress_notes :: Stream.Stream Score.Event -> Stream.Stream Score.Event Source #

Filter out events that fall at and before the EnvKey.suppress_until range of an event with the same (instrument, hand). Only events that don't have a suppress_until are suppressed.

This is complicated by the fact that an event should suppress coincident events even if the supressor follows the suppressee in the list, so I have to look into the future for the greatest suppress_until.

replace_note :: Score.Event -> Score.Event -> Score.Event Source #

A note with inferred duration gets its start from the end of the previous block, but its duration and the rest of its controls come from the corresponding note at the beginning of the next block.

TODO currently this is unused. Formerly it was used when an infer-duration note replaced a note. The intent was that the strong note at the end of the block would determine the initial pitch and dynamic of the note, but control curves would still be picked up from the replaced note, since there is no room to put them on the final note. It seems a little ad-hoc and grody, but it still makes a kind of sense and I may still want it, so I'll leave this function here for now.

apply start offset

c_apply_start_offset :: Transformer Note Source #

Previously I applied the %start-s and %start-t controls in the note generator, but I wound up with notes getting out of sync with their controls. Even if I apply the controls before inversion, it still doesn't work other calls, like say block calls, and I can't apply the controls before the block call

adjust_offset Source #

Conceptually, all notes move together until they bump into each other. Or, they move without restriction, and then go to midway of the overlap. But the note's start is a hard lower or upper limit, so one note moving can never cause another note to move, it can just cause it to not move as much as it wanted.

TODO actually "half of the overlap" is not the same as "all move together". For the latter, the overlap split depends on how far the note moved to get there. So instead of overlap2 it's 'max 0 (overlap - n) 2', where n is the imbalance between their move offsets.

TODO this is still broken if an offset causes an note to skip over another. But that should be stopped by the next event, right?

adjust_duration :: RealTime.RealTime -> RealTime.RealTime -> Score.Event -> RealTime.RealTime Source #

Change the duration based on the movement of the next event.

If the event end touches the next start, then adjust dur by next_offset. If it's less, then shorten but don't lengthen. If it overlaps the next note, then leave it alone.