synthesizer-llvm-0.7.0.1: Efficient signal processing using runtime compilation

Safe HaskellNone
LanguageHaskell98

Synthesizer.LLVM.CausalParameterized.Process

Synopsis

Documentation

data T p a b Source

Constructors

forall context state ioContext parameters . (Storable parameters, MakeValueTuple parameters, C (ValueTuple parameters), C context, C state) => Cons (forall r c. Phi c => context -> a -> state -> T r c (b, state)) (forall r. ValueTuple parameters -> CodeGenFunction r (context, state)) (forall r. context -> state -> CodeGenFunction r ()) (p -> IO (ioContext, parameters)) (ioContext -> IO ()) 

Instances

Category * (T p) 
Arrow (T p) 
C (T p) 
C (T p) 
Functor (T p a) 
Applicative (T p a) 
(Field b, Real b, RationalConstant b) => Fractional (T p a b) 
(PseudoRing b, Real b, IntegerConstant b) => Num (T p a b) 
(Field b, RationalConstant b) => C (T p a b) 
(PseudoRing b, IntegerConstant b) => C (T p a b) 
Additive b => C (T p a b) 
type SignalOf (T p) = T p 

simple :: (Storable parameters, MakeValueTuple parameters, ValueTuple parameters ~ paramValue, C paramValue, C context, C state) => (forall r c. Phi c => context -> a -> state -> T r c (b, state)) -> (forall r. paramValue -> CodeGenFunction r (context, state)) -> T p parameters -> T p a b Source

fromSignal :: T p b -> T p a b Source

toSignal :: T p () a -> T p a Source

mapAccum :: (Storable pnh, MakeValueTuple pnh, ValueTuple pnh ~ pnl, C pnl, Storable psh, MakeValueTuple psh, ValueTuple psh ~ psl, C psl, C s) => (forall r. pnl -> a -> s -> CodeGenFunction r (b, s)) -> (forall r. psl -> CodeGenFunction r s) -> T p pnh -> T p psh -> T p a b Source

map :: (Storable ph, MakeValueTuple ph, ValueTuple ph ~ pl, C pl) => (forall r. pl -> a -> CodeGenFunction r b) -> T p ph -> T p a b Source

mapSimple :: (forall r. a -> CodeGenFunction r b) -> T p a b Source

zipWith :: (Storable ph, MakeValueTuple ph, ValueTuple ph ~ pl, C pl) => (forall r. pl -> a -> b -> CodeGenFunction r c) -> T p ph -> T p (a, b) c Source

zipWithSimple :: (forall r. a -> b -> CodeGenFunction r c) -> T p (a, b) c Source

apply :: T p a b -> T p a -> T p b Source

compose :: T p a b -> T p b c -> T p a c Source

first :: Arrow a => forall b c d. a b c -> a (b, d) (c, d)

Send the first component of the input through the argument arrow, and copy the rest unchanged to the output.

feedFst :: T p a -> T p b (a, b) Source

feedSnd :: T p a -> T p b (b, a) Source

loop :: (Storable c, MakeValueTuple c, ValueTuple c ~ cl, C cl) => T p c -> T p (a, cl) (b, cl) -> T p a b Source

Not quite the loop of ArrowLoop because we need a delay of one time step and thus an initialization value.

For a real ArrowLoop.loop, that is a zero-delay loop, we would formally need a MonadFix instance of CodeGenFunction. But this will not become reality, since LLVM is not able to re-order code in a way that allows to access a result before creating the input.

loopZero :: (C process, Additive c, C c) => process (a, c) (b, c) -> process a b Source

Like loop but uses zero as initial value and it does not need a zero as Haskell value.

take :: T p Int -> T p a a Source

takeWhile :: (Storable ph, MakeValueTuple ph, ValueTuple ph ~ pl, C pl) => (forall r. pl -> a -> CodeGenFunction r (Value Bool)) -> T p ph -> T p a a Source

integrate :: (Storable a, Additive al, MakeValueTuple a, ValueTuple a ~ al, C al) => T p a -> T p al al Source

The first output value is the initial value. Thus integrate delays by one sample compared with integrateSync.

($<) :: T p (a, b) c -> T p a -> T p b c infixl 0 Source

($>) :: T p (a, b) c -> T p b -> T p a c infixl 0 Source

($*) :: T p a b -> T p a -> T p b infixl 0 Source

