Safe Haskell | None |
---|

Generic functions over vectors of `Sample`

s.

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

- x_to_double :: X -> Double
- double_to_x :: Double -> X
- type Boxed y = Vector.Vector (Sample y)
- type Unboxed = Storable.Vector (Sample UnboxedY)
- type UnboxedY = Double
- to_foreign_ptr :: Storable a => Storable.Vector a -> (ForeignPtr a, Int)
- with_ptr :: Storable a => Storable.Vector a -> (Ptr a -> IO b) -> IO b
- index :: V.Vector v a => v a -> Int -> a
- head :: V.Vector v a => v a -> Maybe a
- last :: V.Vector v a => v a -> Maybe a
- uncons :: V.Vector v a => v a -> Maybe (a, v a)
- signal :: V.Vector v (Sample y) => [(X, y)] -> v (Sample y)
- unsignal :: V.Vector v (Sample y) => v (Sample y) -> [(X, y)]
- unsignal_unique :: V.Vector v (Sample y) => v (Sample y) -> [(X, y)]
- set :: V.Vector v (Sample y) => Maybe y -> X -> y -> v (Sample y)
- constant :: V.Vector v (Sample y) => y -> v (Sample y)
- constant_val :: Unboxed -> Maybe UnboxedY
- to_pair :: Sample y -> (X, y)
- check :: V.Vector v (Sample y) => v (Sample y) -> [String]
- merge :: V.Vector v (Sample y) => [v (Sample y)] -> v (Sample y)
- merge_right :: V.Vector v (Sample y) => [v (Sample y)] -> v (Sample y)
- merge_left :: V.Vector v (Sample y) => [v (Sample y)] -> v (Sample y)
- interleave :: V.Vector v (Sample y) => v (Sample y) -> v (Sample y) -> v (Sample y)
- prepend :: V.Vector v (Sample y) => v (Sample y) -> v (Sample y) -> v (Sample y)
- at :: V.Vector v (Sample y) => X -> v (Sample y) -> Maybe y
- sample_at :: V.Vector v (Sample y) => X -> v (Sample y) -> Maybe (X, y)
- before :: V.Vector v (Sample y) => X -> v (Sample y) -> Maybe (Sample y)
- ascending :: V.Vector v (Sample y) => X -> v (Sample y) -> [Sample y]
- descending :: V.Vector v (Sample y) => X -> v (Sample y) -> [Sample y]
- shift :: V.Vector v (Sample y) => X -> v (Sample y) -> v (Sample y)
- drop_at_after :: V.Vector v (Sample y) => X -> v (Sample y) -> v (Sample y)
- drop_after :: V.Vector v (Sample y) => X -> v (Sample y) -> v (Sample y)
- drop_before :: V.Vector v (Sample y) => X -> v (Sample y) -> v (Sample y)
- drop_before_strict :: V.Vector v (Sample y) => X -> v (Sample y) -> v (Sample y)
- drop_before_at :: V.Vector v (Sample y) => X -> v (Sample y) -> v (Sample y)
- within :: V.Vector v (Sample y) => X -> X -> v (Sample y) -> v (Sample y)
- map_x :: V.Vector v (Sample y) => (X -> X) -> v (Sample y) -> v (Sample y)
- map_y :: V.Vector v (Sample y) => (y -> y) -> v (Sample y) -> v (Sample y)
- map_err :: V.Vector v a => (a -> Either err a) -> v a -> (v a, [err])
- sig_op :: V.Vector v (Sample y) => y -> (y -> y -> y) -> v (Sample y) -> v (Sample y) -> v (Sample y)
- sig_op_poly :: y1 -> y2 -> (y1 -> y2 -> y3) -> Boxed y1 -> Boxed y2 -> Boxed y3
- 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)
- find_nonascending :: V.Vector v (Sample y) => v (Sample y) -> [(X, y)]
- unfoldr :: V.Vector v (Sample y) => (state -> Maybe ((X, y), state)) -> state -> v (Sample y)
- y_at :: CallStack.Stack => X -> Double -> X -> Double -> X -> Double
- x_at :: X -> Double -> X -> Double -> Double -> Maybe X
- lowest_index :: V.Vector v (Sample y) => X -> v (Sample y) -> Int
- highest_index :: V.Vector v (Sample y) => X -> v (Sample y) -> Int
- bsearch_above :: V.Vector v (Sample y) => X -> v (Sample y) -> Int
- concat_map_accum :: UnboxedY -> (accum -> X -> UnboxedY -> X -> UnboxedY -> (accum, [Sample UnboxedY])) -> (accum -> Sample UnboxedY -> [Sample UnboxedY]) -> accum -> Unboxed -> Unboxed
- module Util.TimeVectorStorable
- module Data.Vector.Generic

# Documentation

x_to_double :: X -> Double Source #

double_to_x :: Double -> X Source #

type Boxed y = Vector.Vector (Sample y) Source #

# unboxed

to_foreign_ptr :: Storable a => Storable.Vector a -> (ForeignPtr a, Int) Source #

# implementation

## TimeVector specific

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

Construct a TimeVector from a list.

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

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_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 `merge`

d, 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_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_err :: V.Vector v a => (a -> Either err a) -> v a -> (v a, [err]) Source #

A map that can return error msgs.

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

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`

.

module Util.TimeVectorStorable

module Data.Vector.Generic

# Orphan instances

Pretty.Pretty y => Pretty.Pretty (Sample y) # | |