Karya, built on 2018-05-31T02:46:59 (patch 0a1a35479c514820d77330ae8a978975ba22a47a)

Derive.Call.ControlUtil

Description

Utilities that emit Signal.Controls and ControlMods.

Synopsis

# Documentation

Sampling rate.

data CurveD Source #

Package up a curve name along with arguments.

Constructors

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

data Curve Source #

Constructors

 Function !(Double -> Double) Linear 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

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.

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

For calls whose curve can be configured.

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.

Stuff a curve function into a ControlFunction.

Convert a ControlFunction back into a curve function.

# interpolate

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

Interpolate between the given points.

# slope

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.

# exponential

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.

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

# bezier

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.

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

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

Arguments

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

Smooth with split_samples_relative.

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-------1-------0
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-------1-------0
0-----0=1-----1=0 time_at = const 0.25

# control mod

Arguments

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