Safe Haskell | None |
---|

Sample values are doubles, which means each point in the signal is 8*2 bytes. The double resolution is overkill for the value, but float would be too small for time given the time stretching.

TODO split this into Float and Double versions since only Warp really needs Double. Or does Warp really need Double?

## Synopsis

- data Signal kind
- data Sample y = Sample {}
- type X = RealTime.RealTime
- type Y = Double
- x_to_y :: X -> Y
- y_to_x :: Y -> X
- y_to_score :: Y -> ScoreTime.ScoreTime
- y_to_nn :: Y -> Pitch.NoteNumber
- nn_to_y :: Pitch.NoteNumber -> Y
- type Tempo = Signal TempoSig
- type Warp = Signal WarpSig
- type Control = Signal ControlSig
- type NoteNumber = Signal NoteNumberSig
- type Display = Signal DisplaySig
- from_sample :: X -> Y -> Signal kind
- from_pairs :: [(X, Y)] -> Signal kind
- from_segments :: [Segment.Segment Y] -> Signal kind
- to_samples :: Signal kind -> [Sample Y]
- to_pairs :: Signal kind -> [(X, Y)]
- to_pairs_desc :: Signal kind -> [(X, Y)]
- to_segments :: Signal kind -> [Segment.Segment Y]
- to_vector :: Signal kind -> Vector.Vector (Sample Y)
- constant :: Y -> Signal kind
- constant_val :: Signal kind -> Maybe Y
- constant_val_from :: X -> Signal kind -> Maybe Y
- beginning :: RealTime.RealTime
- prepend :: Signal kind -> Signal kind -> Signal kind
- unfoldr :: (state -> Maybe ((X, Y), state)) -> state -> Signal kind
- coerce :: Signal kind1 -> Signal kind2
- to_piecewise_constant :: X -> Signal kind -> TimeVector.Unboxed
- with_ptr :: Display -> (X -> Ptr (Sample Y) -> Int -> IO a) -> IO a
- null :: Signal kind -> Bool
- at :: X -> Signal kind -> Y
- at_maybe :: X -> Signal kind -> Maybe Y
- segment_at :: X -> Signal kind -> Maybe (Segment.Segment Y)
- head :: Signal kind -> Maybe (X, Y)
- last :: Signal kind -> Maybe (X, Y)
- minimum :: Signal kind -> Y
- maximum :: Signal kind -> Y
- find :: (X -> Y -> Bool) -> Signal kind -> Maybe (X, Y)
- drop_after :: X -> Signal kind -> Signal kind
- drop_before :: X -> Signal kind -> Signal kind
- clip_after :: X -> Signal kind -> Signal kind
- clip_before :: X -> Signal kind -> Signal kind
- clip_before_segments :: X -> Signal kind -> [Segment.Segment Y]
- clip_before_pairs :: X -> Signal kind -> [(X, Y)]
- clip_after_keep_last :: X -> Signal kind -> Signal kind
- shift :: X -> Signal kind -> Signal kind
- invert :: Signal kind -> Signal kind
- sig_add :: Control -> Control -> Control
- sig_subtract :: Control -> Control -> Control
- sig_multiply :: Control -> Control -> Control
- sig_scale :: Control -> Control -> Control
- scale :: Y -> Y -> Y
- scale_invert :: Y -> Y -> Y
- drop_discontinuity_at :: X -> Control -> Control
- scalar_max :: Y -> Signal kind -> Signal kind
- scalar_add :: Y -> Signal kind -> Signal kind
- scalar_subtract :: Y -> Signal kind -> Signal kind
- scalar_multiply :: Y -> Signal kind -> Signal kind
- scalar_divide :: Y -> Signal kind -> Signal kind
- scalar_scale :: Y -> Signal kind -> Signal kind
- map_x :: (X -> X) -> Signal kind -> Signal kind
- map_y :: X -> (Y -> Y) -> Signal kind -> Signal kind
- map_y_linear :: (Y -> Y) -> Signal kind -> Signal kind
- map_err :: (Sample Y -> Either err (Sample Y)) -> Signal kind -> (Signal kind, [err])
- integrate_inverse :: Tempo -> Warp
- integrate :: Tempo -> Warp
- tempo_srate :: X

# types

