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



Utilities that emit Signal.Controls and ControlMods.



type SRate = RealTime.RealTime Source #

Sampling rate.

data CurveD Source #

Package up a curve name along with arguments.


forall arg. CurveD !Text !(Sig.Parser arg) !(arg -> Curve) 

data Curve Source #


Function !(Double -> Double) 

Signals can represent linear segments directly, so if I keep track of them, I can use the efficient direct representation.

type CurveF = Double -> Double Source #

Interpolation function. This maps 0--1 to the desired curve, which is also normalized to 0--1.

interpolator call

type InterpolatorTime a = Either (Sig.Parser DeriveT.Duration) (GetTime a, Text) Source #

Left for an explicit time arg. Right is for an implicit time, inferred from the args, along with an extra bit of documentation to describe it.

from_env :: Sig.Parser (Maybe Signal.Y) Source #

Use this for calls that start from the previous value, to give a way to override that behaviour.

interpolator_variations_ :: Taggable a => (Text -> CurveD -> InterpolatorTime a -> call) -> Expr.Symbol -> CurveD -> [(Expr.Symbol, call)] Source #

Create the standard set of interpolator calls. Generic so it can be used by PitchUtil as well.

curve as argument

curve_env :: Sig.Parser Curve Source #

For calls whose curve can be configured.

cf_linear_name :: Text Source #

A ControlFunction is a generic function, so it can't retain the distinction between Function and Linear. So I use a grody hack and keep the distinction in a special name.

curve_to_cf :: Text -> Curve -> DeriveT.ControlFunction Source #

Stuff a curve function into a ControlFunction.

cf_to_curve :: DeriveT.ControlFunction -> Curve Source #

Convert a ControlFunction back into a curve function.


place_range :: Typecheck.Normalized -> ScoreTime -> DeriveT.Duration -> Deriver (RealTime.RealTime, RealTime.RealTime) Source #

Given a placement, start, and duration, return the range thus implied.

make_segment_from :: Curve -> RealTime.RealTime -> Maybe Signal.Y -> RealTime.RealTime -> Signal.Y -> Deriver Signal.Control Source #

Make a curve segment from the previous value, if there was one.

segment :: SRate -> Curve -> RealTime.RealTime -> Signal.Y -> RealTime.RealTime -> Signal.Y -> Signal.Control Source #

Interpolate between the given points.


slope_to_limit :: Maybe Signal.Y -> Maybe Signal.Y -> Signal.Y -> Double -> RealTime.RealTime -> RealTime.RealTime -> Signal.Control Source #

Make a line with a certain slope, with optional lower and upper limits. TODO I could support Curve but it would make the intercept more complicated.


expon :: Double -> CurveF Source #

Negative exponents produce a curve that jumps from the "starting point" which doesn't seem too useful, so so hijack the negatives as an easier way to write 1/n. That way n is smoothly departing, while -n is smoothly approaching.

expon2 :: Double -> Double -> CurveF Source #

I could probably make a nicer curve of this general shape if I knew more math.


guess_x :: (Double -> (Double, Double)) -> CurveF Source #

As far as I can tell, there's no direct way to know what value to give to the bezier function in order to get a specific x. So I guess with binary search. https://youtu.be/aVwxzDHniEw?t=1119

sigmoid :: Double -> Double -> CurveF Source #

Generate a sigmoid curve. The first weight is the flatness at the start, and the second is the flatness at the end. Both should range from 0--1.

bezier3 :: Point -> Point -> Point -> Point -> Double -> Point Source #

Cubic bezier curve.


breakpoints :: SRate -> Curve -> [(RealTime.RealTime, Signal.Y)] -> Signal.Control Source #

Create line segments between the given breakpoints.

signal_breakpoints :: Monoid sig => (RealTime.RealTime -> y -> sig) -> (RealTime.RealTime -> y -> RealTime.RealTime -> y -> sig) -> [(RealTime.RealTime, y)] -> sig Source #

distribute :: RealTime.RealTime -> RealTime.RealTime -> [a] -> [(RealTime.RealTime, a)] Source #

Distribute the values evenly over the given time range.


smooth_absolute Source #


:: Curve 
-> RealTime.RealTime 
-> RealTime.RealTime

If negative, each segment is from this much before the original sample until the sample. If positive, it starts on the sample. If samples are too close, the segments are shortened correspondingly.

-> [(RealTime.RealTime, Signal.Y)] 
-> Signal.Control 

Use the function to create a segment between each point in the signal. Smooth with split_samples_absolute.

split_samples_absolute :: RealTime.RealTime -> [(RealTime.RealTime, y)] -> [(RealTime.RealTime, y)] Source #

Split apart samples to make a flat segment.

TODO if y=Pitch there's no Eq, so breakpoints winds up sampling flat segments. I could emit Maybe y where Nothing means same as previous.

0 1 2 3 4 5 6 7 8
0-----0=1-----1=0      time = -1
0-------0=1-----1=0    time = 1

split_samples_relative :: Typecheck.Function -> [(RealTime.RealTime, y)] -> [(RealTime.RealTime, y)] Source #

Like smooth_absolute, but the transition time is a 0--1 proportion of the available time, rather than an absolute time. Also, the transition is always before the destination sample, unlike absolute, where it's only before for a negative transition time. This is because I can't transition after the sample, because the last sample has no next sample to take a proportional time from!

0 1 2 3 4 5 6 7 8
0-----0=1-----1=0 time_at = const 0.25

control mod

modify_with Source #


:: Merge 
-> ScoreT.Control 
-> RealTime.RealTime

Where the modification should end. I don't need a start time since signals already have an implicit start time.

-> Signal.Control 
-> Deriver () 

Modify the signal only in the given range.