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

Derive.C.Post.Postproc

Contents

Description

Postprocs that change note start and duration.

Synopsis

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.

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.

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.

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.

apply start offset

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

Arguments

 :: RealTime.RealTime don't move notes any closer than this -> Maybe.Maybe (RealTime.RealTime, RealTime.RealTime) -> Maybe.Maybe (RealTime.RealTime, RealTime.RealTime) -> RealTime.RealTime -> RealTime.RealTime -> RealTime.RealTime

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?

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.