Karya, built on Sun Nov 26 01:04:37 PST 2017 (patch 0a920b2bde70c0cbac8ee09d158064798b61bbe5)

Safe HaskellNone

Util.TimeVector

Contents

Description

Generic functions over vectors of Samples.

The samples should be sorted, though this is currently not enforced by the constructors.

The meaning of the samples is defined by the at implementation. Each sample starts at its time and extends up to, but not including, the next sample. Therefore if there are multiple samples at the same time, only the last one is visible.

There is a special rule that says a sample at <=0 is considered to extend backwards indefinitely. So at (-1) [(1, 1)] is 0, but at (-1) [(0, 1)] is 1. This is weird and I've gone back and forth a couple times on the design so I should document how this came up.

The idea is that some calls will move events back in time (e.g. grace notes). If the call starts at 0, the events will start at negative time. Controls start at 0, so these events will have no pitch and no controls. Even if the pitch is set explicitly via constant, it still starts at 0. I could solve the problem with constant by starting it at -bignum, but that doesn't help for control tracks, which still start at 0.

Since tracks provide no way to say what the value should be before they start, I have to do something implicit (well, technically they could, but it seems awkward). So the idea is that a sample at 0 gives the value for negative times as well. Actually the implementation is <=0, since it seems weird that translating a signal back from 0 would change its meaning. This still leaves a bit of weirdness where translating a signal back from positive to will change its definition when it crosses 0. Hopefully this won't be a problem in practice.

This solves the problem for constant and for tracks in the same way, and doesn't result in any ugly arbitrary -bignum values suddenly showing up in signals.

NOTE [signal-discontinuity] TODO

Synopsis

Documentation

unboxed

with_ptr :: Storable a => Storable.Vector a -> (Ptr a -> IO b) -> IO b Source #

implementation

index :: V.Vector v a => v a -> Int -> a Source #

head :: V.Vector v a => v a -> Maybe a Source #

last :: V.Vector v a => v a -> Maybe a Source #

uncons :: V.Vector v a => v a -> Maybe (a, v a) Source #

TimeVector specific

signal :: V.Vector v (Sample y) => [(X, y)] -> v (Sample y) Source #

Construct a TimeVector from a list.

unsignal :: V.Vector v (Sample y) => v (Sample y) -> [(X, y)] Source #

unsignal_unique :: V.Vector v (Sample y) => v (Sample y) -> [(X, y)] Source #

Like unsignal, but filter out explicit discontinuities, so each X is unique. This is for tests, where they're just clutter if I'm not explicitly testing them. NOTE [signal-discontinuity]

set :: V.Vector v (Sample y) => Maybe y -> X -> y -> v (Sample y) Source #

Set the signal value, with a discontinuity. See NOTE [signal-discontinuity].

constant :: V.Vector v (Sample y) => y -> v (Sample y) Source #

to_pair :: Sample y -> (X, y) Source #

check :: V.Vector v (Sample y) => v (Sample y) -> [String] Source #

TimeVectors should be sorted by the X value. Return warnings for where that's not true.

merge :: V.Vector v (Sample y) => [v (Sample y)] -> v (Sample y) Source #

merge_right :: V.Vector v (Sample y) => [v (Sample y)] -> v (Sample y) Source #

This is a merge where the vectors to the right will win in the case of overlap.

merge_left :: V.Vector v (Sample y) => [v (Sample y)] -> v (Sample y) Source #

This is a merge where the vectors to the left will win in the case of overlap.

interleave :: V.Vector v (Sample y) => v (Sample y) -> v (Sample y) -> v (Sample y) Source #

Merge two vectors, interleaving their samples. Analogous to union, if two samples coincide, the one from the first vector wins. TODO this doesn't work with signal-discontinuity and is sketchy anyway

prepend :: V.Vector v (Sample y) => v (Sample y) -> v (Sample y) -> v (Sample y) Source #

When signals are merged, the later one overrides the first one. This is the other way: the first one will override the second.

at :: V.Vector v (Sample y) => X -> v (Sample y) -> Maybe y Source #

Same as sample_at, except don't return the X.

sample_at :: V.Vector v (Sample y) => X -> v (Sample y) -> Maybe (X, y) Source #

Find the sample at or before X. Nothing if the X is before the first sample.

There is a special rule that says a sample at <=0 is considered to extend backwards indefinitely. So at (-1) [(1, 1)] is 0, but at (-1) [(0, 1)] is 1. More documentation in the module haddock.

before :: V.Vector v (Sample y) => X -> v (Sample y) -> Maybe (Sample y) Source #

Find the sample before the given X.

ascending :: V.Vector v (Sample y) => X -> v (Sample y) -> [Sample y] Source #

Samples at and above the given time.

descending :: V.Vector v (Sample y) => X -> v (Sample y) -> [Sample y] Source #

Descending samples, starting below the time.

transform

shift :: V.Vector v (Sample y) => X -> v (Sample y) -> v (Sample y) Source #

Shift the signal in time.

drop_at_after :: V.Vector v (Sample y) => X -> v (Sample y) -> v (Sample y) Source #

Truncate a signal so it doesn't include the given X - RealTime.eta. It's just a view of the old signal, so it doesn't allocate a new signal.

If the x<=0 the signal will still contain up to and including 0. That's because, as per the module haddock, a sample <=0 stands in for all values <=0.

