Karya, built on Mon Jul 24 11:39:07 PDT 2017 (patch 33511aca01257b76b88de7c7a2763b7a965c084e)

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.

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.

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 within a range. This is a combination of drop_before and drop_at_after.

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.

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 

Orphan instances