applyFst :: T p (a, b) c -> T p a -> T p b c Source

applySnd :: T p (a, b) c -> T p b -> T p a c Source

reparameterize :: T q p -> T p a b -> T q a b Source

mapAccumSimple :: C s => (forall r. a -> s -> CodeGenFunction r (b, s)) -> (forall r. CodeGenFunction r s) -> T p a b Source

replicateControlled :: (Undefined x, Phi x) => T p Int -> T p (c, x) x -> T p (c, x) x Source

serial replication

But you may also use it for a parallel replication, see replicateParallel.

replicateParallel :: (Undefined b, Phi b) => T p Int -> T p b -> T p (b, b) b -> T p a b -> T p a b Source

replicateControlledParam :: (Undefined x, Phi x) => (forall q. T q p -> T q a -> T q (c, x) x) -> T p [a] -> T p (c, x) x Source

feedbackControlled :: (Storable ch, MakeValueTuple ch, ValueTuple ch ~ c, C c) => T p ch -> T p ((ctrl, a), c) b -> T p (ctrl, b) c -> T p (ctrl, a) b Source

feedbackControlledZero :: (C process, Additive c, C c) => process ((ctrl, a), c) b -> process (ctrl, b) c -> process (ctrl, a) b Source

fromModifier :: C process => (Flatten ah, Registers ah ~ al, Flatten bh, Registers bh ~ bl, Flatten ch, Registers ch ~ cl, Flatten sh, Registers sh ~ sl, C sl) => Simple sh ch ah bh -> process (cl, al) bl Source

stereoFromMono :: (Phi a, Phi b, Undefined b) => T p a b -> T p (T a) (T b) Source

Run a causal process independently on each stereo channel.

stereoFromMonoControlled :: (Phi a, Phi b, Phi c, Undefined b) => T p (c, a) b -> T p (c, T a) (T b) Source

stereoFromMonoParameterized :: (Phi a, Phi b, Undefined b) => (forall q. T q p -> T q x -> T q a b) -> T p (T x) -> T p (T a) (T b) Source

stereoFromVector :: (C process, IsPrimitive a, IsPrimitive b) => process (Value (Vector D2 a)) (Value (Vector D2 b)) -> process (T (Value a)) (T (Value b)) Source

vectorize :: (C process, Positive n, C x, T x ~ a, T n x ~ va, C y, T y ~ b, T n y ~ vb) => process a b -> process va vb Source

replaceChannel :: (C process, Positive n, C x, T x ~ a, T n x ~ va, C y, T y ~ b, T n y ~ vb) => Int -> process a b -> process va vb -> process va vb Source

Given a vector process, replace the i-th output by output that is generated by a scalar process from the i-th input.

arrayElement :: (C process, IsFirstClass a, Natural index, Natural dim, index :<: dim) => Proxy index -> process (Value (Array dim a)) (Value a) Source

Read the i-th element from each array.

element :: (C process, IsFirstClass a, GetValue agg index, ValueType agg index ~ a) => index -> process (Value agg) (Value a) Source

Read the i-th element from an aggregate type.

mix :: (C process, Additive a) => process (a, a) a Source

You may also use '(+)'.

raise :: (Additive al, Storable a, MakeValueTuple a, ValueTuple a ~ al, C al) => T p a -> T p al al Source

You may also use '(+)' and a constant signal or a number literal.

envelope :: (C process, PseudoRing a) => process (a, a) a Source

You may also use '(*)'.

envelopeStereo :: (C process, PseudoRing a) => process (a, T a) (T a) Source

amplify :: (PseudoRing al, Storable a, MakeValueTuple a, ValueTuple a ~ al, C al) => T p a -> T p al al Source

You may also use '(*)' and a constant signal or a number literal.

amplifyStereo :: (PseudoRing al, Storable a, MakeValueTuple a, ValueTuple a ~ al, C al) => T p a -> T p (T al) (T al) Source

mapLinear :: (IsArithmetic a, Storable a, FirstClass a, Stored a ~ am, IsSized am, MakeValueTuple a, ValueTuple a ~ Value a) => T p a -> T p a -> T p (Value a) (Value a) Source

quantizeLift :: (C b, Storable c, MakeValueTuple c, ValueTuple c ~ Value cl, IntegerConstant cl, IsFloating cl, CmpRet cl, CmpResult cl ~ Bool, FirstClass cl, Stored cl ~ cm, IsSized cm) => T p c -> T p a b -> T p a b Source