A Signal is a `Segment.Signal`

of `Y`

values, which are just Doubles. It
takes a phantom type parameter to make the signal's intended uses a little
clearer. There are type aliases for the various flavors of signal below,
but it really is just documentation and anyone who wants to operate on
a generic signal can take a `Signal kind`

.

#### Instances

#### Instances

Eq y => Eq (Sample y) # | |

Show y => Show (Sample y) # | |

Storable (Sample Double) # | |

Defined in Util.TimeVectorStorable sizeOf :: Sample Double -> Int # alignment :: Sample Double -> Int # peekElemOff :: Ptr (Sample Double) -> Int -> IO (Sample Double) # pokeElemOff :: Ptr (Sample Double) -> Int -> Sample Double -> IO () # peekByteOff :: Ptr b -> Int -> IO (Sample Double) # pokeByteOff :: Ptr b -> Int -> Sample Double -> IO () # | |

CStorable (Sample Double) # | |

Defined in Util.TimeVectorStorable sizeOf :: Sample Double -> Int # alignment :: Sample Double -> Int # peekElemOff :: Ptr (Sample Double) -> Int -> IO (Sample Double) # pokeElemOff :: Ptr (Sample Double) -> Int -> Sample Double -> IO () # peekByteOff :: Ptr b -> Int -> IO (Sample Double) # pokeByteOff :: Ptr b -> Int -> Sample Double -> IO () # | |

ToJSON (Sample Double) # | |

FromJSON (Sample Double) # | |

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

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

type X = RealTime.RealTime Source #

y_to_score :: Y -> ScoreTime.ScoreTime Source #

Some control signals may be interpreted as score time.

y_to_nn :: Y -> Pitch.NoteNumber Source #

nn_to_y :: Pitch.NoteNumber -> Y Source #

type Tempo = Signal TempoSig Source #

A tempo is a normal Control signal, except that instead of going into the control map, it gets turned into a Warp and goes into the warp map.

type Warp = Signal WarpSig Source #

A tempo warp maps score time to real time. Of course the type is still (ScoreTime, Y), so functions that process Warps have to convert.

type Control = Signal ControlSig Source #

This is the type of performer-interpreted controls that go into the event's control map.

type NoteNumber = Signal NoteNumberSig Source #

This is the type of pitch signals used by the performer, after the scale has been factored out.

type Display = Signal DisplaySig Source #

This is the type of signals which are sent to the UI for display.

# construct / destruct

from_segments :: [Segment.Segment Y] -> Signal kind Source #

to_segments :: Signal kind -> [Segment.Segment Y] Source #

to_piecewise_constant :: X -> Signal kind -> TimeVector.Unboxed Source #

# query

segment_at :: X -> Signal kind -> Maybe (Segment.Segment Y) Source #

# transform

clip_before_segments :: X -> Signal kind -> [Segment.Segment Y] Source #

clip_after_keep_last :: X -> Signal kind -> Signal kind Source #

Like `clip_after`

, but always put a sample at the end time, even if it's
flat. This is not necessary if you keep this as a Signal since (<>) will
extend the final sample, but might be if you go to breakpoints via
`to_pairs`

.

## hacks

## scalar transformation

scalar_max :: Y -> Signal kind -> Signal kind Source #

Clip signal to never go below the given value.

This is way more complicated than the piecewise constant version.

map_x :: (X -> X) -> Signal kind -> Signal kind Source #

Map Xs. The slopes will definitely change unless the function is adding a constant, but presumably that's what you want.

map_y :: X -> (Y -> Y) -> Signal kind -> Signal kind Source #

Map Ys. This resamples the signal, so it's valid for a nonlinear function.

map_y_linear :: (Y -> Y) -> Signal kind -> Signal kind Source #

If the function is linear, there's no need to resample.

# special functions

integrate_inverse :: Tempo -> Warp Source #

integrate :: Tempo -> Warp Source #

Integrate the signal.

Since the output will have more samples than the input, this needs a sampling rate. The sampling rate determines the resolution of the tempo track. So it can probably be fairly low resolution before having a noticeable impact.

TODO this is only called after map_y at srate, so it's already been resampled. Maybe it would be more efficient to remove srate from Segment.integrate.

tempo_srate :: X Source #