Safe Haskell | Safe-Inferred |
---|
Post-processing utils. These are transformers that directly modify the
output of a deriver, as opposed to simply modifying the Dynamic
.
Unfortunately things are complicated by the presence of LEvent.Log
s in
the output stream. I haven't been able to figure out how to cleanly
abstract that away, so I wind up with a collection of functions to handle
specific kinds of maps.
There are variants for each axis:
- monadic vs. pure
- state vs. stateless
- 1:1 vs. 1:many
- preserves order vs. doesn't preserve order
TODO
One big problem with this is the permutations. Another is that I should be able to fuse composed maps, but I think it'll mostly be defeated by the monadic bits, and maybe state. But even monadic bits should be theoretically fusible since I don't mind if the effects (i.e. exceptions) are interleaved. A job for pipes maybe?
Synopsis
- emap1_ :: (a -> b) -> Stream.Stream a -> Stream.Stream b
- emap1_ord_ :: (a -> Score.Event) -> Stream.Stream a -> Stream.Stream Score.Event
- emap1 :: (state -> a -> (state, b)) -> state -> Stream.Stream a -> (state, Stream.Stream b)
- emap :: (state -> a -> (state, [Score.Event])) -> state -> Stream.Stream a -> (state, Stream.Stream Score.Event)
- emap_asc :: (state -> a -> (state, [Score.Event])) -> state -> Stream.Stream a -> (state, Stream.Stream Score.Event)
- emap_ :: (a -> [Score.Event]) -> Stream.Stream a -> Stream.Stream Score.Event
- emap_asc_ :: (a -> [Score.Event]) -> Stream.Stream a -> Stream.Stream Score.Event
- apply :: ([a] -> [b]) -> Stream.Stream a -> Stream.Stream b
- apply_m :: Functor f => ([a] -> f [b]) -> Stream.Stream a -> f (Stream.Stream b)
- emap1m_ :: (a -> Score.Event) -> (a -> Deriver b) -> Stream.Stream a -> Deriver (Stream.Stream b)
- emap_m :: (a -> Score.Event) -> (state -> a -> Deriver (state, [b])) -> state -> Stream.Stream a -> Deriver (state, Stream.Stream b)
- emap_asc_m :: (a -> Score.Event) -> (state -> a -> Deriver (state, [Score.Event])) -> state -> Stream.Stream a -> Deriver (state, Stream.Stream Score.Event)
- emap_m_ :: (a -> Score.Event) -> (a -> Deriver [b]) -> Stream.Stream a -> Deriver (Stream.Stream b)
- emap_asc_m_ :: (a -> Score.Event) -> (a -> Deriver [Score.Event]) -> Stream.Stream a -> Deriver (Stream.Stream Score.Event)
- emap_s_ :: (a -> Score.Event) -> (a -> NoteDeriver) -> Stream.Stream a -> NoteDeriver
- merge_asc :: [[Score.Event]] -> [Score.Event]
- only :: (a -> event) -> (event -> Bool) -> (a -> event) -> a -> event
- has_instrument :: [ScoreT.Instrument] -> Score.Event -> Bool
- control :: ScoreT.Function -> Stream.Stream Score.Event -> [Signal.Y]
- real_time_control :: ScoreT.Function -> Stream.Stream Score.Event -> [RealTime.RealTime]
- duration_control :: ScoreT.TimeT -> ScoreT.Function -> Stream.Stream Score.Event -> Deriver [RealTime.RealTime]
- neighbors :: Stream.Stream a -> Stream.Stream ([a], a, [a])
- neighbors_by :: Eq key => (a -> key) -> Stream.Stream a -> Stream.Stream (Maybe a, a, Maybe a)
- nexts_by :: Eq key => (a -> key) -> Stream.Stream a -> Stream.Stream (a, [a])
- next_by :: Eq key => (a -> key) -> Stream.Stream a -> Stream.Stream (a, Maybe a)
- prev_by :: Eq key => (a -> key) -> Stream.Stream a -> Stream.Stream (Maybe a, a)
- hand_key :: Score.Event -> (ScoreT.Instrument, Maybe Text)
- voice_key :: Score.Event -> (ScoreT.Instrument, Int)
- nexts :: [a] -> [[a]]
- prevs :: [a] -> [[a]]
- map_first :: (a -> Deriver a) -> Stream.Stream a -> Deriver (Stream.Stream a)
- map_head_tail :: (a -> Stream.Stream a -> Deriver (Stream.Stream a)) -> Stream.Stream a -> Deriver (Stream.Stream a)
- control_range :: ControlDeriver -> Deriver (Signal.Control, (RealTime.RealTime, RealTime.RealTime), [Log.Msg])
- pitch_range :: PitchDeriver -> Deriver (DeriveT.PSignal, (RealTime.RealTime, RealTime.RealTime), [Log.Msg])
- signal :: Monoid sig => (sig -> sig) -> Deriver (Stream.Stream sig) -> Deriver (Stream.Stream sig)
- derive_signal :: Monoid sig => Deriver (Stream.Stream sig) -> Deriver (sig, [Log.Msg])
- make_delayed :: PassedArgs a -> RealTime.RealTime -> [DeriveT.Val] -> NoteDeriver
- delayed_event :: [DeriveT.Val] -> Score.Event -> Score.Event
- delayed_args :: Expr.Symbol -> Score.Event -> Maybe [DeriveT.Val]
- put_environ :: Typecheck.ToVal a => EnvKey.Key -> a -> Score.Event -> Either Text Score.Event
- add_environ :: Typecheck.ToVal a => EnvKey.Key -> a -> Score.Event -> Score.Event
- set_instrument :: (ScoreT.Instrument, Instrument) -> Score.Event -> Score.Event
- add_event_stack :: Score.Event -> Log.Msg -> Log.Msg
map events
non-monadic
emap1_ :: (a -> b) -> Stream.Stream a -> Stream.Stream b Source #
1:1 non-monadic map without state.
TODO this is expected to not destroy the order, but that isn't checked. That means either the event doesn't move, or it doesn't move past its neighbors. Way back when events didn't have their start times, I could express this by only mapping over the event, but I'm not sure how to do it now. And in any case, "don't destroy order" is more permissive than "don't move."
emap1_ord_ :: (a -> Score.Event) -> Stream.Stream a -> Stream.Stream Score.Event Source #
Map on Score.Events. The function is allowed to move the events, since it sorts them afterwards.
emap1 :: (state -> a -> (state, b)) -> state -> Stream.Stream a -> (state, Stream.Stream b) Source #
1:1 non-monadic map with state. This is like mapAccumL.
emap :: (state -> a -> (state, [Score.Event])) -> state -> Stream.Stream a -> (state, Stream.Stream Score.Event) Source #
1:n non-monadic map with state.
emap_asc :: (state -> a -> (state, [Score.Event])) -> state -> Stream.Stream a -> (state, Stream.Stream Score.Event) Source #
This is emap
, but it promises to emit events in sorted order.
TODO except that's not enforced, and maybe I should just always sort.
emap_ :: (a -> [Score.Event]) -> Stream.Stream a -> Stream.Stream Score.Event Source #
emap
without state.
emap_asc_ :: (a -> [Score.Event]) -> Stream.Stream a -> Stream.Stream Score.Event Source #
monadic
apply :: ([a] -> [b]) -> Stream.Stream a -> Stream.Stream b Source #
Apply a function to the non-log events. TODO assumes the function doesn't destroy the order.
apply_m :: Functor f => ([a] -> f [b]) -> Stream.Stream a -> f (Stream.Stream b) Source #
emap1m_ :: (a -> Score.Event) -> (a -> Deriver b) -> Stream.Stream a -> Deriver (Stream.Stream b) Source #
1:1 monadic map without state.
:: (a -> Score.Event) | |
-> (state -> a -> Deriver (state, [b])) | Process an event. Exceptions are caught and logged. |
-> state | |
-> Stream.Stream a | |
-> Deriver (state, Stream.Stream b) |
Monadic map with state. The event type is polymorphic, so you can use
LEvent.zip
and co. to zip up unthreaded state, constructed with control
and nexts
and such.
:: (a -> Score.Event) | |
-> (state -> a -> Deriver (state, [Score.Event])) | Process an event. Exceptions are caught and logged. |
-> state | |
-> Stream.Stream a | |
-> Deriver (state, Stream.Stream Score.Event) |
emap_m_ :: (a -> Score.Event) -> (a -> Deriver [b]) -> Stream.Stream a -> Deriver (Stream.Stream b) Source #
emap_m
without the state.
emap_asc_m_ :: (a -> Score.Event) -> (a -> Deriver [Score.Event]) -> Stream.Stream a -> Deriver (Stream.Stream Score.Event) Source #
emap_s_ :: (a -> Score.Event) -> (a -> NoteDeriver) -> Stream.Stream a -> NoteDeriver Source #
Postprocess each event with a NoteDeriver. This is necessary if you need
to generate more notes, e.g. with Call.note
.
merge_asc :: [[Score.Event]] -> [Score.Event] Source #
only
only :: (a -> event) -> (event -> Bool) -> (a -> event) -> a -> event Source #
Only process the events that match, otherwise pass unchanged.
has_instrument :: [ScoreT.Instrument] -> Score.Event -> Bool Source #
unthreaded state
control :: ScoreT.Function -> Stream.Stream Score.Event -> [Signal.Y] Source #
duration_control :: ScoreT.TimeT -> ScoreT.Function -> Stream.Stream Score.Event -> Deriver [RealTime.RealTime] Source #
Take a typed signal to RealTime durations.
neighbors :: Stream.Stream a -> Stream.Stream ([a], a, [a]) Source #
Zip each event up with its neighbors.
neighbors_by :: Eq key => (a -> key) -> Stream.Stream a -> Stream.Stream (Maybe a, a, Maybe a) Source #
Zip each event with its nearest neighbor with the same key. A key might
be Score.event_instrument
, hand_key
, or voice_key
.
TODO it's awkward how calls that are not instrument-specific still have to choose between hand or voice when they want the next "relevant" note. Perhaps hand and voice should be merged into a single concept. They have to be distinct for the lilypond backend though.
nexts_by :: Eq key => (a -> key) -> Stream.Stream a -> Stream.Stream (a, [a]) Source #
next_by :: Eq key => (a -> key) -> Stream.Stream a -> Stream.Stream (a, Maybe a) Source #
Like neighbors_by
, but only the next neighbor.
prev_by :: Eq key => (a -> key) -> Stream.Stream a -> Stream.Stream (Maybe a, a) Source #
hand_key :: Score.Event -> (ScoreT.Instrument, Maybe Text) Source #
voice_key :: Score.Event -> (ScoreT.Instrument, Int) Source #
misc maps
map_first :: (a -> Deriver a) -> Stream.Stream a -> Deriver (Stream.Stream a) Source #
Apply a function on the first Event of an LEvent stream. TODO this shouldn't destroy the order, but it isn't checkded.
map_head_tail :: (a -> Stream.Stream a -> Deriver (Stream.Stream a)) -> Stream.Stream a -> Deriver (Stream.Stream a) Source #
Transform the first event and the rest of the events.
signal
control_range :: ControlDeriver -> Deriver (Signal.Control, (RealTime.RealTime, RealTime.RealTime), [Log.Msg]) Source #
pitch_range :: PitchDeriver -> Deriver (DeriveT.PSignal, (RealTime.RealTime, RealTime.RealTime), [Log.Msg]) Source #
signal :: Monoid sig => (sig -> sig) -> Deriver (Stream.Stream sig) -> Deriver (Stream.Stream sig) Source #
Transform a pitch or control signal.
derive_signal :: Monoid sig => Deriver (Stream.Stream sig) -> Deriver (sig, [Log.Msg]) Source #
delayed events
make_delayed :: PassedArgs a -> RealTime.RealTime -> [DeriveT.Val] -> NoteDeriver Source #
Make a delayed event.
A delayed event should be realized by an accompanying postproc call. It has
an EnvKey.args
, which are the arguments to the postproc call, and so
it's a little bit like a closure or a delayed thunk.
It's awkward because you have to manually call the postproc, which then has to extract the args and re-typecheck them. I considered storing actual thunks as functions, and running a generic postproc which forces them, but I think each one is likely to require a different context. E.g. previous and next events for the same instrument, or with the same hand, or map over groups of events, etc. TODO wait until I have more experience.
TODO this stuff is now unused, but maybe I'll find a use for it again some day.
delayed_event :: [DeriveT.Val] -> Score.Event -> Score.Event Source #
delayed_args :: Expr.Symbol -> Score.Event -> Maybe [DeriveT.Val] Source #
Return the args if this is a delayed event created by the given call.
modify events
put_environ :: Typecheck.ToVal a => EnvKey.Key -> a -> Score.Event -> Either Text Score.Event Source #
Like add_environ
, but check the type.
add_environ :: Typecheck.ToVal a => EnvKey.Key -> a -> Score.Event -> Score.Event Source #
:: (ScoreT.Instrument, Instrument) | unaliased instrument name, from |
-> Score.Event | |
-> Score.Event |
misc
add_event_stack :: Score.Event -> Log.Msg -> Log.Msg Source #
Like with_event_stack
, but directly add the event's innermost
stack to a log msg.
TODO unused