quantizeLift k f applies the process f to every kth sample and repeats the result k times.

Like interpolateConstant this function can be used for computation of filter parameters at a lower rate. This can be useful, if you have a frequency control signal at sample rate that shall be used both for an oscillator and a frequency filter.

osciSimple :: (FirstClass t, Stored t ~ tm, IsSized tm, Fraction t) => (forall r. Value t -> CodeGenFunction r y) -> T p (Value t, Value t) y Source

osciCore :: (C process, C t, Fraction t) => process (t, t) t Source

Compute the phases from phase distortions and frequencies.

It's like integrate but with wrap-around performed by fraction. For FM synthesis we need also negative phase distortions, thus we use addToPhase which supports that.

osciCoreSync :: (C process, C t, Fraction t) => process (t, t) t Source

Compute the phases from phase distortions and frequencies.

It's like integrate but with wrap-around performed by fraction. For FM synthesis we need also negative phase distortions, thus we use addToPhase which supports that.

shapeModOsci :: (C process, C t, Fraction t) => (forall r. c -> t -> CodeGenFunction r y) -> process (c, (t, t)) y Source

delay :: (Storable a, MakeValueTuple a, ValueTuple a ~ al, C al) => T p a -> T p Int -> T p al al Source

Delay time must be non-negative.

The initial value is needed in order to determine the ring buffer element type.

delayZero :: (C a, Additive a) => T p Int -> T p a a Source

delay1 :: (Storable a, MakeValueTuple a, ValueTuple a ~ al, C al) => T p a -> T p al al Source

Delay by one sample. For very small delay times (say up to 8) it may be more efficient to apply delay1 several times or to use a pipeline, e.g. pipeline (id :: T (Vector D4 Float) (Vector D4 Float)) delays by 4 samples in an efficient way. In principle it would be also possible to use unpack (delay1 (const $ toVector (0,0,0,0))) but unpack causes an additional delay. Thus unpack (id :: T (Vector D4 Float) (Vector D4 Float)) may do, what you want.

delay1Zero :: (C process, Additive a, C a) => process a a Source

delayControlled :: (Storable a, MakeValueTuple a, ValueTuple a ~ al, C al) => T p a -> T p Int -> T p (Value Word32, al) al Source

Delay by a variable amount of samples. The momentum delay must be between 0 and maxTime, inclusively.

delayControlledInterpolated :: (C nodes, Storable vh, MakeValueTuple vh, ValueTuple vh ~ v, C v, IsFloating a, NumberOfElements a ~ D1) => (forall r. T r nodes (Value a) v) -> T p vh -> T p Int -> T p (Value a, v) v Source

Delay by a variable fractional amount of samples. Non-integer delays are achieved by linear interpolation. The momentum delay must be between 0 and maxTime, inclusively.

differentiate :: (Additive al, Storable a, MakeValueTuple a, ValueTuple a ~ al, C al) => T p a -> T p al al Source

comb :: (PseudoRing al, Storable a, MakeValueTuple a, ValueTuple a ~ al, C al) => T p a -> T p Int -> T p al al Source

Delay time must be greater than zero!

combStereo :: (PseudoRing al, Storable a, MakeValueTuple a, ValueTuple a ~ al, C al) => T p a -> T p Int -> T p (T al) (T al) Source

reverb :: (Random a, IsArithmetic a, RationalConstant a, MakeValueTuple a, ValueTuple a ~ Value a, Storable a, FirstClass a, Stored a ~ am, IsSized am, RandomGen g) => g -> Int -> (a, a) -> (Int, Int) -> T p (Value a) (Value a) Source

Example: apply a stereo reverb to a mono sound.

traverse
   (\seed -> reverb (Random.mkStdGen seed) 16 (0.92,0.98) (200,1000))
   (Stereo.cons 42 23)

reverbEfficient :: (Random a, PseudoModule a, Scalar a ~ s, IsFloating s, IntegerConstant s, NumberOfElements s ~ D1, MakeValueTuple a, ValueTuple a ~ Value a, Storable a, FirstClass a, Stored a ~ am, IsSized am, RandomGen g) => T p g -> T p Int -> T p (a, a) -> T p (Int, Int) -> T p (Value a) (Value a) Source

pipeline :: (C process, Positive n, C x, v ~ T n x, a ~ T x, Zero v, C v) => process v v -> process a a Source

