-- Hoogle documentation, generated by Haddock
-- See Hoogle, http://www.haskell.org/hoogle/


-- | Audio signal processing with static physical dimensions
--   
--   High-level functions that use physical units and abstract from the
--   sample rate in a statically type safe way.
@package synthesizer-dimensional
@version 0.8.1

module Synthesizer.Dimensional.Amplitude

-- | Can be used as amplitude value for enumeration types such as
--   <a>Bool</a> and <a>Ordering</a> and other types, where a numeric
--   amplitude makes no sense. It is essential in <a>T</a>. It would be a
--   bad idea to omit the <tt>Abstract</tt> parameter in dimensional causal
--   processes since the correspondence between amplitude type and sample
--   type would be lost.
data Abstract
Abstract :: Abstract
newtype Numeric amp
Numeric :: amp -> Numeric amp
type Dimensional v y = Numeric (T v y)

-- | <tt>Flat y</tt> is quite the same as <tt>Dimensional Dim.Scalar y</tt>
--   but in some cases it allows a little more efficient processing. It
--   should not be mixed up with <tt>Abstract</tt>. <tt>Flat y</tt> is
--   reserved for numeric amplitudes.
data Flat y
Flat :: Flat y

-- | This class is used to make <a>mapAmplitude</a> both flexible and a bit
--   safe. Its instances are dimensional numbers <a>Numeric</a> and
--   <a>Abstract</a>. It should not be necessary to add more instances.
class C amp

-- | This class is used for <a>append</a> and <a>map</a> that expect that
--   the amplitude value does carry not more information than that
--   expressed by the type. It should not be necessary to add more
--   instances.
class Primitive amp
primitive :: Primitive amp => amp
instance Synthesizer.Dimensional.Amplitude.Primitive Synthesizer.Dimensional.Amplitude.Abstract
instance Synthesizer.Dimensional.Amplitude.Primitive (Synthesizer.Dimensional.Amplitude.Flat y)
instance Synthesizer.Dimensional.Amplitude.C Synthesizer.Dimensional.Amplitude.Abstract
instance Synthesizer.Dimensional.Amplitude.C (Synthesizer.Dimensional.Amplitude.Flat y)
instance Synthesizer.Dimensional.Amplitude.C (Synthesizer.Dimensional.Amplitude.Numeric amp)
instance GHC.Base.Functor Synthesizer.Dimensional.Amplitude.Numeric


-- | Treat a signal as period of a cyclic signal.
--   
--   ToDo: In principle this module does no longer belong to dimensional
--   package but could be moved to synthesizer-core.
module Synthesizer.Dimensional.Cyclic.Signal
newtype T period
Cons :: period -> T period

-- | the sampled values
[toPeriod] :: T period -> period
processPeriod :: (body0 -> body1) -> T body0 -> T body1
fromPeriod :: body -> T body

-- | Periodization of a straight signal.
fromSignal :: (C yv, Write sig yv) => Int -> sig yv -> T (sig yv)

-- | Convert a cyclic signal to a straight signal containing a loop.
toSignal :: (Monoid sig) => T sig -> sig
instance GHC.Show.Show period => GHC.Show.Show (Synthesizer.Dimensional.Cyclic.Signal.T period)
instance GHC.Classes.Eq period => GHC.Classes.Eq (Synthesizer.Dimensional.Cyclic.Signal.T period)


-- | Light-weight sample parameter inference which will fit most needs. We
--   only do "poor man's inference", only for sample rates. The sample rate
--   will be provided as an argument of a special type <a>T</a>. This
--   argument will almost never be passed explicitly but should be handled
--   by operators analogous to '($)' and '(.)'.
--   
--   In contrast to the run-time inference approach, we have the static
--   guarantee that the sample rate is fixed before passing a signal to the
--   outside world. However we still need to make it safe that signals that
--   are rendered for one sample rate are not processed with another sample
--   rate.
module Synthesizer.Dimensional.Process

-- | This wraps a function which computes a sample rate dependent result.
--   Sample rate tells how many values per unit are stored for
--   representation of a signal.
--   
--   The process is labeled with a type variable <tt>s</tt> which is part
--   the signals. This way we can ensure that signals are only used with
--   the sample rate they are created for.
newtype T s u t a
Cons :: (T (Recip u) t -> a) -> T s u t a
[process] :: T s u t a -> T (Recip u) t -> a

-- | Get results from the Process monad. You can obtain only signals (or
--   other values) that do not implicitly depend on the sample rate, that
--   is value without the <tt>s</tt> type parameter.
run :: (C u) => T (Recip u) t -> (forall s. T s u t a) -> a
withParam :: (a -> T s u t b) -> T s u t (a -> b)
getSampleRate :: C u => T s u t (T (Recip u) t)
toTimeScalar :: (C t, C u) => T u t -> T s u t t
toFrequencyScalar :: (C t, C u) => T (Recip u) t -> T s u t t
toTimeDimension :: (C t, C u) => t -> T s u t (T u t)
toFrequencyDimension :: (C t, C u) => t -> T s u t (T (Recip u) t)
intFromTime :: (C t, C u) => String -> T u t -> T s u t Int
intFromTime98 :: (C t, RealFrac t, C u) => String -> T u t -> T s u t Int
type DimensionGradient u v = Mul (Recip u) v
toGradientScalar :: (C q, C u, C v) => T v q -> T (DimensionGradient u v) q -> T s u q q

-- | Create a loop (feedback) from one node to another one. That is,
--   compute the fix point of a process iteration.
loop :: Functor f => f (a -> a) -> f a
pure :: a -> T s u t a

-- | This corresponds to <a>&lt;*&gt;</a>
($:) :: Applicative f => f (a -> b) -> f a -> f b
infixl 0 $:

