synthesizer-core-0.8.2: Audio signal processing coded in Haskell: Low level part

Copyright(c) Henning Thielemann 2006-2010
LicenseGPL
Maintainersynthesizer@henning-thielemann.de
Stabilityprovisional
Portabilityrequires multi-parameter type classes
Safe HaskellNone
LanguageHaskell2010

Synthesizer.Basic.Wave

Description

Basic waveforms

If you want to use parametrized waves with two parameters then zip your parameter signals and apply uncurry to the wave function.

Synopsis

Documentation

newtype T t y Source #

Constructors

Cons 

Fields

Instances

C a y => C a (T t y) Source # 

Methods

(*>) :: a -> T t y -> T t y #

Functor (T t) Source # 

Methods

fmap :: (a -> b) -> T t a -> T t b #

(<$) :: a -> T t b -> T t a #

Applicative (T t) Source # 

Methods

pure :: a -> T t a #

(<*>) :: T t (a -> b) -> T t a -> T t b #

liftA2 :: (a -> b -> c) -> T t a -> T t b -> T t c #

(*>) :: T t a -> T t b -> T t b #

(<*) :: T t a -> T t b -> T t a #

C y => C (T t y) Source # 

Methods

zero :: T t y #

(+) :: T t y -> T t y -> T t y #

(-) :: T t y -> T t y -> T t y #

negate :: T t y -> T t y #

fromFunction :: (t -> y) -> T t y Source #

raise :: C y => y -> T t y -> T t y Source #

amplify :: C y => y -> T t y -> T t y Source #

distort :: (y -> z) -> T t y -> T t z Source #

overtone :: (C t, C n) => n -> T t y -> T t y Source #

apply :: T t y -> T t -> y Source #

phaseOffset :: C a => T a b -> a -> T a b Source #

Turn an unparametrized waveform into a parametrized one, where the parameter is a phase offset. This way you may express a phase modulated oscillator using a shape modulated oscillator.

flip phaseOffset could have also be named rotateLeft, since it rotates the wave to the left.

sine :: C a => T a a Source #

map a phase to value of a sine wave

cosine :: C a => T a a Source #

helix :: C a => T a (T a) Source #

fastSine2 :: (Ord a, C a) => T a a Source #

Approximation of sine by parabolas. Surprisingly it is not really faster than sine. The wave results from integrating the triangle wave, thus it the k-th harmonic has amplitude recip (k^3).

fastSine2Alt :: C a => T a a Source #

fastSine3 :: (Ord a, C a) => T a a Source #

Piecewise third order polynomial approximation by integrating fastSine2.

fastSine3Alt :: (C a, C a) => T a a Source #

fastSine4 :: (Ord a, C a) => T a a Source #

Piecewise fourth order polynomial approximation by integrating fastSine3.

fastSine4Alt :: (C a, C a) => T a a Source #

fastSine4LeastSquares :: (Ord a, C a) => T a a Source #

Least squares approximation of sine by fourth order polynomials computed with MuPad.

fastSinePolynomials :: C a => [T a] Source #

The coefficient of the highest power is the reciprocal of an element from http://oeis.org/A000111 and the polynomial coefficients are http://oeis.org/A119879 .

mapM_ print $ map (\p -> fmap ((round :: Rational -> Integer) . (/last(Poly.coeffs p))) p) (take 10 $ fastSinePolynomials)

fastSines :: C a => [T a a] Source #

rationalHelix1 :: C a => a -> T a (T a) Source #

This is a helix that is distorted in phase such that it becomes a purely rational function. It is guaranteed that the magnitude of the wave is one. For the distortion factor recip pi you get the closest approximation to an undistorted helix. We have chosen this scaling in order to stay with field operations.

rationalHelix1Alt :: C a => a -> T a (T a) Source #

rationalHelix :: C a => Int -> a -> T a (T a) Source #

Here we distort the rational helix in phase using tangent approximations by a sum of 2*n reciprocal functions. For the tangent function we obtain perfect cosine and sine, thus for k = recip pi and high n we approach an undistorted complex helix.

saw :: C a => T a a Source #

saw tooth, it's a ramp down in order to have a positive coefficient for the first partial sine

sawCos :: (C a, C a) => T a a Source #

This wave has the same absolute Fourier coefficients as saw but the partial waves are shifted by 90 degree. That is, it is the Hilbert transform of the saw wave. The formula is derived from sawComplex.

sawComplex :: (Power a, C a, C a) => T a (T a) Source #

sawCos + i*saw

This is an analytic function and thus it may be used for frequency shifting.

The formula can be derived from the power series of the logarithm function.

square :: (Ord a, C a) => T a a Source #

square

squareCos :: (C a, C a) => T a a Source #

This wave has the same absolute Fourier coefficients as square but the partial waves are shifted by 90 degree. That is, it is the Hilbert transform of the saw wave.

squareComplex :: (Power a, C a, C a) => T a (T a) Source #

squareCos + i*square

This is an analytic function and thus it may be used for frequency shifting.

The formula can be derived from the power series of the area tangens function.

triangle :: (Ord a, C a) => T a a Source #

triangle

truncOddCosine :: C a => Int -> T a a Source #

A truncated cosine. This has rich overtones.

truncOddTriangle :: C a => Int -> T a a Source #

For parameter zero this is saw.

truncCosine :: C a => a -> T a a Source #

A truncated cosine plus a ramp that guarantees a bump of high 2 at the boundaries.

It is truncCosine (2 * fromIntegral n + 0.5) == truncOddCosine (2*n)

truncTriangle :: C a => a -> T a a Source #

powerNormed :: (C a, C a) => a -> T a a Source #

Deprecated: Use powerNormed2 instead.