This allows to compute a chain of equal processes efficiently, if all of these processes can be bundled in one vectorial process. Applications are an allpass cascade or an FM operator cascade.

The function expects that the vectorial input process works like parallel scalar processes. The different pipeline stages may be controlled by different parameters, but the structure of all pipeline stages must be equal. Our function feeds the input of the pipelined process to the zeroth element of the Vector. The result of processing the i-th element (the i-th channel, so to speak) is fed to the (i+1)-th element. The (n-1)-th element of the vectorial process is emitted as output of the pipelined process.

The pipeline necessarily introduces a delay of (n-1) values. For simplification we extend this to n values delay. If you need to combine the resulting signal from the pipeline with another signal in a zip-like way, you may delay that signal with pipeline id. The first input values in later stages of the pipeline are initialized with zero. If this is not appropriate for your application, then we may add a more sensible initialization.

skip :: (C process, SignalOf process ~ signal, Undefined v, Phi v, C v) => signal v -> process (Value Word32) v Source

Feeds a signal into a causal process while holding or skipping signal elements according to the process input. The skip happens after a value is passed from the fed signal.

skip x $* 0 repeats the first signal value in the output. skip x $* 1 feeds the signal to the output as is. skip x $* 2 feeds the signal to the output with double speed.

frequencyModulation :: (C process, SignalOf process ~ signal, IntegerConstant a, IsFloating a, CmpRet a, CmpResult a ~ Bool, FirstClass a, Stored a ~ am, IsSized am, Undefined nodes, Phi nodes, C nodes) => (forall r. Value a -> nodes -> CodeGenFunction r v) -> signal nodes -> process (Value a) v Source

frequencyModulationLinear :: (IntegerConstant a, IsFloating a, CmpRet a, CmpResult a ~ Bool, FirstClass a, Stored a ~ am, IsSized am) => T p (Value a) -> T p (Value a) (Value a) Source

frequencyModulationLinear signal

is a causal process mapping from a shrinking factor to the modulated input signal. Similar to interpolateConstant but the factor is reciprocal and controllable and we use linear interpolation. The shrinking factor must be non-negative.

trigger :: (Storable a, MakeValueTuple a, ValueTuple a ~ al, C al, Undefined b, Phi b) => (forall q. T q p -> T q a -> T q b) -> T p (T al) (T b) Source

trigger fill signal send signal to the output and restart it whenever the Boolean process input is True. Before the first occurrence of True and between instances of the signal the output is filled with nothing.

Every restart of the signal needs a call into Haskell code. Thus it is certainly a good idea, not to trigger the signal too frequently.

runStorable :: (Storable a, MakeValueTuple a, ValueTuple a ~ valueA, C valueA, Storable b, MakeValueTuple b, ValueTuple b ~ valueB, C valueB) => T p valueA valueB -> IO (p -> Vector a -> Vector b) Source

applyStorable :: (Storable a, MakeValueTuple a, ValueTuple a ~ valueA, C valueA, Storable b, MakeValueTuple b, ValueTuple b ~ valueB, C valueB) => T p valueA valueB -> p -> Vector a -> Vector b Source

runStorableChunky :: (Storable a, MakeValueTuple a, ValueTuple a ~ valueA, C valueA, Storable b, MakeValueTuple b, ValueTuple b ~ valueB, C valueB) => T p valueA valueB -> IO (p -> Vector a -> Vector b) Source

runStorableChunkyCont :: (Storable a, MakeValueTuple a, ValueTuple a ~ valueA, C valueA, Storable b, MakeValueTuple b, ValueTuple b ~ valueB, C valueB) => T p valueA valueB -> IO ((Vector a -> Vector b) -> p -> Vector a -> Vector b) Source

This function should be used instead of StorableVector.Lazy.Pattern.splitAt and subsequent append, because it does not have the risk of a memory leak.

applyStorableChunky :: (Storable a, MakeValueTuple a, ValueTuple a ~ valueA, C valueA, Storable b, MakeValueTuple b, ValueTuple b ~ valueB, C valueB) => T p valueA valueB -> p -> Vector a -> Vector b Source

processIO :: (Read a, Default a, Default d) => T p (Element a) (Element d) -> IO (p -> T a d) Source

processIOCore :: Read a => T a b -> T p b c -> T c d -> IO (p -> T a d) Source