-- | Instead of <tt>mixMulti $:: map f xs</tt> the caller should write
--   <tt>mixMulti $: mapM f xs</tt> in order to save the user from learning
--   another infix operator.
($::) :: (Applicative f, Traversable t) => f (t a -> b) -> t f a -> f b
infixl 0 $::
($^) :: Functor f => (a -> b) -> f a -> f b
infixl 0 $^
($#) :: Functor f => f (a -> b) -> a -> f b
infixl 0 $#
(.:) :: (Applicative f, Arrow arrow) => f arrow b c -> f arrow a b -> f arrow a c
infixr 9 .:
(.^) :: (Functor f, Arrow arrow) => arrow b c -> f arrow a b -> f arrow a c
infixr 9 .^

-- | Our signal processors have types like <tt>f (a -&gt; b -&gt; c)</tt>.
--   They could also have the type <tt>a -&gt; b -&gt; f c</tt> or <tt>f a
--   -&gt; f b -&gt; f c</tt>. We did not choose the last variant for
--   reduction of redundancy in type signatures and for simplifying
--   sharing, and we did not choose the second variant for easy composition
--   of processors. However the forms are freely convertible, and if you
--   prefer the last one because you do not want to sprinkle '($:)' in your
--   code, then you may want to convert the processors using the following
--   functions, that can be defined purely in the <a>Applicative</a> class.
liftP :: Applicative f => f (a -> b) -> f a -> f b
liftP2 :: Applicative f => f (a -> b -> c) -> f a -> f b -> f c
liftP3 :: Applicative f => f (a -> b -> c -> d) -> f a -> f b -> f c -> f d
liftP4 :: Applicative f => f (a -> b -> c -> d -> e) -> f a -> f b -> f c -> f d -> f e
instance GHC.Base.Functor (Synthesizer.Dimensional.Process.T s u t)
instance GHC.Base.Applicative (Synthesizer.Dimensional.Process.T s u t)
instance GHC.Base.Monad (Synthesizer.Dimensional.Process.T s u t)
instance Control.Monad.Fix.MonadFix (Synthesizer.Dimensional.Process.T s u t)


-- | This module contains types that may be used as sample rate type in a
--   dimensional signal.
module Synthesizer.Dimensional.Rate

-- | This type does not store a sample rate. It just provides a phantom
--   type parameter which asserts a common sample rate among several
--   signals.
data Phantom s
Phantom :: Phantom s

-- | Store the sample rate that a signal is sampled with.
newtype Actual rate
Actual :: rate -> Actual rate
type Dimensional u t = Actual (T (Recip u) t)
common :: Eq rate => String -> rate -> rate -> rate

module Synthesizer.Dimensional.Sample

-- | The constructor is only needed for <tt>arr</tt>, which is a kind of a
--   hack.
data T amp yv
Cons :: amp -> yv -> T amp yv
cons :: C amp => amp -> yv -> T amp yv
type Dimensional v y yv = T (Dimensional v y) yv
type Numeric amp yv = T (Numeric amp) yv
type Flat y = T (Flat y) y
type Abstract y = T Abstract y

-- | When you define additional instances, take care that displacements and
--   amplitudes cannot be brought out of order!
class Build sample
build :: Build sample => Amplitude sample -> Displacement sample -> sample
class Inspect sample
amplitude :: Inspect sample => sample -> Amplitude sample
displacement :: Inspect sample => sample -> Displacement sample
instance Synthesizer.Dimensional.Sample.Inspect (Synthesizer.Dimensional.Sample.T amp yv)
instance (Synthesizer.Dimensional.Sample.Inspect sample0, Synthesizer.Dimensional.Sample.Inspect sample1) => Synthesizer.Dimensional.Sample.Inspect (sample0, sample1)
instance (Synthesizer.Dimensional.Sample.Inspect sample0, Synthesizer.Dimensional.Sample.Inspect sample1, Synthesizer.Dimensional.Sample.Inspect sample2) => Synthesizer.Dimensional.Sample.Inspect (sample0, sample1, sample2)
instance Synthesizer.Dimensional.Sample.Build (Synthesizer.Dimensional.Sample.T amp yv)
instance (Synthesizer.Dimensional.Sample.Build sample0, Synthesizer.Dimensional.Sample.Build sample1) => Synthesizer.Dimensional.Sample.Build (sample0, sample1)
instance (Synthesizer.Dimensional.Sample.Build sample0, Synthesizer.Dimensional.Sample.Build sample1, Synthesizer.Dimensional.Sample.Build sample2) => Synthesizer.Dimensional.Sample.Build (sample0, sample1, sample2)


-- | Signals equipped with volume and sample rate information that may
--   carry a unit. Kind of volume and sample rate is configurable by types.
module Synthesizer.Dimensional.Signal.Private

-- | A signal value 0.5 at global amplitude 1 and signal value 1 at global
--   amplitude 0.5 shall represent the same signal. Thus observing the
--   amplitude breaks the abstraction.
--   
--   Cyclic nature such as needed for Fourier transform must be expressend
--   in the body. It would be nice to use the data type for waveforms, too,
--   but for waveforms the <tt>rate</tt> parameter makes no sense.
data T rate amplitude body
Cons :: rate -> amplitude -> body -> T rate amplitude body
[sampleRate] :: T rate amplitude body -> rate
[amplitude] :: T rate amplitude body -> amplitude
[body] :: T rate amplitude body -> body
type R s v y yv = T (Phantom s) (Dimensional v y) (T yv)
actualSampleRate :: T (Actual rate) amp sig -> rate
actualAmplitude :: T rate (Numeric amp) sig -> amp
toAmplitudeScalar :: (C y, C v) => T rate (Dimensional v y) sig -> T v y -> y
rewriteAmplitudeDimension :: (C v0, C v1) => (v0 -> v1) -> T rate (Dimensional v0 y) sig -> T rate (Dimensional v1 y) sig
asTypeOfAmplitude :: y -> T rate (Dimensional v y) sig -> y
scalarSamples :: (C y, Transform sig y) => (amp -> y) -> T rate (Numeric amp) (sig y) -> sig y
vectorSamples :: (C y yv, Transform sig yv) => (amp -> y) -> T rate (Numeric amp) (sig yv) -> sig yv
embedSampleRate :: (C u) => T s u t (T (Phantom s) amp sig -> T (Dimensional u t) amp sig)
render :: (C u) => T (Recip u) t -> (forall s. T s u t (T (Phantom s) amp sig)) -> T (Dimensional u t) amp sig
apply :: (C u) => (forall s. T s u t (T (Phantom s) amp0 sig0 -> T (Phantom s) amp1 sig1)) -> T (Dimensional u t) amp0 sig0 -> T (Dimensional u t) amp1 sig1
zip :: (Transform sig y1, Transform sig (y0, y1), Read sig y0) => T (Phantom s) amp0 (sig y0) -> T (Phantom s) amp1 (sig y1) -> T (Phantom s) (amp0, amp1) (sig (y0, y1))
processBody :: (sig0 -> sig1) -> T rate amp sig0 -> T rate amp sig1
replaceBody :: sig1 -> T rate amp sig0 -> T rate amp sig1
fromBody :: amp -> sig -> T (Phantom s) (Numeric amp) sig
flatFromBody :: sig -> T (Phantom s) (Flat y) sig
abstractFromBody :: sig -> T (Phantom s) Abstract sig
primitiveFromBody :: (Primitive amp) => sig -> T (Phantom s) amp sig
cache :: (Storable yv) => T rate amp (T yv) -> T rate amp (T yv)
bindCached :: (Storable yv) => T s u t (T rate amp (T yv)) -> (T rate amp (T yv) -> T s u t b) -> T s u t b
share :: (Storable yv) => T s u t (T rate amp (T yv)) -> (T s u t (T rate amp (T yv)) -> T s u t b) -> T s u t b
store :: (C t, C u, Storable yv) => T u t -> T s u t (T (Phantom s) amp (T yv) -> T (Phantom s) amp (T yv))
restore :: (Read sig yv) => T rate amp (sig yv) -> T rate amp (T yv)
toStorableInt16Mono :: (C a) => T rate (Dimensional Voltage a) (T a) -> T Int16
toStorableInt16Stereo :: (C a a, C a) => T rate (Dimensional Voltage a) (T (T a)) -> T (T Int16)
defaultChunkSize :: ChunkSize

module Synthesizer.Dimensional.RateAmplitude.Play
auto :: (Bounded int, C int, Storable int, C int, C u, C t, C v, C yv, C y yv, C y) => T (Recip u) t -> T v y -> (int -> Builder int) -> Signal u t v y yv -> IO ExitCode
timeVoltage :: (Bounded int, C int, Storable int, C int, C t, C yv, C y yv, C y) => (int -> Builder int) -> Signal Time t Voltage y yv -> IO ExitCode
timeVoltageMonoDoubleToInt16 :: Signal Time Double Voltage Double Double -> IO ExitCode
timeVoltageStereoDoubleToInt16 :: Signal Time Double Voltage Double (T Double) -> IO ExitCode
renderTimeVoltage :: (Bounded int, C int, Storable int, C int, C t, C yv, C y yv, C y) => (int -> Builder int) -> T Frequency t -> (forall s. T s Time t (R s Voltage y yv)) -> IO ExitCode
renderTimeVoltageMonoDoubleToInt16 :: T Frequency Double -> (forall s. T s Time Double (R s Voltage Double Double)) -> IO ExitCode
renderTimeVoltageStereoDoubleToInt16 :: T Frequency Double -> (forall s. T s Time Double (R s Voltage Double (T Double))) -> IO ExitCode

module Synthesizer.Dimensional.RateAmplitude.Piece
step :: (C q, C u, C v, Write sig q) => T s u v sig q
linear :: (C q, C u, C v, Write sig q) => T s u v sig q
exponential :: (C q, C u, C v, Write sig q) => T v q -> T s u v sig q
cosine :: (C q, C u, C v, Write sig q) => T s u v sig q
halfSine :: (C q, C u, C v, Write sig q) => FlatPosition -> T s u v sig q
cubic :: (C q, C u, C v, Write sig q) => T (DimensionGradient u v) q -> T (DimensionGradient u v) q -> T s u v sig q
type T s u v sig q = Piece (T u q) (T v q) (T v q -> LazySize -> q -> T s u q (T (Phantom s) (Flat q) (sig q)))
type Sequence s u v sig q = T (T u q) (T v q) (T v q -> LazySize -> q -> T s u q (T (Phantom s) (Flat q) (sig q)))

-- | Since this function looks for the maximum node value, and since the
--   signal parameter inference phase must be completed before signal
--   processing, infinite descriptions cannot be used here.
run :: (C q, C q, C u, C v, Write sig q) => T u q -> Sequence s u v sig q -> T s u q (T (Phantom s) (Dimensional v q) (sig q))
runVolume :: (C q, C q, C u, C v, Write sig q) => T u q -> Sequence s u v sig q -> T v q -> T s u q (T (Phantom s) (Dimensional v q) (sig q))
runState :: (C q, C q, C u, C v) => Sequence s u v T q -> T s u q (R s v q q)
runStateVolume :: (C q, C q, C u, C v) => Sequence s u v T q -> T v q -> T s u q (R s v q q)
(-|#) :: () => y -> (PieceDist t y sig, T t y sig) -> (PieceRightSingle y, T t y sig)
infixr 5 -|#

-- | The 6 operators simplify constructing a list of <tt>PieceData a</tt>.
--   The description consists of nodes (namely the curve values at nodes)
--   and the connecting curve types. The naming scheme is as follows: In
--   the middle there is a bar <tt>|</tt>. With respect to the bar, the pad
--   symbol <tt>#</tt> is at the side of the curve type, at the other side
--   there is nothing, a minus sign <tt>-</tt>, or an equality sign
--   <tt>=</tt>.
--   
--   <ol>
--   <li>Nothing means that here is the start or the end node of a
--   curve.</li>
--   <li>Minus means that here is a node where left and right curve meet at
--   the same value. The node description is thus one value.</li>
--   <li>Equality sign means that here is a split node, where left and
--   right curve might have different ending and beginning values,
--   respectively. The node description consists of a pair of values.</li>
--   </ol>
(#|-) :: () => (t, Piece t y sig) -> (PieceRightSingle y, T t y sig) -> (PieceDist t y sig, T t y sig)
infixr 5 #|-
(=|#) :: () => (y, y) -> (PieceDist t y sig, T t y sig) -> (PieceRightDouble y, T t y sig)
infixr 5 =|#
(#|=) :: () => (t, Piece t y sig) -> (PieceRightDouble y, T t y sig) -> (PieceDist t y sig, T t y sig)
infixr 5 #|=
(|#) :: () => y -> (PieceDist t y sig, T t y sig) -> T t y sig
infixr 5 |#
(#|) :: () => (t, Piece t y sig) -> y -> (PieceDist t y sig, T t y sig)
infixr 5 #|
data FlatPosition :: *
FlatLeft :: FlatPosition
FlatRight :: FlatPosition

module Synthesizer.Dimensional.RateAmplitude.File

-- | The output format is determined by SoX by the file name extension. The
--   sample precision is determined by the provided <a>Builder</a>
--   function.
--   
--   Example:
--   
--   <pre>
--   import qualified Data.StorableVector.Lazy.Builder as Builder
--   
--   write (DN.frequency one) (DN.voltage one) (\i -&gt; Builder.put (i::Int16)) "test.aiff" sound
--   </pre>
write :: (Bounded int, C int, Storable int, C int, C yv, C u, C t, C v, C y yv, C y) => T (Recip u) t -> T v y -> (int -> Builder int) -> FilePath -> Signal u t v y yv -> IO ExitCode
writeTimeVoltage :: (Bounded int, C int, Storable int, C int, C yv, C t, C y yv, C y) => (int -> Builder int) -> FilePath -> Signal Time t Voltage y yv -> IO ExitCode
writeTimeVoltageMonoDoubleToInt16 :: FilePath -> Signal Time Double Voltage Double Double -> IO ExitCode
writeTimeVoltageStereoDoubleToInt16 :: FilePath -> Signal Time Double Voltage Double (T Double) -> IO ExitCode
renderTimeVoltageMonoDoubleToInt16 :: T Frequency Double -> FilePath -> (forall s. T s Time Double (R s Voltage Double Double)) -> IO ExitCode
renderTimeVoltageStereoDoubleToInt16 :: T Frequency Double -> FilePath -> (forall s. T s Time Double (R s Voltage Double (T Double))) -> IO ExitCode

module Synthesizer.Dimensional.Rate.Dirac

-- | We want to represent streams of discrete events in a manner that is
--   more safe than plain <tt>[Bool]</tt>. Each peak can be imagined as a
--   Dirac impulse.
--   
--   A <tt>[Bool]</tt> could be used accidentally for <a>selectBool</a>,
--   where <tt>selectBool</tt> is intended for piecewise constant control
--   curves.
--   
--   You may think that a type like <tt>Peak = Peak Bool</tt> as sample
--   type in <tt>T s Peak</tt> would also do the job. Actually, this
--   wouldn't be a good idea since you can apply constant interpolation on
--   it, which obviously fools the idea of a peak.
--   
--   This type is so level that it could be moved to
--   Synthesizer.Generic.Dirac.
newtype T s sig
Cons :: sig Bool -> T s sig
[decons] :: T s sig -> sig Bool

-- | This is the most frequently needed transformation of a stream of
--   peaks, if not the only one. It converts to a signal of peaks with area
--   1. This convention is especially useful for smoothing filters that
--   produce frequency progress curves from zero crossings.
toAmplitudeSignal :: (C q, C u, Functor sig) => T s u q (T s sig -> T (Phantom s) (Numeric (T (Recip u) q)) (sig q))
instance Data.Semigroup.Semigroup (sig GHC.Types.Bool) => Data.Semigroup.Semigroup (Synthesizer.Dimensional.Rate.Dirac.T s sig)
instance GHC.Base.Monoid (sig GHC.Types.Bool) => GHC.Base.Monoid (Synthesizer.Dimensional.Rate.Dirac.T s sig)
instance Synthesizer.Generic.Cut.Read (sig GHC.Types.Bool) => Synthesizer.Generic.Cut.Read (Synthesizer.Dimensional.Rate.Dirac.T s sig)
instance Synthesizer.Generic.Cut.Transform (sig GHC.Types.Bool) => Synthesizer.Generic.Cut.Transform (Synthesizer.Dimensional.Rate.Dirac.T s sig)


module Synthesizer.Dimensional.RateAmplitude.Noise
white :: (C yv, Random yv, C q, C u, C v) => T (Recip u) q -> T v q -> T s u q (R s v q yv)
whiteBandEnergy :: (C yv, Random yv, C q, C u, C v) => T (Mul u (Sqr v)) q -> T s u q (R s v q yv)
randomPeeks :: (C q, Random q, Ord q, C u) => T s u q (R s (Recip u) q q -> R s (Recip u) q q)
whiteGen :: (C yv, Random yv, RandomGen g, C q, C u, C v) => g -> T (Recip u) q -> T v q -> T s u q (R s v q yv)
whiteBandEnergyGen :: (C yv, Random yv, RandomGen g, C q, C u, C v) => g -> T (Mul u (Sqr v)) q -> T s u q (R s v q yv)
randomPeeksGen :: (C q, Random q, Ord q, C u, RandomGen g) => g -> T s u q (R s (Recip u) q q -> R s (Recip u) q q)


module Synthesizer.Dimensional.Rate.Cut

-- | To avoid recomputation, don't use this directly on State signals but
--   only after buffering.
splitAt :: (Transform sig, C t, C u) => T u t -> T s u t (Signal s amp sig -> (Signal s amp sig, Signal s amp sig))
take :: (Transform sig, C t, C u) => T u t -> T s u t (Signal s amp sig -> Signal s amp sig)
drop :: (Transform sig, C t, C u) => T u t -> T s u t (Signal s amp sig -> Signal s amp sig)
concat :: (Primitive amp, Monoid sig, C u) => T s u t ([Signal s amp sig] -> Signal s amp sig)
append :: (Primitive amp, Monoid sig, C u) => T s u t (Signal s amp sig -> Signal s amp sig -> Signal s amp sig)


-- | Control curves which can be used as envelopes, for controlling filter
--   parameters and so on.
module Synthesizer.Dimensional.Rate.Control
constant :: (C y, C u) => T s u t (Signal s y)

-- | Caution: This control curve can contain samples with an absolute value
--   greater than 1. The linear curve starts with zero.
linear :: (C q, C u) => T u q -> T s u q (Signal s q)
exponential :: (C q, C u) => T u q -> T s u q (Signal s q)
exponential2 :: (C q, C u) => T u q -> T s u q (Signal s q)


module Synthesizer.Dimensional.Rate.Analysis
centroid :: (C q, C u) => SignalRate u q amp q -> T u q
length :: (C t, C u) => SignalRate u t amp yv -> T u t


module Synthesizer.Dimensional.Cyclic.Analysis

-- | Fourier analysis
toFrequencySpectrum :: (C q, C u, C v, Transform sig (T q)) => T (Dimensional u q) (Dimensional v q) (T (sig (T q))) -> T (Dimensional (Recip u) q) (Dimensional (Mul u v) q) (T (sig (T q)))

-- | Fourier synthesis
fromFrequencySpectrum :: (C q, C u, C v, Transform sig (T q)) => T (Dimensional (Recip u) q) (Dimensional (Mul u v) q) (T (sig (T q))) -> T (Dimensional u q) (Dimensional v q) (T (sig (T q)))


module Synthesizer.Dimensional.ChunkySize.Signal
store :: (Write sig yv) => Size s -> Signal s amp (T yv) -> Signal s amp (sig yv)
length :: (Read sig) => Signal s amp sig -> Size s


module Synthesizer.Dimensional.ChunkySize.Cut

-- | To avoid recomputation, don't use this directly on State signals but
--   only after buffering.
splitAt :: (Transform sig) => Size s -> Signal s amp sig -> (Signal s amp sig, Signal s amp sig)
take :: (Transform sig) => Size s -> Signal s amp sig -> Signal s amp sig
drop :: (Transform sig) => Size s -> Signal s amp sig -> Signal s amp sig


-- | A class that allows unified handling of <tt>Amplitude.Flat</tt> and
--   <tt>Amplitude.Dimensional Dim.Scalar</tt> which is often used for
--   control curves. However, I'm thinking about whether this is more abuse
--   than use. So this class may disappear in future. Amplitude.Flat might
--   become a synonym for <tt>DN.scalar one</tt>. Sometimes, using Flat
--   instead of DN.Scalar has the advantage of internally saving a
--   multiplication with one, but I think the compiler should optimize that
--   away. The optimization however is more complicated if a whole
--   StorableVector is multiplied element-wise by one. E.g. the
--   concatenation of flat (storable) signals can be done without copying
--   the entire data.
module Synthesizer.Dimensional.Amplitude.Flat
class C amp => C y amp | amp -> y
amplifySample :: C y amp => amp -> y -> y
amplifySample :: C y amp => amp -> y -> y
canonicalize :: (C y flat, Transform sig y) => T rate flat (sig y) -> T rate (Flat y) (sig y)
toSamples :: (C y flat, Transform sig y) => T rate flat (sig y) -> sig y
instance Algebra.Ring.C y => Synthesizer.Dimensional.Amplitude.Flat.C y (Synthesizer.Dimensional.Amplitude.Flat y)
instance (Algebra.DimensionTerm.IsScalar v, Algebra.Ring.C y) => Synthesizer.Dimensional.Amplitude.Flat.C y (Synthesizer.Dimensional.Amplitude.Numeric (Number.DimensionTerm.T v y))


-- | A wrapper around <tt>(-&gt;)</tt> or <tt>Causal.Process</tt> that adds
--   amplitude handling to the Arrow paradigm. This wrapper unifies
--   <a>Synthesizer.Dimensional.Map</a> and
--   <a>Synthesizer.Dimensional.Causal.Process</a>.
module Synthesizer.Dimensional.Arrow

-- | The sample type parameters can be arbitrarily nested tuples of
--   <tt>Samples</tt>. Type functions are used for untangling amplitudes
--   and displacements. We use this approach in order to be able to match
--   (as good as possible) the Arrow type class.
newtype T arrow sample0 sample1
Cons :: (Amplitude sample0 -> (arrow (Displacement sample0) (Displacement sample1), Amplitude sample1)) -> T arrow sample0 sample1
type Single arrow amp0 amp1 yv0 yv1 = T arrow (T amp0 yv0) (T amp1 yv1)
class C arrow => Applicable arrow rate
apply :: (Transform sig (Displacement sample0), Transform sig (Displacement sample1), Applicable arrow rate) => T arrow sample0 sample1 -> T rate (Amplitude sample0) (sig (Displacement sample0)) -> T rate (Amplitude sample1) (sig (Displacement sample1))
infixl 9 `apply`
applyFlat :: (C yv0 amp0, Transform sig yv0, Transform sig yv1, Applicable arrow rate) => Single arrow (Flat yv0) amp1 yv0 yv1 -> T rate amp0 (sig yv0) -> T rate amp1 (sig yv1)
canonicalizeFlat :: (C y flat, Arrow arrow) => Single arrow flat (Flat y) y y
applyConst :: (C amp1, C y0, C arrow) => Single arrow (Numeric amp0) amp1 y0 yv1 -> amp0 -> T (Phantom s) amp1 (T yv1)
($/:) :: (Applicative f, Transform sig yv0, Transform sig yv1, Applicable arrow rate) => f (Single arrow amp0 amp1 yv0 yv1) -> f (T rate amp0 (sig yv0)) -> f (T rate amp1 (sig yv1))
infixl 0 $/:
($/-) :: (C amp1, Functor f, C y0, C arrow) => f (Single arrow (Numeric amp0) amp1 y0 yv1) -> amp0 -> f (T (Phantom s) amp1 (T yv1))
infixl 0 $/-
id :: (Category arrow) => T arrow sample sample
compose :: (Category arrow) => T arrow sample0 sample1 -> T arrow sample1 sample2 -> T arrow sample0 sample2

-- | This instance lacks an implementation for <a>arr</a>. However the
--   syntactic sugar for arrows uses <a>arr</a> for shuffling the operands.
--   Actually shuffling is possible for our arrow, but lifting general
--   functions is a problem. If you want to use arrow syntax, you should
--   hide the <a>arr</a> from Control.Arrow and use the one provided as
--   plain function, here.

-- | This implementation would work for all <tt>f</tt>s where the output
--   amplitude does not depend on the input displacement. This is true for
--   all shuffling operations that are needed in the translation of the
--   arrow syntax. However, for the implementation we would need type
--   constraints of the function passed to <a>arr</a> and this is not
--   allowed.
arr :: (Arrow arrow, Build sample0, Inspect sample1) => (sample0 -> sample1) -> T arrow sample0 sample1
first :: (Arrow arrow) => T arrow sample0 sample1 -> T arrow (sample0, sample) (sample1, sample)
second :: (Arrow arrow) => T arrow sample0 sample1 -> T arrow (sample, sample0) (sample, sample1)
split :: (Arrow arrow) => T arrow sample0 sample1 -> T arrow sample2 sample3 -> T arrow (sample0, sample2) (sample1, sample3)
fanout :: (Arrow arrow) => T arrow sample sample0 -> T arrow sample sample1 -> T arrow sample (sample0, sample1)
independentMap :: (Arrow arrow) => (Amplitude sample0 -> Amplitude sample1) -> (Displacement sample0 -> Displacement sample1) -> T arrow sample0 sample1
double :: (Arrow arrow) => T arrow sample (sample, sample)
forceDimensionalAmplitude :: (C v, C y, C y yv, Arrow arrow) => T v y -> Single arrow (Dimensional v y) (Dimensional v y) yv yv

-- | I will call the connection from input to output amplitudes of type
--   <tt>amp</tt> the looping channel. It is essential, that the looping
--   channel decouples output from input amplitude. You can achieve this by
--   inserting one of the <tt>forceAmplitude</tt> functions somewhere in
--   the looping channel.
loop :: (ArrowLoop arrow) => T arrow (restSampleIn, sample) (restSampleOut, sample) -> T arrow restSampleIn restSampleOut
loopVolume :: (C y, C y yv, C v, ArrowLoop arrow) => T v y -> T arrow (restSampleIn, T (Dimensional v y) yv) (restSampleOut, T (Dimensional v y) yv) -> T arrow restSampleIn restSampleOut
loop2Volume :: (C y0, C y0 yv0, C v0, C y1, C y1 yv1, C v1, ArrowLoop arrow) => (T v0 y0, T v1 y1) -> T arrow (restSampleIn, (T (Dimensional v0 y0) yv0, T (Dimensional v1 y1) yv1)) (restSampleOut, (T (Dimensional v0 y0) yv0, T (Dimensional v1 y1) yv1)) -> T arrow restSampleIn restSampleOut
instance Synthesizer.Dimensional.Arrow.Applicable (->) rate
instance Control.Category.Category arrow => Control.Category.Category (Synthesizer.Dimensional.Arrow.T arrow)
instance Control.Arrow.Arrow arrow => Control.Arrow.Arrow (Synthesizer.Dimensional.Arrow.T arrow)

module Synthesizer.Dimensional.Map.Displacement

-- | Mix two signals. In contrast to <a>zipWith</a> the result has the
--   length of the longer signal.
mix :: (C y, C y, C y yv, C v, Arrow arrow) => T arrow (DNS v y yv, DNS v y yv) (DNS v y yv)
mixVolume :: (C y, C y yv, C v, Arrow arrow) => T v y -> T arrow (DNS v y yv, DNS v y yv) (DNS v y yv)

-- | Mix one or more signals.
fanoutAndMixMulti :: (C y, C y yv, C v, Arrow arrow) => [T arrow sample (DNS v y yv)] -> T arrow sample (DNS v y yv)

-- | Mix zero or more signals.
fanoutAndMixMultiVolume :: (C y, C y yv, C v, Arrow arrow) => T v y -> [T arrow sample (DNS v y yv)] -> T arrow sample (DNS v y yv)

-- | Add a number to all of the signal values. This is useful for adjusting
--   the center of a modulation.
raise :: (C y, C y yv, C v, Arrow arrow) => T v y -> yv -> T arrow (DNS v y yv) (DNS v y yv)

-- | Distort the signal using a flat function. The first signal gives the
--   scaling of the function. If the scaling is <tt>c</tt> and the input
--   sample is <tt>y</tt>, then <tt>c * f(y/c)</tt> is emitted. This way we
--   can use an (efficient) flat function and have a simple, yet dimension
--   conform, way of controlling the distortion. E.g. if the distortion
--   function is <tt>tanh</tt> then the value <tt>c</tt> controls the
--   saturation level.
distort :: (C y, C y yv, C v, Arrow arrow) => (yv -> yv) -> T arrow (DNS v y y, DNS v y yv) (DNS v y yv)

-- | Map a control curve without amplitude unit by a linear (affine)
--   function with a unit. This is a combination of <a>raise</a> and
--   <tt>amplify</tt>.
--   
--   It is not quite correct in the sense, that it does not produce
--   low-level sample values in the range (-1,1). Instead it generates
--   values around 1.
mapLinear :: (C y flat, C y, C u, Arrow arrow) => y -> T u y -> T arrow (T flat y) (DNS u y y)
mapExponential :: (C y flat, C y, C u, Arrow arrow) => y -> T u q -> T arrow (T flat y) (DNS u q y)
mapLinearDimension :: (C y, C y, C u, C v, Arrow arrow) => T v y -> T (Mul v u) y -> T arrow (DNS u y y) (DNS (Mul v u) y y)


-- | Maps that handle pairs of amplitudes and sampled values. They are a
--   special form of arrows.
module Synthesizer.Dimensional.Map

-- | This type shall ensure, that you do not accidentally bring amplitudes
--   and the corresponding low-level signal values out of sync. We also use
--   it for generation of internal control parameters in
--   <a>Synthesizer.Dimensional.Causal.ControlledProcess</a>. In principle
--   this could also be <a>T</a>, but maps are not bound to a sampling
--   rate, and thus do not need the <tt>s</tt> type parameter.
type T = T (->)
type Single amp0 amp1 yv0 yv1 = Single (->) amp0 amp1 yv0 yv1
consFlip :: (Amplitude sample0 -> (Amplitude sample1, Displacement sample0 -> Displacement sample1)) -> T sample0 sample1
apply :: (Transform sig yv0, Transform sig yv1) => Single amp0 amp1 yv0 yv1 -> T rate amp0 (sig yv0) -> T rate amp1 (sig yv1)
applyFlat :: (C yv0 amp0, Transform sig yv0, Transform sig yv1) => Single (Flat yv0) amp1 yv0 yv1 -> T rate amp0 (sig yv0) -> T rate amp1 (sig yv1)
forceDimensionalAmplitude :: (C v, C y, C y yv, Arrow arrow) => T v y -> Single arrow (Dimensional v y) (Dimensional v y) yv yv
forcePrimitiveAmplitude :: (Primitive amp, Arrow arrow) => Single arrow amp amp yv yv

-- | We restrict the amplitude types to those of class <tt>Amplitude</tt>.
--   Otherwise <a>mapAmplitude</a> could be abused for bringing amplitudes
--   and respective sample values out of sync. For mapping amplitudes that
--   are nested in some pairs, use it in combination with <tt>first</tt>
--   and <tt>second</tt>.
--   
--   FIXME: This function however still breaks the abstraction, since
--   normally it should not be observable how the volume is balanced
--   between amplitude and signal. This function allows to replace an
--   actual amplitude by <tt>Flat</tt>, which also breaks the abstraction.
--   This may only be used for proportional mappings. See <a>T</a>.
mapAmplitude :: (C amp0, C amp1, Arrow arrow) => (amp0 -> amp1) -> Single arrow amp0 amp1 yv yv

-- | FIXME: This function is unsafe. Only use it for proportional mappings.
--   See <a>T</a>.
mapAmplitudeSameType :: (Arrow arrow) => (Amplitude sample -> Amplitude sample) -> T arrow sample sample

-- | This function can be abused to bring the amplitudes out of order. So
--   be careful!
independent :: (Arrow arrow) => (Amplitude sample0 -> Amplitude sample1) -> (Displacement sample0 -> Displacement sample1) -> T arrow sample0 sample1
id :: (Category arrow) => T arrow sample sample
double :: (Arrow arrow) => T arrow sample (sample, sample)
fst :: (Arrow arrow) => T arrow (sample0, sample1) sample0
snd :: (Arrow arrow) => T arrow (sample0, sample1) sample1
swap :: (Arrow arrow) => T arrow (sample0, sample1) (sample1, sample0)
balanceRight :: (Arrow arrow) => T arrow ((sample0, sample1), sample2) (sample0, (sample1, sample2))
balanceLeft :: (Arrow arrow) => T arrow (sample0, (sample1, sample2)) ((sample0, sample1), sample2)
packTriple :: (Arrow arrow) => T arrow (sample0, (sample1, sample2)) (sample0, sample1, sample2)
unpackTriple :: (Arrow arrow) => T arrow (sample0, sample1, sample2) (sample0, (sample1, sample2))


module Synthesizer.Dimensional.Map.Filter

-- | The amplification factor must be positive.
amplify :: (C y amp, Arrow arrow) => y -> Single arrow (Numeric amp) (Numeric amp) yv yv
amplifyDimension :: (C y, C v0, C v1, Arrow arrow) => T v0 y -> Single arrow (Dimensional v1 y) (Dimensional (Mul v0 v1) y) yv yv
amplifyScalarDimension :: (C y, C v, Arrow arrow) => T v y -> Single arrow (Dimensional Scalar y) (Dimensional v y) yv yv
negate :: (C (Displacement sample), Arrow arrow) => T arrow sample sample
envelope :: (C y, Arrow arrow) => T arrow (Flat y, Numeric amp y) (Numeric amp y)
envelopeScalarDimension :: (C y, C v, Arrow arrow) => T arrow (Dimensional Scalar y y, Dimensional v y y) (Dimensional v y y)
envelopeVector :: (C y (Displacement sample), Arrow arrow) => T arrow (Flat y, sample) sample
envelopeVectorDimension :: (C y0 yv, C y, C v0, C v1, Arrow arrow) => T arrow (Dimensional v0 y y0, Dimensional v1 y yv) (Dimensional (Mul v0 v1) y yv)

module Synthesizer.Dimensional.Causal.Process

-- | Note that <tt>amp</tt> can also be a pair of amplitudes or a more
--   complicated ensemble of amplitudes.
type T s sample0 sample1 = T (Core s) sample0 sample1
type Single s amp0 amp1 yv0 yv1 = Single (Core s) amp0 amp1 yv0 yv1
newtype Core s yv0 yv1
Core :: (T yv0 yv1) -> Core s yv0 yv1
consFlip :: (Amplitude sample0 -> (Amplitude sample1, T (Displacement sample0) (Displacement sample1))) -> T s sample0 sample1
apply :: (Transform sig yv0, Transform sig yv1) => Single s amp0 amp1 yv0 yv1 -> T (Phantom s) amp0 (sig yv0) -> T (Phantom s) amp1 (sig yv1)
infixl 9 `apply`
applyFlat :: (C yv0 amp0, Transform sig yv0, Transform sig yv1) => Single s (Flat yv0) amp1 yv0 yv1 -> T (Phantom s) amp0 (sig yv0) -> T (Phantom s) amp1 (sig yv1)
canonicalizeFlat :: (C y flat) => Single s flat (Flat y) y y
applyConst :: (C amp1, C y0) => Single s (Numeric amp0) amp1 y0 yv1 -> amp0 -> T (Phantom s) amp1 (T yv1)
($/:) :: (Applicative f, Transform sig yv0, Transform sig yv1) => f (Single s amp0 amp1 yv0 yv1) -> f (T (Phantom s) amp0 (sig yv0)) -> f (T (Phantom s) amp1 (sig yv1))
infixl 0 $/:
($/-) :: (C amp1, Functor f, C y0) => f (Single s (Numeric amp0) amp1 y0 yv1) -> amp0 -> f (T (Phantom s) amp1 (T yv1))
infixl 0 $/-
applyFst :: (Read sig yv) => T s (T amp yv, restSampleIn) restSampleOut -> T (Phantom s) amp (sig yv) -> T s restSampleIn restSampleOut
infixl 9 `applyFst`
applyFlatFst :: (C yv amp, Read sig yv) => T s (T (Flat yv) yv, restSampleIn) restSampleOut -> T (Phantom s) amp (sig yv) -> T s restSampleIn restSampleOut
feedFst :: (Read sig yv) => T (Phantom s) amp (sig yv) -> T s restSample (T amp yv, restSample)
applySnd :: (Read sig yv) => T s (restSampleIn, T amp yv) restSampleOut -> T (Phantom s) amp (sig yv) -> T s restSampleIn restSampleOut
feedSnd :: (Read sig yv) => T (Phantom s) amp (sig yv) -> T s restSample (restSample, T amp yv)
map :: T sample0 sample1 -> T s sample0 sample1

-- | Precomposition with a pure function.
(^>>) :: T sample0 sample1 -> T s sample1 sample2 -> T s sample0 sample2
infixr 1 ^>>

-- | Postcomposition with a pure function.
(>>^) :: T s sample0 sample1 -> T sample1 sample2 -> T s sample0 sample2
infixr 1 >>^

-- | Precomposition with a pure function (right-to-left variant).
(<<^) :: T s sample1 sample2 -> T sample0 sample1 -> T s sample0 sample2
infixr 1 <<^

-- | Postcomposition with a pure function (right-to-left variant).
(^<<) :: T sample1 sample2 -> T s sample0 sample1 -> T s sample0 sample2
infixr 1 ^<<

-- | Lift a low-level homogeneous process to a dimensional one.
--   
--   Note that the <tt>amp</tt> type variable is unrestricted. This way we
--   show, that the amplitude is not touched, which also means that the
--   underlying low-level process must be homogeneous.
homogeneous :: T yv0 yv1 -> Single s amp amp yv0 yv1
id :: T s sample sample
loop2Volume :: (C y0, C y0 yv0, C v0, C y1, C y1 yv1, C v1) => (T v0 y0, T v1 y1) -> T s (restSampleIn, (T (Dimensional v0 y0) yv0, T (Dimensional v1 y1) yv1)) (restSampleOut, (T (Dimensional v0 y0) yv0, T (Dimensional v1 y1) yv1)) -> T s restSampleIn restSampleOut

-- | Split the input between the two argument arrows and combine their
--   output. Note that this is in general not a functor.
--   
--   The default definition may be overridden with a more efficient version
--   if desired.
(***) :: Arrow a => forall b c b' c'. () => a b c -> a b' c' -> a (b, b') (c, c')
infixr 3 ***

-- | Fanout: send the input to both argument arrows and combine their
--   output.
--   
--   The default definition may be overridden with a more efficient version
--   if desired.
(&&&) :: Arrow a => forall b c c'. () => a b c -> a b c' -> a b (c, c')
infixr 3 &&&

-- | Left-to-right composition
(>>>) :: Category k cat => cat a b -> cat b c -> cat a c
infixr 1 >>>

-- | Right-to-left composition
(<<<) :: Category k cat => cat b c -> cat a b -> cat a c
infixr 1 <<<
compose :: (Category arrow) => T arrow sample0 sample1 -> T arrow sample1 sample2 -> T arrow sample0 sample2
first :: (Arrow arrow) => T arrow sample0 sample1 -> T arrow (sample0, sample) (sample1, sample)
second :: (Arrow arrow) => T arrow sample0 sample1 -> T arrow (sample, sample0) (sample, sample1)
split :: (Arrow arrow) => T arrow sample0 sample1 -> T arrow sample2 sample3 -> T arrow (sample0, sample2) (sample1, sample3)
fanout :: (Arrow arrow) => T arrow sample sample0 -> T arrow sample sample1 -> T arrow sample (sample0, sample1)

-- | I will call the connection from input to output amplitudes of type
--   <tt>amp</tt> the looping channel. It is essential, that the looping
--   channel decouples output from input amplitude. You can achieve this by
--   inserting one of the <tt>forceAmplitude</tt> functions somewhere in
--   the looping channel.
loop :: (ArrowLoop arrow) => T arrow (restSampleIn, sample) (restSampleOut, sample) -> T arrow restSampleIn restSampleOut
loopVolume :: (C y, C y yv, C v, ArrowLoop arrow) => T v y -> T arrow (restSampleIn, T (Dimensional v y) yv) (restSampleOut, T (Dimensional v y) yv) -> T arrow restSampleIn restSampleOut
instance Synthesizer.Causal.Arrow.C (Synthesizer.Dimensional.Causal.Process.Core s)
instance Control.Arrow.ArrowLoop (Synthesizer.Dimensional.Causal.Process.Core s)
instance Control.Arrow.Arrow (Synthesizer.Dimensional.Causal.Process.Core s)
instance Control.Category.Category (Synthesizer.Dimensional.Causal.Process.Core s)
instance Synthesizer.Dimensional.Arrow.Applicable (Synthesizer.Dimensional.Causal.Process.Core s) (Synthesizer.Dimensional.Rate.Phantom s)


module Synthesizer.Dimensional.Causal.Filter

-- | The amplification factor must be positive.
amplify :: (C y amp) => y -> T s u t (Single s (Numeric amp) (Numeric amp) yv yv)
amplifyDimension :: (C y, C u, C v0, C v1) => T v0 y -> T s u t (Single s (Dimensional v1 y) (Dimensional (Mul v0 v1) y) yv yv)
amplifyScalarDimension :: (C y, C u, C v) => T v y -> T s u t (Single s (Dimensional Scalar y) (Dimensional v y) yv yv)
negate :: (C (Displacement sample)) => T s u t (T s sample sample)
envelope :: (C y) => T s u t (T s (Flat y, Numeric amp y) (Numeric amp y))
envelopeScalarDimension :: (C y, C u, C v) => T s u t (T s (Dimensional Scalar y y, Dimensional v y y) (Dimensional v y y))
envelopeVector :: (C y (Displacement sample)) => T s u t (T s (Flat y, sample) sample)
envelopeVectorDimension :: (C y0 yv, C y, C u, C v0, C v1) => T s u t (T s (Dimensional v0 y y0, Dimensional v1 y yv) (Dimensional (Mul v0 v1) y yv))
differentiate :: (C yv, C q, C u, C v) => T s u q (Single s (Dimensional v q) (Dimensional (DimensionGradient u v) q) yv yv)
integrate :: (C yv, C q, C u, C v) => T s u q (T s (Dimensional v q yv) (Dimensional (Mul u v) q yv))


module Synthesizer.Dimensional.Causal.Displacement
mix :: (C y, C y, C y yv, C v) => T s u t (T s (DNS v y yv, DNS v y yv) (DNS v y yv))
mixVolume :: (C y, C y yv, C v) => T v y -> T s u t (T s (DNS v y yv, DNS v y yv) (DNS v y yv))
fanoutAndMixMulti :: (C y, C y yv, C v) => [T s u t (T s sample (DNS v y yv))] -> T s u t (T s sample (DNS v y yv))
fanoutAndMixMultiVolume :: (C y, C y yv, C v) => T v y -> [T s u t (T s sample (DNS v y yv))] -> T s u t (T s sample (DNS v y yv))
raise :: (C y, C y yv, C v) => T v y -> yv -> T s u t (T s (DNS v y yv) (DNS v y yv))
distort :: (C y, C y yv, C v) => (yv -> yv) -> T s u t (T s (DNS v y y, DNS v y yv) (DNS v y yv))


module Synthesizer.Dimensional.Causal.Analysis
deltaSigmaModulationPositive :: (C a, C a, C u, C v) => T s u a (T s (DNS (Mul u v) a a, DNS v a a) (DNS v a a))


-- | Basic definitions for causal signal processors that are controlled by
--   another signal. E.g. a Moog lowpass filter is controlled by the
--   cut-off frequency and the resonance. However internally the Moog
--   filter uses some feed-back factors. The translation from cut-off
--   frequency and resonance (we call them external parameters) to the
--   feed-back factors (we call them internal parameters) depends on the
--   sampling rate. The problem we want to tackle is, that computation of
--   internal filter parameters is expensive, but application of filters is
--   not. Thus we wish to compute internal filter parameters at a lower
--   rate than the sampling rate of the input and output (refered to as
--   audio rate, here).
--   
--   Other digital sound synthesis systems solve it this way:
--   
--   <ul>
--   <li>Csound, SuperCollider: They distinguish between audio rate (say
--   44100 Hz), control rate (say 4410 Hz) and note rate (irregular, but
--   usually less then 100 Hz). The control rate is globally equal and
--   constant.</li>
--   <li>ChucK: It updates internal filter parameters when external filter
--   parameters change, that is, it updates by demand. In terms of control
--   rates this means, that multiple control rates exist and they can be
--   irregular.</li>
--   </ul>
--   
--   After playing around with several approaches in this library, the
--   following one appeals me most: We reveal the existence of internal
--   filter parameters to the user, but we hide the details of that
--   parameters. For every filter, we provide two functions: One that
--   computes internal filter parameters from external ones and one for
--   actual filtering of the audio data. We provide a type class that
--   selects a filter according to the type of the internal filter
--   parameters. That is, the user only has to choose a filter parameter
--   computation, as found in
--   <a>Synthesizer.Dimensional.Causal.FilterParameter</a>. For globally
--   constant filter parameters, such as the filter order, we use the
--   signal amplitude. You might call this abuse, but in future we may
--   revise the notion of amplitude to that of a global signal parameter.
--   
--   Additionally we provide functions that perform the full filtering
--   process given only the filter parameter generator. There are two
--   modes:
--   
--   <ul>
--   <li>Synchronous: The filter parameters are computed at audio
--   rate.</li>
--   <li>Asynchronous: The filter parameters are computed at a rate that
--   can differ from audio rate. You can choose the control rate
--   individually for every filter application.</li>
--   </ul>
--   
--   This approach has several advantages:
--   
--   <ul>
--   <li>A filter only has to treat inputs of the same sampling rate. We do
--   not have to duplicate the code for coping with input at rates
--   different from the sample rate.</li>
--   <li>We can provide different ways of specifying filter parameters,
--   e.g. the resonance of a lowpass filter can be controlled either by the
--   slope or by the amplification of the resonant frequency.</li>
--   <li>We can use different control rates in the same program.</li>
--   <li>We can even adapt the speed of filter parameter generation to the
--   speed of changes in the control signal.</li>
--   <li>For a sinusoidal controlled filter sweep we can setup a table of
--   filter parameters for logarithmically equally spaced cut-off
--   frequencies and traverse this table at varying rates according to
--   arcus sine.</li>
--   <li>Classical handling of control rate filter parameter computation
--   can be considered as resampling of filter parameters with constant
--   interpolation. If there is only a small number of internal filter
--   parameters then we may resample with linear interpolation of the
--   filter parameters.</li>
--   </ul>
module Synthesizer.Dimensional.Causal.ControlledProcess

-- | Select a filter process according to the filter parameter type.
class C global => C global parameter a b | global parameter a -> b, global parameter b -> a
process :: (C global parameter a b, (C u)) => T s u t (T s (T global (RateDep s parameter), a) b)

-- | This type tags an internal filter parameter with the sampling rate for
--   which it was generated. Be aware, that in asynchronous application the
--   internal filter parameters are computed at control rate, but the
--   internal filter parameters must correspond to the sampling rate of the
--   target audio signal. The type parameter <tt>s</tt> corresponds to that
--   target audio rate.
newtype RateDep s ic
RateDep :: ic -> RateDep s ic
[unRateDep] :: RateDep s ic -> ic
runSynchronous1 :: (C global parameter sampleIn sampleOut, C u, C ecAmp) => T s u t (T (T ecAmp ec) (T global (RateDep s parameter))) -> T s u t (Signal s ecAmp ec -> T s sampleIn sampleOut)
runSynchronous2 :: (C global parameter sampleIn sampleOut, C u, C ecAmp0, C ecAmp1) => T s u t (T (T ecAmp0 ec0, T ecAmp1 ec1) (T global (RateDep s parameter))) -> T s u t (Signal s ecAmp0 ec0 -> Signal s ecAmp1 ec1 -> T s sampleIn sampleOut)
runAsynchronous1 :: (C global ic sampleIn sampleOut, C u, C t) => T t (RateDep s ic) -> T s u t (T (T ecAmp ec) (T global (RateDep s ic))) -> T (Dimensional u t) ecAmp (T ec) -> T s u t (T s sampleIn sampleOut)
runAsynchronousBuffered1 :: (C global ic sampleIn sampleOut, C u, C t) => T t (RateDep s ic) -> T s u t (T (T ecAmp ec) (T global (RateDep s ic))) -> T (Dimensional u t) ecAmp (T ec) -> T s u t (T s sampleIn sampleOut)
processAsynchronous1 :: (C global ic sampleIn sampleOut, C ecAmp, C u, C t) => T t (RateDep s ic) -> T s u t (T (T ecAmp ec) (T global (RateDep s ic))) -> T (Recip u) t -> (forall r. T r u t (Signal r ecAmp ec)) -> T s u t (T s sampleIn sampleOut)

-- | Using two <tt>SigP.T</tt>'s as input has the disadvantage that their
--   rates must be compared dynamically. It is not possible with our data
--   structures to use one rate for multiple signals. We could also allow
--   the input of a Rate.T and two Proc.T's, since this is the form we get
--   from the computation routines. But this way we lose sharing.
runAsynchronous2 :: (C global ic sampleIn sampleOut, C ecAmp0, C ecAmp1, C u, C t) => T t (RateDep s ic) -> T s u t (T (T ecAmp0 ec0, T ecAmp1 ec1) (T global (RateDep s ic))) -> T (Dimensional u t) (ecAmp0) (T ec0) -> T (Dimensional u t) (ecAmp1) (T ec1) -> T s u t (T s sampleIn sampleOut)

-- | This function will be more commonly used than <a>runAsynchronous2</a>,
--   but it disallows sharing of control signals. It can be easily defined
--   in terms of <a>runAsynchronous2</a> and <a>render</a>, but the
--   implementation here does not need the check for equal sample rates.
processAsynchronous2 :: (C global ic sampleIn sampleOut, C ecAmp0, C ecAmp1, C u, C t) => T t (RateDep s ic) -> T s u t (T (T ecAmp0 ec0, T ecAmp1 ec1) (T global (RateDep s ic))) -> T (Recip u) t -> (forall r. T r u t (Signal r ecAmp0 ec0)) -> (forall r. T r u t (Signal r ecAmp1 ec1)) -> T s u t (T s sampleIn sampleOut)

-- | This buffers internal control parameters before interpolation. This
--   should be faster, since interpolation needs frequent look-ahead, and
--   this is faster on a buffered signal than on a plain stateful signal
--   generator.
--   
--   Since the look-ahead is constant, it is interesting whether
--   interpolation can be made more efficient without the inefficient
--   intermediate list structure.
processAsynchronousBuffered2 :: (C global ic sampleIn sampleOut, C ecAmp0, C ecAmp1, C u, C t) => T t (RateDep s ic) -> T s u t (T (T ecAmp0 ec0, T ecAmp1 ec1) (T global (RateDep s ic))) -> T (Recip u) t -> (forall r. T r u t (Signal r ecAmp0 ec0)) -> (forall r. T r u t (Signal r ecAmp1 ec1)) -> T s u t (T s sampleIn sampleOut)
instance Synthesizer.Interpolation.Class.C a ic => Synthesizer.Interpolation.Class.C a (Synthesizer.Dimensional.Causal.ControlledProcess.RateDep s ic)
instance Foreign.Storable.Storable ic => Foreign.Storable.Storable (Synthesizer.Dimensional.Causal.ControlledProcess.RateDep s ic)


module Synthesizer.Dimensional.Amplitude.Filter

-- | The amplification factor must be positive.
amplify :: (C y, C u) => y -> T rate (Dimensional u y) body -> T rate (Dimensional u y) body
amplifyDimension :: (C y, C u, C v) => T v y -> T rate (Dimensional u y) body -> T rate (Dimensional (Mul v u) y) body
amplifyScalarDimension :: (C y, C v) => T v y -> T rate (Dimensional Scalar y) body -> T rate (Dimensional v y) body
negate :: (Transform sig yv, C yv) => T rate amp (sig yv) -> T rate amp (sig yv)
envelope :: (C y flat, C y) => T (Phantom s) flat (T y) -> T (Phantom s) amp (T y) -> T (Phantom s) amp (T y)

-- | This is like <a>envelope</a> but it does not require prior conversion
--   to a flat signal, what might violate the sample range (-1,1). Instead
--   the global amplitudes are multiplied.
envelopeScalarDimension :: (C v, C y) => R s Scalar y y -> R s v y y -> R s v y y
envelopeVector :: (C y0 flat, C y0 yv) => T (Phantom s) flat (T y0) -> T (Phantom s) amp (T yv) -> T (Phantom s) amp (T yv)
envelopeVectorDimension :: (C y0 yv, C y, C u, C v) => R s v y y0 -> R s u y yv -> R s (Mul v u) y yv


module Synthesizer.Dimensional.Rate.Filter
negate :: (C yv, C u) => T s u t (Signal s amp yv -> Signal s amp yv)
envelope :: (C y0 flat, C y0, C u) => T s u t (Signal s flat y0 -> Signal s amp y0 -> Signal s amp y0)
envelopeVector :: (C y0 flat, C y0 yv, C u) => T s u t (Signal s flat y0 -> Signal s amp yv -> Signal s amp yv)
convolveVector :: (C q yv, C q, C u) => T s u q (R s (Recip u) q q -> Signal s amp yv -> Signal s amp yv)

-- | needs a better handling of boundaries, yet
mean :: (C yv, C q, C q yv, C u, Storable q, Storable yv) => T (Recip u) q -> T s u q (R s (Recip u) q q -> Signal s amp yv -> Signal s amp yv)

-- | needs a better handling of boundaries, yet
meanStatic :: (C yv, C q, C q yv, C u) => T (Recip u) q -> T s u q (Signal s amp yv -> Signal s amp yv)
delay :: (C yv, C t, C u, Write sig yv) => T u t -> T s u t (T (Phantom s) amp (sig yv) -> T (Phantom s) amp (sig yv))
phaseModulation :: (C yv, C q, C u, Storable q, Storable yv) => T q yv -> T u q -> T u q -> T s u q (R s u q q -> Signal s amp yv -> Signal s amp yv)

-- | symmetric phaser
phaser :: (C yv, C q, C q yv, C u, Storable q, Storable yv) => T q yv -> T u q -> T s u q (R s u q q -> Signal s amp yv -> Signal s amp yv)
phaserStereo :: (C yv, C q, C q yv, C u, Storable q, Storable yv) => T q yv -> T u q -> T s u q (R s u q q -> Signal s amp yv -> Signal s amp (T yv))
frequencyModulation :: (C t flat, C yv, C t, C u) => T t yv -> T s u t (Signal s flat t -> Signal s amp yv -> Signal s amp yv)

-- | Frequency modulation where the input signal can have a sample rate
--   different from the output. (The sample rate values can differ, the
--   unit must be the same. We could lift that restriction, but then the
--   unit handling becomes more complicated, and I didn't have a use for it
--   so far.)
--   
--   The function can be used for resampling.
frequencyModulationDecoupled :: (C t flat, C yv, C t, C u) => T t yv -> T (Dimensional u t) amp (T yv) -> T s u t (Signal s flat t -> Signal s amp yv)
firstOrderLowpass :: (C q, C q yv, C u) => T s u q (R s (Recip u) q q -> Signal s amp yv -> Signal s amp yv)
firstOrderHighpass :: (C q, C q yv, C u) => T s u q (R s (Recip u) q q -> Signal s amp yv -> Signal s amp yv)
butterworthLowpass :: (C q flat, C q, C q yv, C u) => Int -> T s u q (Signal s flat q -> R s (Recip u) q q -> Signal s amp yv -> Signal s amp yv)
butterworthHighpass :: (C q flat, C q, C q yv, C u) => Int -> T s u q (Signal s flat q -> R s (Recip u) q q -> Signal s amp yv -> Signal s amp yv)
chebyshevALowpass :: (C q flat, C q, C q yv, C u) => Int -> T s u q (Signal s flat q -> R s (Recip u) q q -> Signal s amp yv -> Signal s amp yv)
chebyshevAHighpass :: (C q flat, C q, C q yv, C u) => Int -> T s u q (Signal s flat q -> R s (Recip u) q q -> Signal s amp yv -> Signal s amp yv)
chebyshevBLowpass :: (C q flat, C q, C q yv, C u) => Int -> T s u q (Signal s flat q -> R s (Recip u) q q -> Signal s amp yv -> Signal s amp yv)
chebyshevBHighpass :: (C q flat, C q, C q yv, C u) => Int -> T s u q (Signal s flat q -> R s (Recip u) q q -> Signal s amp yv -> Signal s amp yv)
universal :: (C q flat, C q, C q yv, C u) => T s u q (Signal s flat q -> R s (Recip u) q q -> Signal s amp yv -> Signal s amp (Result yv))
highpassFromUniversal :: Signal s amp (Result yv) -> Signal s amp yv
bandpassFromUniversal :: Signal s amp (Result yv) -> Signal s amp yv
lowpassFromUniversal :: Signal s amp (Result yv) -> Signal s amp yv
bandlimitFromUniversal :: Signal s amp (Result yv) -> Signal s amp yv
moogLowpass :: (C q flat, C q, C q yv, C u) => Int -> T s u q (Signal s flat q -> R s (Recip u) q q -> Signal s amp yv -> Signal s amp yv)
allpassCascade :: (C q, C q yv, C u) => Int -> q -> T s u q (R s (Recip u) q q -> Signal s amp yv -> Signal s amp yv)
allpassFlangerPhase :: C a => a

-- | Infinitely many equi-delayed exponentially decaying echos.
comb :: (C t, C y yv, C u, Storable yv) => T u t -> y -> T s u t (Signal s amp yv -> Signal s amp yv)
interpolateMultiRelativeZeroPad :: (C q, C yv) => T q yv -> T q -> T yv -> T yv


module Synthesizer.Dimensional.RateAmplitude.Filter

-- | The amplification factor must be positive.
amplify :: (C y, C u, C v) => y -> T s u t (R s v y yv -> R s v y yv)
amplifyDimension :: (C y, C u, C v0, C v1) => T v0 y -> T s u t (R s v1 y yv -> R s (Mul v0 v1) y yv)
negate :: (C yv, C u, C v) => T s u t (R s v y yv -> R s v y yv)
envelope :: (C y0 flat, C y0, C u, C v) => T s u t (FlatSignal s flat y0 -> R s v y y0 -> R s v y y0)
envelopeVector :: (C y0 flat, C y0 yv, C y, C u, C v) => T s u t (FlatSignal s flat y0 -> R s v y yv -> R s v y yv)
envelopeVectorDimension :: (C y0 yv, C y, C u, C v0, C v1) => T s u t (R s v0 y y0 -> R s v1 y yv -> R s (Mul v0 v1) y yv)
differentiate :: (C yv, C q, C u, C v) => T s u q (R s v q yv -> R s (DimensionGradient u v) q yv)

-- | Infinitely many equi-delayed exponentially decaying echos.
comb :: (C t, C y yv, C u, C v, Storable yv) => T u t -> y -> T s u t (R s v y yv -> R s v y yv)

-- | Infinitely many equi-delayed echos processed by an arbitrary
--   time-preserving signal processor.
combProc :: (C t, C y, C y, C y yv, C u, C v, Storable yv) => T u t -> T s u t (R s v y yv -> R s v y yv) -> T s u t (R s v y yv -> R s v y yv)


module Synthesizer.Dimensional.Causal.FilterParameter
highpassFromFirstOrder :: Single s amp amp (Result yv) yv
lowpassFromFirstOrder :: Single s amp amp (Result yv) yv
firstOrder :: (C u, C q, Arrow arrow) => T s u q (T arrow (Dimensional (Recip u) q q) (T FirstOrderGlobal (RateDep s (Parameter q))))
data FirstOrderGlobal
butterworthLowpass :: (Arrow arrow, C q, Storable q, C u) => Int -> SecondOrderCascade s u q arrow
butterworthHighpass :: (Arrow arrow, C q, Storable q, C u) => Int -> SecondOrderCascade s u q arrow
chebyshevALowpass :: (Arrow arrow, C q, Storable q, C u) => Int -> SecondOrderCascade s u q arrow
chebyshevAHighpass :: (Arrow arrow, C q, Storable q, C u) => Int -> SecondOrderCascade s u q arrow
chebyshevBLowpass :: (Arrow arrow, C q, Storable q, C u) => Int -> SecondOrderCascade s u q arrow
chebyshevBHighpass :: (Arrow arrow, C q, Storable q, C u) => Int -> SecondOrderCascade s u q arrow
data SecondOrderCascadeGlobal
allpassCascade :: (C u, C q, Arrow arrow) => Int -> q -> T s u q (T arrow (Dimensional (Recip u) q q) (T AllpassCascadeGlobal (RateDep s (Parameter q))))
data AllpassCascadeGlobal
allpassPhaser :: (C u, C q, Arrow arrow) => Int -> T s u q (T arrow (Dimensional Scalar q q, Dimensional (Recip u) q q) (T AllpassPhaserGlobal (RateDep s (q, Parameter q))))
data AllpassPhaserGlobal
allpassFlangerPhase :: C a => a
universal :: (C u, C q, Arrow arrow) => T s u q (T arrow (Dimensional Scalar q q, Dimensional (Recip u) q q) (T UniversalGlobal (RateDep s (Parameter q))))
data UniversalGlobal
highpassFromUniversal :: Single s amp amp (Result yv) yv
bandpassFromUniversal :: Single s amp amp (Result yv) yv
lowpassFromUniversal :: Single s amp amp (Result yv) yv
bandlimitFromUniversal :: Single s amp amp (Result yv) yv

-- | The returned arrow has intentionally no <tt>s</tt> type parameter, in
--   order to let you apply the parameter generator to control signals with
--   control sampling rate that is different from the one target audio
--   sampling rate.
moogLowpass :: (C u, C q, Arrow arrow) => Int -> T s u q (T arrow (Dimensional Scalar q q, Dimensional (Recip u) q q) (T MoogLowpassGlobal (RateDep s (Parameter q))))
data MoogLowpassGlobal
instance Synthesizer.Dimensional.Amplitude.C Synthesizer.Dimensional.Causal.FilterParameter.AllpassPhaserGlobal
instance Algebra.Module.C q yv => Synthesizer.Dimensional.Causal.ControlledProcess.C Synthesizer.Dimensional.Causal.FilterParameter.AllpassPhaserGlobal (q, Synthesizer.Plain.Filter.Recursive.Allpass.Parameter q) (Synthesizer.Dimensional.Sample.T amp yv) (Synthesizer.Dimensional.Sample.T amp yv)
instance Synthesizer.Dimensional.Amplitude.C Synthesizer.Dimensional.Causal.FilterParameter.AllpassCascadeGlobal
instance Algebra.Module.C q yv => Synthesizer.Dimensional.Causal.ControlledProcess.C Synthesizer.Dimensional.Causal.FilterParameter.AllpassCascadeGlobal (Synthesizer.Plain.Filter.Recursive.Allpass.Parameter q) (Synthesizer.Dimensional.Sample.T amp yv) (Synthesizer.Dimensional.Sample.T amp yv)
instance Synthesizer.Dimensional.Amplitude.C Synthesizer.Dimensional.Causal.FilterParameter.MoogLowpassGlobal
instance Algebra.Module.C q yv => Synthesizer.Dimensional.Causal.ControlledProcess.C Synthesizer.Dimensional.Causal.FilterParameter.MoogLowpassGlobal (Synthesizer.Plain.Filter.Recursive.Moog.Parameter q) (Synthesizer.Dimensional.Sample.T amp yv) (Synthesizer.Dimensional.Sample.T amp yv)
instance Synthesizer.Dimensional.Amplitude.C Synthesizer.Dimensional.Causal.FilterParameter.UniversalGlobal
instance Synthesizer.Dimensional.Amplitude.Primitive Synthesizer.Dimensional.Causal.FilterParameter.UniversalGlobal
instance Algebra.Module.C q yv => Synthesizer.Dimensional.Causal.ControlledProcess.C Synthesizer.Dimensional.Causal.FilterParameter.UniversalGlobal (Synthesizer.Plain.Filter.Recursive.Universal.Parameter q) (Synthesizer.Dimensional.Sample.T amp yv) (Synthesizer.Dimensional.Sample.T amp (Synthesizer.Plain.Filter.Recursive.Universal.Result yv))
instance Synthesizer.Dimensional.Amplitude.C Synthesizer.Dimensional.Causal.FilterParameter.SecondOrderCascadeGlobal
instance (Foreign.Storable.Storable q, Foreign.Storable.Storable yv, Algebra.Module.C q yv) => Synthesizer.Dimensional.Causal.ControlledProcess.C Synthesizer.Dimensional.Causal.FilterParameter.SecondOrderCascadeGlobal (Synthesizer.Plain.Filter.Recursive.SecondOrderCascade.Parameter q) (Synthesizer.Dimensional.Sample.T amp yv) (Synthesizer.Dimensional.Sample.T amp yv)
instance Synthesizer.Dimensional.Amplitude.C Synthesizer.Dimensional.Causal.FilterParameter.FirstOrderGlobal
instance Synthesizer.Dimensional.Amplitude.Primitive Synthesizer.Dimensional.Causal.FilterParameter.FirstOrderGlobal
instance Algebra.Module.C q yv => Synthesizer.Dimensional.Causal.ControlledProcess.C Synthesizer.Dimensional.Causal.FilterParameter.FirstOrderGlobal (Synthesizer.Plain.Filter.Recursive.FirstOrder.Parameter q) (Synthesizer.Dimensional.Sample.T amp yv) (Synthesizer.Dimensional.Sample.T amp (Synthesizer.Plain.Filter.Recursive.FirstOrder.Result yv))


module Synthesizer.Dimensional.Amplitude.Displacement

-- | Mix two signals. In contrast to <a>zipWith</a> the result has the
--   length of the longer signal.
mix :: (C y, C y, C y yv, C u) => R s u y yv -> R s u y yv -> R s u y yv
mixVolume :: (C y, C y, C y yv, C u) => T u y -> R s u y yv -> R s u y yv -> R s u y yv

-- | Mix one or more signals.
mixMulti :: (C y, C y, C y yv, C u) => [R s u y yv] -> R s u y yv
mixMultiVolume :: (C y, C y, C y yv, C u) => T u y -> [R s u y yv] -> R s u y yv

-- | Add a number to all of the signal values. This is useful for adjusting
--   the center of a modulation.
raise :: (C y, C u) => T u y -> T rate (Dimensional u y) (T y) -> T rate (Dimensional u y) (T y)
raiseVector :: (C y, C y yv, C u) => T u y -> yv -> T rate (Dimensional u y) (T yv) -> T rate (Dimensional u y) (T yv)

-- | Distort the signal using a flat function. The first signal gives the
--   scaling of the function. If the scaling is c and the input sample is
--   y, then <tt>c * f(y/c)</tt> is output. This way we can use an
--   (efficient) flat function and have a simple, yet dimension conform,
--   way of controlling the distortion. E.g. if the distortion function is
--   <tt>tanh</tt> then the value <tt>c</tt> controls the saturation level.
distort :: (C y, C y yv, C u) => (yv -> yv) -> R s u y y -> R s u y yv -> R s u y yv
map :: (Primitive amp) => (y0 -> y1) -> T rate amp (T y0) -> T rate amp (T y1)

-- | Map a control curve without amplitude unit by a linear (affine)
--   function with a unit. This is a combination of <a>raise</a> and
--   <tt>amplify</tt>.
mapLinear :: (C y flat, C y, C u) => y -> T u y -> T rate flat (T y) -> T rate (Dimensional u y) (T y)
mapExponential :: (C y flat, C y, C u) => y -> T u q -> T rate flat (T y) -> T rate (Dimensional u q) (T y)
mapLinearDimension :: (C y, C y, C u, C v) => T v y -> T (Mul v u) y -> T rate (Dimensional u y) (T y) -> T rate (Dimensional (Mul v u) y) (T y)

-- | I suspect that this function will most oftenly not the right choice.
--   When the amplitude is Flat, better use <a>inflate</a>. When the
--   amplitude is Numeric, better use
--   <tt>Filter.amplifyScalarDimension</tt> since this will not modify
--   signal values but only the global amplitude. This is both more
--   efficient and ensures boundedness of signal values.
inflateGeneric :: (C y flat, Transform sig y) => amp -> T rate flat (sig y) -> T rate (Numeric amp) (sig y)
inflate :: amp -> T rate (Flat y) sig -> T rate (Numeric amp) sig


module Synthesizer.Dimensional.RateAmplitude.Displacement

-- | Mix two signals. In opposition to <a>zipWith</a> the result has the
--   length of the longer signal.
mix :: (C y, C y, C y yv, C v) => T s u t (R s v y yv -> R s v y yv -> R s v y yv)
mixVolume :: (C y, C y, C y yv, C v) => T v y -> T s u t (R s v y yv -> R s v y yv -> R s v y yv)

-- | Mix one or more signals.
mixMulti :: (C y, C y, C y yv, C v) => T s u t ([R s v y yv] -> R s v y yv)
mixMultiVolume :: (C y, C y, C y yv, C v) => T v y -> T s u t ([R s v y yv] -> R s v y yv)

-- | Add a number to all of the signal values. This is useful for adjusting
--   the center of a modulation.
raise :: (C y, C v) => T v y -> T s u t (R s v y y -> R s v y y)
raiseVector :: (C y, C y yv, C v) => T v y -> yv -> T s u t (R s v y yv -> R s v y yv)

-- | Distort the signal using a flat function. The first signal gives the
--   scaling of the function. If the scaling is c and the input sample is
--   y, then <tt>c * f(y/c)</tt> is output. This way we can use an
--   (efficient) flat function and have a simple, yet dimension conform,
--   way of controlling the distortion. E.g. if the distortion function is
--   <tt>tanh</tt> then the value <tt>c</tt> controls the saturation level.
distort :: (C y, C y yv, C v) => (yv -> yv) -> T s u t (R s v y y -> R s v y yv -> R s v y yv)


module Synthesizer.Dimensional.Amplitude.Cut
unzip :: (Transform sig (yv0, yv1), Transform sig yv0, Transform sig yv1) => T rate amp (sig (yv0, yv1)) -> (T rate amp (sig yv0), T rate amp (sig yv1))
unzip3 :: (Transform sig (yv0, yv1, yv2), Transform sig yv0, Transform sig yv1, Transform sig yv2) => T rate amp (sig (yv0, yv1, yv2)) -> (T rate amp (sig yv0), T rate amp (sig yv1), T rate amp (sig yv2))
leftFromStereo :: (C u) => R s u y (T yv) -> R s u y yv
rightFromStereo :: (C u) => R s u y (T yv) -> R s u y yv
span :: (Transform sig yv, C v, C y, C y yv) => T v y -> (yv -> Bool) -> (T rate (Dimensional v y) (sig yv) -> (T rate (Dimensional v y) (sig yv), T rate (Dimensional v y) (sig yv)))
dropWhile :: (Transform sig yv, C v, C y, C y yv) => T v y -> (yv -> Bool) -> T rate (Dimensional v y) (sig yv) -> T rate (Dimensional v y) (sig yv)
takeWhile :: (Transform sig yv, C v, C y, C y yv) => T v y -> (yv -> Bool) -> T rate (Dimensional v y) (sig yv) -> T rate (Dimensional v y) (sig yv)
spanPrimitive :: (Transform sig y, Primitive amp) => (y -> Bool) -> (T rate amp (sig y) -> (T rate amp (sig y), T rate amp (sig y)))
dropWhilePrimitive :: (Transform sig y, Primitive amp) => (y -> Bool) -> T rate amp (sig y) -> T rate amp (sig y)
takeWhilePrimitive :: (Transform sig y, Primitive amp) => (y -> Bool) -> T rate amp (sig y) -> T rate amp (sig y)

-- | Similar to <tt>foldr1 append</tt> but more efficient and accurate,
--   because it reduces the number of amplifications. Does not work for
--   infinite lists, because no maximum amplitude can be computed.
concat :: (Ord y, C y, C u, C y yv, Transform sig yv) => [Signal s u y sig yv] -> Signal s u y sig yv

-- | Give the output volume explicitly. Does also work for infinite lists.
concatVolume :: (C y, C u, C y yv, Transform sig yv) => T u y -> [Signal s u y sig yv] -> Signal s u y sig yv
concatPrimitive :: (Transform sig, Primitive amp) => [T (Phantom s) amp sig] -> T (Phantom s) amp sig
append :: (Ord y, C y, C u, C y yv, Transform sig yv) => Signal s u y sig yv -> Signal s u y sig yv -> Signal s u y sig yv
appendVolume :: (C y, C u, C y yv, Transform sig yv) => T u y -> Signal s u y sig yv -> Signal s u y sig yv -> Signal s u y sig yv
appendPrimitive :: (Transform sig, Primitive amp) => T (Phantom s) amp sig -> T (Phantom s) amp sig -> T (Phantom s) amp sig
zip :: (Ord y, C y, C u, C y yv0, C y yv1, Read sig yv0, Transform sig yv1, Transform sig (yv0, yv1)) => Signal s u y sig yv0 -> Signal s u y sig yv1 -> Signal s u y sig (yv0, yv1)
zipVolume :: (C y, C u, C y yv0, C y yv1, Read sig yv0, Transform sig yv1, Transform sig (yv0, yv1)) => T u y -> Signal s u y sig yv0 -> Signal s u y sig yv1 -> Signal s u y sig (yv0, yv1)
zip3 :: (Ord y, C y, C u, C y yv0, C y yv1, C y yv2, Read sig yv0, Read sig yv1, Transform sig yv2, Transform sig (yv0, yv1, yv2)) => Signal s u y sig yv0 -> Signal s u y sig yv1 -> Signal s u y sig yv2 -> Signal s u y sig (yv0, yv1, yv2)
zip3Volume :: (C y, C u, C y yv0, C y yv1, C y yv2, Read sig yv0, Read sig yv1, Transform sig yv2, Transform sig (yv0, yv1, yv2)) => T u y -> Signal s u y sig yv0 -> Signal s u y sig yv1 -> Signal s u y sig yv2 -> Signal s u y sig (yv0, yv1, yv2)
mergeStereo :: (Ord y, C y, C u, C y yv, Transform sig yv, Transform sig (T yv)) => Signal s u y sig yv -> Signal s u y sig yv -> Signal s u y sig (T yv)
mergeStereoVolume :: (C y, C u, C y yv, Transform sig yv, Transform sig (T yv)) => T u y -> Signal s u y sig yv -> Signal s u y sig yv -> Signal s u y sig (T yv)
mergeStereoPrimitive :: (Primitive amp, Transform sig y, Transform sig (T y)) => T (Phantom s) amp (sig y) -> T (Phantom s) amp (sig y) -> T (Phantom s) amp (sig (T y))
selectBool :: (Ord y, C y, C u, C y yv, Read sig yv, Transform sig Bool, Transform sig yv) => Signal s u y sig yv -> Signal s u y sig yv -> T (Phantom s) Abstract (sig Bool) -> Signal s u y sig yv
reverse :: (Transform sig yv) => T rate amp (sig yv) -> T rate amp (sig yv)


module Synthesizer.Dimensional.RateAmplitude.Cut
splitAt :: (C t, C u, C v, Storable yv) => T u t -> T s u t (R s v y yv -> (R s v y yv, R s v y yv))
take :: (C t, C u, C v) => T u t -> T s u t (R s v y yv -> R s v y yv)
drop :: (C t, C u, C v) => T u t -> T s u t (R s v y yv -> R s v y yv)
takeUntilPause :: (C t, C u, C y, C y yv, C v) => T v y -> T u t -> T s u t (R s v y yv -> R s v y yv)
unzip :: (C u, C v) => T s u t (R s v y (yv0, yv1) -> (R s v y yv0, R s v y yv1))
unzip3 :: (C u, C v) => T s u t (R s v y (yv0, yv1, yv2) -> (R s v y yv0, R s v y yv1, R s v y yv2))
leftFromStereo :: (C u) => T s u t (R s u y (T yv) -> R s u y yv)
rightFromStereo :: (C u) => T s u t (R s u y (T yv) -> R s u y yv)

-- | Similar to <tt>foldr1 append</tt> but more efficient and accurate,
--   because it reduces the number of amplifications. Does not work for
--   infinite lists, because no maximum amplitude can be computed.
concat :: (Ord y, C y, C v, C u, C y yv) => T s u t ([R s v y yv] -> R s v y yv)

-- | Give the output volume explicitly. Does also work for infinite lists.
concatVolume :: (C y, C v, C u, C y yv) => T v y -> T s u t ([R s v y yv] -> R s v y yv)
append :: (Ord y, C y, C v, C u, C y yv) => T s u t (R s v y yv -> R s v y yv -> R s v y yv)
appendVolume :: (C y, C v, C u, C y yv) => T v y -> T s u t (R s v y yv -> R s v y yv -> R s v y yv)
zip :: (Ord y, C y, C v, C y yv0, C y yv1) => T s u t (R s v y yv0 -> R s v y yv1 -> R s v y (yv0, yv1))
zipVolume :: (C y, C v, C y yv0, C y yv1) => T v y -> T s u t (R s v y yv0 -> R s v y yv1 -> R s v y (yv0, yv1))
zip3 :: (Ord y, C y, C v, C y yv0, C y yv1, C y yv2) => T s u t (R s v y yv0 -> R s v y yv1 -> R s v y yv2 -> R s v y (yv0, yv1, yv2))
zip3Volume :: (C y, C v, C y yv0, C y yv1, C y yv2) => T v y -> T s u t (R s v y yv0 -> R s v y yv1 -> R s v y yv2 -> R s v y (yv0, yv1, yv2))
mergeStereo :: (Ord y, C y, C v, C y yv) => T s u t (R s v y yv -> R s v y yv -> R s v y (T yv))
mergeStereoVolume :: (C y, C v, C y yv) => T v y -> T s u t (R s v y yv -> R s v y yv -> R s v y (T yv))

-- | Uses maximum input volume as output volume. Does not work for infinite
--   schedules, because no maximum amplitude can be computed.
arrange :: (C t, C u, RealFrac t, Ord y, C y, C v, C y yv, Storable yv) => T u t -> T u t -> T s u t (T (T t) (R s v y yv) -> R s v y yv)

-- | Given a list of signals with time stamps, mix them into one signal as
--   they occur in time. Ideal for composing music.
arrangeVolume :: (C t, C u, RealFrac t, C y, C v, C y yv, Storable yv) => T u t -> T v y -> T u t -> T s u t (T (T t) (R s v y yv) -> R s v y yv)
arrangeStorableVolume :: (C t, C u, RealFrac t, C y, C v, C y yv, Storable yv) => T u t -> T v y -> T u t -> T s u t (T (T t) (T (Phantom s) (Dimensional v y) (T yv)) -> (T (Phantom s) (Dimensional v y) (T yv)))


-- | Control curves which can be used as envelopes, for controlling filter
--   parameters and so on.
module Synthesizer.Dimensional.Amplitude.Control
constant :: (C y, C u) => T u y -> R s u y y

-- | The amplitude must be positive! This is not checked.
constantVector :: T u y -> yv -> R s u y yv
piecewiseConstantGeneric :: (Write sig y) => T rate amp (T y) -> T rate amp (sig y)
piecewiseConstantStorable :: (Storable y) => T rate amp (T y) -> T rate amp (T y)


-- | Signals equipped with volume and sample rate information that may
--   carry a unit. Kind of volume and sample rate is configurable by types.
module Synthesizer.Dimensional.Signal

-- | A signal value 0.5 at global amplitude 1 and signal value 1 at global
--   amplitude 0.5 shall represent the same signal. Thus observing the
--   amplitude breaks the abstraction.
--   
--   Cyclic nature such as needed for Fourier transform must be expressend
--   in the body. It would be nice to use the data type for waveforms, too,
--   but for waveforms the <tt>rate</tt> parameter makes no sense.
data T rate amplitude body
type R s v y yv = T (Phantom s) (Dimensional v y) (T yv)
asTypeOfAmplitude :: y -> T rate (Dimensional v y) sig -> y
render :: (C u) => T (Recip u) t -> (forall s. T s u t (T (Phantom s) amp sig)) -> T (Dimensional u t) amp sig
apply :: (C u) => (forall s. T s u t (T (Phantom s) amp0 sig0 -> T (Phantom s) amp1 sig1)) -> T (Dimensional u t) amp0 sig0 -> T (Dimensional u t) amp1 sig1
cache :: (Storable yv) => T rate amp (T yv) -> T rate amp (T yv)
bindCached :: (Storable yv) => T s u t (T rate amp (T yv)) -> (T rate amp (T yv) -> T s u t b) -> T s u t b
share :: (Storable yv) => T s u t (T rate amp (T yv)) -> (T s u t (T rate amp (T yv)) -> T s u t b) -> T s u t b
store :: (C t, C u, Storable yv) => T u t -> T s u t (T (Phantom s) amp (T yv) -> T (Phantom s) amp (T yv))
restore :: (Read sig yv) => T rate amp (sig yv) -> T rate amp (T yv)

-- | Take a scalar argument where a process expects a signal. Only possible
--   for non-negative values so far.
($-) :: (C y, C y, C u, C v) => T s u t (R s v y y -> a) -> T v y -> T s u t a
infixl 0 $-
($&) :: Applicative f => f (a -> b) -> f a -> f b
(&*^) :: (C y flat, Transform sig y) => amp -> T s u t (T rate flat (sig y)) -> T s u t (T rate (Numeric amp) (sig y))
infix 7 &*^
(&*>^) :: amp -> T s u t (T rate (Flat y) sig) -> T s u t (T rate (Numeric amp) sig)
infix 7 &*>^


-- | Control curves which can be used as envelopes, for controlling filter
--   parameters and so on.
module Synthesizer.Dimensional.RateAmplitude.Control
constant :: (C y, C u, C v) => T v y -> T s u t (R s v y y)

-- | The amplitude must be positive! This is not checked.
constantVector :: T v y -> yv -> T s u t (R s v y yv)

-- | Caution: This control curve can contain samples with an absolute value
--   greater than 1.
--   
--   Linear curves starting with zero are impossible. Maybe you prefer
--   using <a>line</a>.
linear :: (C q, C q, C u, C v) => T (DimensionGradient u v) q -> T v q -> T s u q (R s v q q)

-- | Generates a finite ramp.
line :: (C q, C u, C v) => T u q -> (T v q, T v q) -> T s u q (R s v q q)
exponential :: (C q, C q, C u, C v) => T u q -> T v q -> T s u q (R s v q q)
exponential2 :: (C q, C q, C u, C v) => T u q -> T v q -> T s u q (R s v q q)

-- | Generate an exponential curve through two nodes.
exponentialFromTo :: (C q, C q, C u, C v) => T u q -> (T v q, T v q) -> T s u q (R s v q q)
cubicHermite :: (C q, C u, C v) => (T u q, (T v q, T (DimensionGradient u v) q)) -> (T u q, (T v q, T (DimensionGradient u v) q)) -> T s u q (R s v q q)


module Synthesizer.Dimensional.Amplitude.Analysis
beginning :: (C y, C v, Transform sig y) => T rate (Dimensional v y) (sig y) -> T v y
end :: (C y, C v, Transform sig y) => T rate (Dimensional v y) (sig y) -> T v y
beginningPrimitive :: (Primitive amp, Transform sig y) => y -> T rate amp (sig y) -> y
endPrimitive :: (Primitive amp, Transform sig y) => y -> T rate amp (sig y) -> y

-- | Volume based on Manhattan norm.
volumeMaximum :: (C y, C u) => SignalRateInd rate u y y -> T u y

-- | Volume based on Energy norm.
volumeEuclidean :: (C y, C u) => SignalRateInd rate u y y -> T u y

-- | Volume based on Sum norm.
volumeSum :: (C y, C y, C u) => SignalRateInd rate u y y -> T u y

-- | Volume based on Manhattan norm.
volumeVectorMaximum :: (C y yv, Ord y, C u) => SignalRateInd rate u y yv -> T u y

-- | Volume based on Energy norm.
volumeVectorEuclidean :: (C y yv, C y, C u) => SignalRateInd rate u y yv -> T u y

-- | Volume based on Sum norm.
volumeVectorSum :: (C y yv, C y, C u) => SignalRateInd rate u y yv -> T u y

-- | Requires finite length. This is identical to the arithmetic mean.
directCurrentOffset :: (C y, C u) => SignalRateInd rate u y y -> T u y
rectify :: (C y) => T rate amp (T y) -> T rate amp (T y)

-- | Detect thresholds with a hysteresis.
flipFlopHysteresis :: (Ord y, C y, C u) => (T u y, T u y) -> BinaryLevel -> SignalRateInd rate u y y -> T rate Abstract (T BinaryLevel)
compare :: (Ord y, C y, C u, C y yv, Ord yv) => R s u y yv -> R s u y yv -> T (Phantom s) Abstract (T Ordering)
lessOrEqual :: (Ord y, C y, C u, C y yv, Ord yv) => R s u y yv -> R s u y yv -> T (Phantom s) Abstract (T Bool)


module Synthesizer.Dimensional.RateAmplitude.Analysis
centroid :: (C q, C u) => SignalRate u q amp q -> T u q
length :: (C t, C u) => SignalRate u t amp yv -> T u t
beginning :: (C y, C v, Transform sig y) => T rate (Dimensional v y) (sig y) -> T v y
end :: (C y, C v, Transform sig y) => T rate (Dimensional v y) (sig y) -> T v y

-- | Manhattan norm.
normMaximum :: (C y, C u, C v) => Signal u t v y y -> T v y

-- | Manhattan norm.
normVectorMaximum :: (C q yv, Ord q, C u, C v) => Signal u q v q yv -> T v q

-- | Square of energy norm.
--   
--   Could also be called <tt>variance</tt>.
normEuclideanSqr :: (C q, C u, C v) => Signal u q v q q -> T (Mul u (Sqr v)) q

-- | Energy norm.
normVectorEuclideanSqr :: (C q yv, C q, C u, C v) => Signal u q v q yv -> T (Mul u (Sqr v)) q

-- | Sum norm.
normSum :: (C q, C q, C u, C v) => Signal u q v q q -> T (Mul u v) q

-- | Sum norm.
normVectorSum :: (C q yv, C q, C u, C v) => Signal u q v q yv -> T (Mul u v) q

-- | Manhattan norm.
normMaximumProc :: (C y, C u, C v) => T s u y (R s v y y -> T v y)

-- | Manhattan norm.
normVectorMaximumProc :: (C y yv, Ord y, C u, C v) => T s u y (R s v y yv -> T v y)

-- | Square of energy norm.
--   
--   Could also be called <tt>variance</tt>.
normEuclideanSqrProc :: (C q, C u, C v) => T s u q (R s v q q -> T (Mul u (Sqr v)) q)

-- | Energy norm.
normVectorEuclideanSqrProc :: (C y yv, C y, C u, C v) => T s u y (R s v y yv -> T (Mul u (Sqr v)) y)

-- | Sum norm.
normSumProc :: (C q, C q, C u, C v) => T s u q (R s v q q -> T (Mul u v) q)

-- | Sum norm.
normVectorSumProc :: (C y yv, C y, C u, C v) => T s u y (R s v y yv -> T (Mul u v) y)
histogram :: (C q, C u, C v) => Signal u q v q q -> T s v q (Int, R s (DimensionGradient v u) q q)

-- | Detects zeros (sign changes) in a signal. This can be used as a simple
--   measure of the portion of high frequencies or noise in the signal. The
--   result has a frequency as amplitude. If you smooth it, you will get a
--   curve that represents a frequency progress. It ca be used as
--   voiced/unvoiced detector in a vocoder.
--   
--   The result will be one value shorter than the input.
zeros :: (Ord q, C q, C u, C v) => T s u q (R s v q q -> R s (Recip u) q q)

module Synthesizer.Dimensional.Wave
type SamplePhase t = Abstract (T t)

-- | We define a dimensional waveform in terms of a Map. This allows any
--   kind and number of result samples and distortion of waveforms using
--   <tt>(distortion &lt;&lt;&lt;)</tt>
type T t y = T (SamplePhase t) y
simple :: amp -> T t y -> T t (T amp y)
(&*~) :: amp -> T t y -> T t (Numeric amp y)
infix 7 &*~
sample :: (C t, Transform sig y) => T t y -> T rate amp (sig y) -> T t (T amp y)
flat :: (C y) => T t y -> T t (Flat y)
abstract :: T t y -> T t (Abstract y)
amplified :: amp -> T t y -> T t (Numeric amp y)
mapLinear :: (C y, C u) => y -> T u y -> T t y -> T t (Dimensional u y y)
mapExponential :: (C y, C u) => y -> T u y -> T t y -> T t (Dimensional u y y)


-- | Turn frequency information into signals of phases. This is mainly the
--   fundament for implementation of oscillators but you may also use it
--   for generating coherent waves of different form.
module Synthesizer.Dimensional.Causal.Oscillator.Core
type Frequency u t = Numeric (T (Recip u) t)
type SampleFrequency u t = T (Frequency u t) t
static :: (C t, C u) => T t -> T (Recip u) t -> T s u t (T (Phantom s) Abstract (T (T t)))
phaseMod :: (C t, C u) => T (Recip u) t -> T s u t (T s (Flat t) (SamplePhase t))
freqMod :: (C t, C u) => T t -> T s u t (T s (SampleFrequency u t) (SamplePhase t))
phaseFreqMod :: (C t, C u) => T s u t (T s (Flat t, SampleFrequency u t) (SamplePhase t))

module Synthesizer.Dimensional.Wave.Controlled

-- | We define a dimensional parametrized waveform in terms of a Map. This
--   allows any kind and number of control parameters and distortion of
--   waveforms using <tt>(distortion &lt;&lt;&lt;)</tt>
type T c t y = T (c, SamplePhase t) y
simple :: (Primitive cAmp) => amp -> (c -> T t y) -> T (T cAmp c) t (T amp y)
flat :: (C y, Primitive cAmp) => (c -> T t y) -> T (T cAmp c) t (Flat y)
abstract :: (Primitive cAmp) => (c -> T t y) -> T (T cAmp c) t (Abstract y)
amplified :: (C y, C u, Primitive cAmp) => T u y -> (c -> T t y) -> T (T cAmp c) t (Dimensional u y y)
mapLinear :: (C y, C u, Primitive cAmp) => y -> T u y -> (c -> T t y) -> T (T cAmp c) t (Dimensional u y y)
mapExponential :: (C y, C u, Primitive cAmp) => y -> T u y -> (c -> T t y) -> T (T cAmp c) t (Dimensional u y y)

-- | Interpolate first within waves and then across waves, which is simpler
--   but maybe less efficient for lists. However for types with fast
--   indexing/drop like StorableVector this is optimal.
sampledTone :: (C t, Transform sig y, C u) => T t y -> T t y -> T u t -> T (Dimensional u t) amp (sig y) -> T (Flat t) t (T amp y)


module Synthesizer.Dimensional.Causal.Oscillator

-- | oscillator with a functional waveform with modulated frequency
freqMod :: (C t, C u) => T t y -> T t -> T s u t (T s (SampleFrequency u t) y)

-- | oscillator with modulated phase
phaseMod :: (C t, C u) => T t y -> T (Recip u) t -> T s u t (T s (Flat t) y)

-- | oscillator with a functional waveform with modulated phase and
--   frequency
phaseFreqMod :: (C t, C u) => T t y -> T s u t (T s (Flat t, SampleFrequency u t) y)

-- | oscillator with modulated shape
shapeMod :: (C t, C u) => T c t y -> T t -> T (Recip u) t -> T s u t (T s c y)

-- | oscillator with both shape and frequency modulation
shapeFreqMod :: (C t, C u) => T c t y -> T t -> T s u t (T s (c, SampleFrequency u t) y)
shapeFreqModFromSampledTone :: (C t, Transform sig yv, C u) => T t yv -> T t yv -> T (Recip u) t -> T (Dimensional u t) amp (sig yv) -> t -> T t -> T s u t (T s (Flat t, SampleFrequency u t) (T amp yv))
shapePhaseFreqModFromSampledTone :: (C t, Transform sig yv, C u) => T t yv -> T t yv -> T (Recip u) t -> T (Dimensional u t) amp (sig yv) -> t -> T t -> T s u t (T s (Flat t, Flat t, SampleFrequency u t) (T amp yv))


-- | This module contains various oscillators that respect physical
--   dimensions. By using the type variable <tt>amp</tt> we show, that the
--   oscillators are homogeneous functions. But since there are even no
--   restrictions on the sample type, we even show that values from the
--   waveform go untouched to the output signal.
module Synthesizer.Dimensional.Rate.Oscillator

-- | oscillator with a functional waveform with constant frequency
static :: (C t, C u) => T t (T amp y) -> T t -> T (Recip u) t -> T s u t (Signal s amp y)

-- | oscillator with a functional waveform with modulated frequency
freqMod :: (C t, C u) => T t (T amp y) -> T t -> T s u t (R s (Recip u) t t -> Signal s amp y)

-- | oscillator with modulated phase
phaseMod :: (C t flat, C t, C u) => T t (T amp y) -> T (Recip u) t -> T s u t (Signal s flat t -> Signal s amp y)

-- | oscillator with a functional waveform with modulated phase and
--   frequency
phaseFreqMod :: (C t flat, C t, C u) => T t (T amp y) -> T s u t (Signal s flat t -> R s (Recip u) t t -> Signal s amp y)

-- | oscillator with modulated shape
shapeMod :: (C t, C u) => T (T cAmp c) t (T amp y) -> T t -> T (Recip u) t -> T s u t (Signal s cAmp c -> Signal s amp y)

-- | oscillator with both shape and frequency modulation
shapeFreqMod :: (C t, C u) => T (T cAmp c) t (T amp y) -> T t -> T s u t (Signal s cAmp c -> R s (Recip u) t t -> Signal s amp y)

-- | oscillator with a sampled waveform with constant frequency This is
--   essentially an interpolation with cyclic padding. You can also achieve
--   this with a waveform constructed by <a>sample</a>.
staticSample :: (C t, C u) => T t y -> T rate amp (T (T y)) -> T t -> T (Recip u) t -> T s u t (Signal s amp y)

-- | oscillator with a sampled waveform with modulated frequency Should
--   behave homogenously for different types of interpolation.
freqModSample :: (C t, C u) => T t y -> T rate amp (T (T y)) -> T t -> T s u t (R s (Recip u) t t -> Signal s amp y)
shapeFreqModFromSampledTone :: (C t, C u, C t flat) => T t yv -> T t yv -> T (Recip u) t -> T (Dimensional u t) amp (T yv) -> t -> T t -> T s u t (Signal s flat t -> R s (Recip u) t t -> Signal s amp yv)
shapePhaseFreqModFromSampledTone :: (C t, C u, C t flatS, C t flatP) => T t yv -> T t yv -> T (Recip u) t -> T (Dimensional u t) amp (T yv) -> t -> T t -> T s u t (Signal s flatS t -> Signal s flatP t -> R s (Recip u) t t -> Signal s amp yv)

module Synthesizer.Dimensional.RateAmplitude.Instrument

-- | Create a sound of a slightly changed frequency just as needed for a
--   simple stereo sound.
stereoPhaser :: C a => (T Frequency a -> T s Time a (R s u b b)) -> a -> T Frequency a -> T s Time a (R s u b b)
allpassDown :: (C a, C a, C a a) => Int -> T Time a -> T Frequency a -> T Frequency a -> T s Time a (R s Voltage a a)
moogDown :: (C a, C a, C a a) => Int -> T Time a -> T Frequency a -> T Frequency a -> T s Time a (R s Voltage a a)
moogReso :: (C a, C a, C a a) => Int -> T Time a -> T Frequency a -> T Frequency a -> T s Time a (R s Voltage a a)
bell :: (C a, C a, C a a) => T Frequency a -> T s Time a (R s Voltage a a)
bellHarmonic :: (C a, C a, C a a) => a -> T Time a -> T Frequency a -> T s Time a (R s Voltage a a)
fastBell :: (C a, C a, C a a) => T Frequency a -> T s Time a (R s Voltage a a)
squareBell :: (C a, C a, C a a) => T Frequency a -> T s Time a (R s Voltage a a)
moogGuitar :: (C a, C a, C a a) => T Frequency a -> T s Time a (R s Voltage a a)
moogGuitarSoft :: (C a, C a, C a a) => T Frequency a -> T s Time a (R s Voltage a a)
fatSaw :: (C a, C a, C a a) => T Frequency a -> T s Time a (R s Voltage a a)
filterSaw :: (C a a, C a, C a) => T Frequency a -> T Frequency a -> T s Time a (R s Voltage a a)
fmBell :: (C a, C a, C a a) => a -> a -> T Frequency a -> T s Time a (R s Voltage a a)

-- | Phase modulation using a ring modulated signal. May be used as some
--   kind of e-guitar.
fmRing :: (C a, C a, C a a) => T Frequency a -> T s Time a (R s Voltage a a)
fatPad :: (C a, C a, C a a, Random a) => T Frequency a -> T s Time a (R s Voltage a a)
brass :: (C a, C a, C a a, Random a) => T Frequency a -> T s Time a (R s Voltage a a)

-- | low pass with resonance
filterSweep :: (C a v, C a, C a) => T a -> T s Time a (R s Voltage a v -> R s Voltage a v)
fatSawChordFilter :: (C a, C a, C a a) => T Frequency a -> T s Time a (R s Voltage a a)
fatSawChord :: (C a, C a, C a a) => T Frequency a -> T s Time a (R s Voltage a a)
filterDown :: (C a, C a) => T s Time a (R s Frequency a a)
simpleSaw :: (C a, C u, C v) => T (Recip u) v -> T s u v (R s Voltage a v)

-- | accumulate multiple similar saw sounds and observe the increase of
--   volume The oscillator <tt>osc</tt> must accept relative frequencies.
modulatedWave :: (C a, C a, C u) => T s u a (R s (Recip u) a a -> R s Voltage a a) -> T (Recip u) a -> a -> T a -> T (Recip u) a -> T s u a (R s Voltage a a)
accumulationParameters :: (Random a, C a, C a, C a a) => [(T a, a, T a, T Frequency a)]
accumulatedSaws :: (Random a, C a, C a, C a a) => T Frequency a -> T s Time a (R s Voltage a a)
choir :: (Random a, C a, C a, C a a) => T Frequency a -> T s Time a (R s Voltage a a)

-- | A good choice is <tt>freq = DN.frequency 110</tt>
wasp :: (C q, C q, C q q, Random q, C u) => T (Recip u) q -> T s u q (R s Voltage q q)
osciDoubleSaw :: (C a, C a a, C u) => T s u a (R s (Recip u) a a -> R s Voltage a a)
sampledWave :: (C t) => T t y -> amp -> [y] -> T t (Numeric amp y)

-- | A tone with a waveform with roughly the dependency <tt>x -&gt;
--   x^?p</tt>, where the waveform is normalized to constant quadratic norm
osciSharp :: (C a, C a) => T Frequency a -> T s Time a (R s Voltage a a)

-- | Build a saw sound from its harmonics and modulate it. Different to
--   normal modulation I modulate each harmonic with the same depth rather
--   than a proportional one.
osciAbsModSaw :: (C a, C a, C a a) => T Frequency a -> T s Time a (R s Voltage a a)

-- | Short pulsed Noise.white, i.e. Noise.white amplified with pulses of
--   varying H/L ratio.
pulsedNoise :: (Random a, C a, C a, C a a) => T Frequency a -> T s Time a (R s Voltage a a)
noisePerc :: (Random a, C a, C a) => T s Time a (R s Voltage a a)
noiseBass :: (Random a, C a, C a, C a a, Storable a) => T Frequency a -> T s Time a (R s Voltage a a)

-- | Drum sound using the Karplus-Strong-Algorithm This is a Noise.white
--   enveloped by an exponential2 which is piped through the Karplus-Strong
--   machine for generating some frequency. The whole thing is then
--   frequency modulated to give a falling frequency.
electroTom :: (Random a, C a, C a, C a a, Storable a) => T s Time a (R s Voltage a a)
bassDrum :: (C q, C q, C q q, Random q) => T s Time q (R s Voltage q q)
