```{- |
Construction of a data type that describes piecewise defined curves.
-}
module Synthesizer.Piecewise where

type T t y sig = [PieceData t y sig]

{- |
The curve type of a piece of a piecewise defined control curve.
-}
newtype Piece t y sig =
Piece {computePiece :: y  {- y0 -}
-> y  {- y1 -}
-> t  {- duration -}
-> sig}

pieceFromFunction ::
(y -> y -> t -> sig) -> Piece t y sig
pieceFromFunction = Piece

{- |
The full description of a control curve piece.
-}
data PieceData t y sig =
PieceData {pieceType :: Piece t y sig,
pieceY0 :: y,
pieceY1 :: y,
pieceDur :: t}
--   deriving (Eq, Show)

newtype PieceRightSingle y = PRS y
newtype PieceRightDouble y = PRD y

data PieceDist t y sig = PD t (Piece t y sig) y

-- precedence and associativity like (:)
infixr 5 -|#, #|-, =|#, #|=, |#, #|

{- |
The 6 operators simplify constructing a list of @PieceData a@.
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 @|@.
With respect to the bar,
the pad symbol @\#@ is at the side of the curve type,
at the other side there is nothing, a minus sign @-@, or an equality sign @=@.

(1) Nothing means that here is the start or the end node of a curve.

(2) Minus means that here is a node where left and right curve meet at the same value.
The node description is thus one value.

(3) 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.
-}

-- the leading space is necessary for the Haddock parser

( #|-) :: (t, Piece t y sig) -> (PieceRightSingle y, T t y sig) ->
(PieceDist t y sig, T t y sig)
(d,c) #|- (PRS y1, xs)  =  (PD d c y1, xs)

(-|#) :: y -> (PieceDist t y sig, T t y sig) ->
(PieceRightSingle y, T t y sig)
y0 -|# (PD d c y1, xs)  =  (PRS y0, PieceData c y0 y1 d : xs)

( #|=) :: (t, Piece t y sig) -> (PieceRightDouble y, T t y sig) ->
(PieceDist t y sig, T t y sig)
(d,c) #|= (PRD y1, xs)  =  (PD d c y1, xs)

(=|#) :: (y,y) -> (PieceDist t y sig, T t y sig) ->
(PieceRightDouble y, T t y sig)
(y01,y10) =|# (PD d c y11, xs)  =  (PRD y01, PieceData c y10 y11 d : xs)

( #|) :: (t, Piece t y sig) -> y ->
(PieceDist t y sig, T t y sig)
(d,c) #| y1  =  (PD d c y1, [])

(|#) :: y -> (PieceDist t y sig, T t y sig) ->
T t y sig
y0 |# (PD d c y1, xs)  =  PieceData c y0 y1 d : xs
```