Power function. Roughly the map p x -> x**p but retains the sign of x and it should normalize the mapping over [-1,1] to an L2 norm of 1, but I got this one wrong.

The sign is flipped with respect to saw and sine which is an historical artifact.

powerNormed2 :: (C a, C a) => a -> T a a Source #

Power function. Roughly the map p x -> x**p but retains the sign of x and normalizes the mapping over [0,1] to an L2 norm of 1.

logitSaw :: C a => a -> T a a Source #

Tangens hyperbolicus allows interpolation between some kind of saw tooth and square wave. In principle it is not necessary because you can distort a saw tooth oscillation by map tanh.

logitSine :: C a => a -> T a a Source #

Tangens hyperbolicus of a sine allows interpolation between some kind of sine and square wave. In principle it is not necessary because you can distort a square oscillation by map tanh.

sineSquare Source #

Arguments

:: (C a, C a) 
=> a

0 for sine, 1 for square

-> T a a 

Interpolation between sine and square.

piecewiseParabolaSaw Source #

Arguments

:: (C a, Ord a) 
=> a

0 for fastSine2, 1 for saw

-> T a a 

Interpolation between fastSine2 and saw. We just shrink the parabola towards the borders and insert a linear curve such that its slope matches the one of the parabola.

piecewiseSineSaw Source #

Arguments

:: (C a, Ord a) 
=> a

0 for sine, 1 for saw

-> T a a 

Interpolation between sine and saw. We just shrink the sine towards the borders and insert a linear curve such that its slope matches the one of the sine.

sineSawSmooth Source #

Arguments

:: C a 
=> a

0 for sine, 1 for saw

-> T a a 

Interpolation between sine and saw with smooth intermediate shapes but no perfect saw.

sineSawSharp Source #

Arguments

:: C a 
=> a

0 for sine, 1 for saw

-> T a a 

Interpolation between sine and saw with perfect saw, but sharp intermediate shapes.

sawGaussianHarmonics :: (C a, C a) => a -> [Harmonic a] Source #

Harmonics of a saw wave that is smoothed by a Gaussian lowpass filter. This can also be used to interpolate between saw wave and sine. The parameter is the cutoff-frequency defined as the standard deviation of the Gaussian in frequency space. That is, high values approximate a saw and need many harmonics, whereas low values tend to a sine and need only few harmonics.

sawPike Source #

Arguments

:: (Ord a, C a) 
=> a

pike width ranging from 0 to 1, 1 yields saw

-> T a a 

saw with space

trianglePike Source #

Arguments

:: (C a, C a) 
=> a

pike width ranging from 0 to 1, 1 yields triangle

-> T a a 

triangle with space

trianglePikeShift Source #

Arguments

:: (C a, C a) 
=> a

pike width ranging from 0 to 1

-> a

shift ranges from -1 to 1; 0 yields trianglePike

-> T a a 

triangle with space and shift

squarePike Source #

Arguments

:: C a 
=> a

pike width ranging from 0 to 1, 1 yields square

-> T a a 

square with space, can also be generated by mixing square waves with different phases

squarePikeShift Source #

Arguments

:: C a 
=> a

pike width ranging from 0 to 1

-> a

shift ranges from -1 to 1; 0 yields squarePike

-> T a a 

square with space and shift

squareAsymmetric Source #

Arguments

:: (Ord a, C a) 
=> a

value between -1 and 1 controlling the ratio of high and low time: -1 turns the high time to zero, 1 makes the low time zero, 0 yields square

-> T a a 

square with different times for high and low

squareBalanced :: (Ord a, C a) => a -> T a a Source #

Like squareAsymmetric but with zero average. It could be simulated by adding two saw oscillations with 180 degree phase difference and opposite sign.

triangleAsymmetric Source #

Arguments

:: (Ord a, C a) 
=> a

asymmetry parameter ranging from -1 to 1: For 0 you obtain the usual triangle. For -1 you obtain a falling saw tooth starting with its maximum. For 1 you obtain a rising saw tooth starting with a zero.

-> T a a 

triangle

trapezoid Source #

Arguments

:: (C a, C a) 
=> a

width of the plateau ranging from 0 to 1: 0 yields triangle, 1 yields square

-> T a a 

Mixing trapezoid and trianglePike you can get back a triangle wave form

trapezoidAsymmetric Source #

Arguments

:: (C a, C a) 
=> a

sum of the plateau widths ranging from 0 to 1: 0 yields triangleAsymmetric, 1 yields squareAsymmetric

-> a

asymmetry of the plateau widths ranging from -1 to 1

-> T a a 

Trapezoid with distinct high and low time. That is the high and low trapezoids are symmetric itself, but the whole waveform is not symmetric.

trapezoidBalanced :: (C a, C a) => a -> a -> T a a Source #

trapezoid with distinct high and low time and zero direct current offset

trapezoidSkew Source #

Arguments

:: (Ord a, C a) 
=> a

width of the ramp, that is 1 yields a downwards saw ramp and 0 yields a square wave.

-> T a a 

parametrized trapezoid that can range from a saw ramp to a square waveform.

data Harmonic a Source #

This is similar to Polar coordinates, but the range of the phase is from 0 to 1, not 0 to 2*pi.

If you need to represent a harmonic by complex coefficients instead of the polar representation, then please build a complex valued polynomial from your coefficients and use it to distort a helix.

distort (Poly.evaluate (Poly.fromCoeffs complexCoefficients)) helix

Constructors

Harmonic 

Fields

harmonic :: T a -> a -> Harmonic a Source #

composedHarmonics :: C a => [Harmonic a] -> T a a Source #

Specify the wave by its harmonics.

The function is implemented quite efficiently by applying the Horner scheme to a polynomial with complex coefficients (the harmonic parameters) using a complex exponential as argument.