drop_after :: V.Vector v (Sample y) => X -> v (Sample y) -> v (Sample y) Source #

drop_before :: V.Vector v (Sample y) => X -> v (Sample y) -> v (Sample y) Source #

Like drop_before_strict, except if there is no sample at x, keep one sample before it to preserve the value at x. If there are multiple samples at x, drop all but the last one. This is because they indicate a discontinuity, but if you don't care about the previous value, then you don't need the discontinuity.

drop_before_strict :: V.Vector v (Sample y) => X -> v (Sample y) -> v (Sample y) Source #

The reverse of drop_at_after: trim a signal's head up until, but not including, the given X.

drop_before_at :: V.Vector v (Sample y) => X -> v (Sample y) -> v (Sample y) Source #

Like drop_before_strict, but also drop samples at the X.

within :: V.Vector v (Sample y) => X -> X -> v (Sample y) -> v (Sample y) Source #

Return samples to set the value at start and until end. This means samples start <= t < end, along with one < start if necessary to set the initial value, and the end sample if start == end.

map_x :: V.Vector v (Sample y) => (X -> X) -> v (Sample y) -> v (Sample y) Source #

map_y :: V.Vector v (Sample y) => (y -> y) -> v (Sample y) -> v (Sample y) Source #

map_err :: V.Vector v a => (a -> Either err a) -> v a -> (v a, [err]) Source #

A map that can return error msgs.

sig_op Source #

Arguments

:: V.Vector v (Sample y) 
=> y

the implicit y value of a vector before its first sample

-> (y -> y -> y) 
-> v (Sample y) 
-> v (Sample y) 
-> v (Sample y) 

Combine two vectors with the given function. They will be resampled so they have samples at the same time.

sig_op_poly :: y1 -> y2 -> (y1 -> y2 -> y3) -> Boxed y1 -> Boxed y2 -> Boxed y3 Source #

Polymorphic variant of sig_op.

The signature is specialized to Boxed since you might as well use sig_op for Unboxed vectors.

resample1 :: (V.Vector v1 (Sample y1), V.Vector v2 (Sample y2)) => y1 -> y2 -> Int -> Int -> Int -> Int -> v1 (Sample y1) -> v2 (Sample y2) -> Maybe (X, y1, y2, Int, Int) Source #

util

find_nonascending :: V.Vector v (Sample y) => v (Sample y) -> [(X, y)] Source #

Find samples whose sx is <= the previous X.

unfoldr :: V.Vector v (Sample y) => (state -> Maybe ((X, y), state)) -> state -> v (Sample y) Source #

y_at :: CallStack.Stack => X -> Double -> X -> Double -> X -> Double Source #

Given a line defined by the two points, find the y at the given x. Crashes if called on a vertical line (y0==y1). Yeah, it's inconsistent with x_at.

x_at :: X -> Double -> X -> Double -> Double -> Maybe X Source #

Given a line defined by the two points, find the x at the given y.

lowest_index :: V.Vector v (Sample y) => X -> v (Sample y) -> Int Source #

Binary search for the lowest index of the given X, or where it would be if it were present. So the next value is guaranteed to be >=X.

lowest_index_1 :: V.Vector v (Sample y) => X -> v (Sample y) -> Int Source #

highest_index :: V.Vector v (Sample y) => X -> v (Sample y) -> Int Source #

Binary search for the highest index of the given X. So the next value is guaranteed to be >X, if it exists. Return -1 if x is before the first element. RealTime.eta is added to x, so a sample that's almost the same will still be considered a match.

bsearch_above :: V.Vector v (Sample y) => X -> v (Sample y) -> Int Source #

This gets the index of the value *after* x.

concat_map_accum Source #

Arguments

:: UnboxedY 
-> (accum -> X -> UnboxedY -> X -> UnboxedY -> (accum, [Sample UnboxedY]))

Take the previous accum, previous x and y, and current x and y.

-> (accum -> Sample UnboxedY -> [Sample UnboxedY])

Given the final (accum, Sample), produce samples to append.

-> accum 
-> Unboxed 
-> Unboxed 

signal-discontinuity

at_before :: V.Vector v (Sample y) => X -> v (Sample y) -> Maybe y Source #

This is like at, but if there is a discontinuity, this is the value before the discontinuity. So if you have (1, 0), (1, 1) and ask for 1, this will be 0, not 1.

sample_at_before :: V.Vector v (Sample y) => X -> v (Sample y) -> Maybe (X, y) Source #

clip_to :: V.Vector v (Sample y) => X -> v (Sample y) -> v (Sample y) Source #

append_extend :: V.Vector v (Sample y) => v (Sample y) -> v (Sample y) -> v (Sample y) Source #

merge_right_extend :: V.Vector v (Sample y) => [v (Sample y)] -> v (Sample y) Source #

This is like merge_right except assuming NOTE [signal-discontinuity]. If the first signal is cut off by the second, its last sample will be extended up to the cut-off point.

TODO this should probably replace merge_right. But I should really have an organized design around line segments, and not this ad-hoc thing where everyone has to manually remember to treat Samples right.

strip :: Eq y => V.Vector v (Sample y) => v (Sample y) -> v (Sample y) Source #

Strip out samples that don't have any effect.

TODO verify that the intermediate list is eliminated

Orphan instances