-- | The Csound types.
--
-- There are several primitive types:
--
-- * @Sig@ - signals
--
-- * @D@ - numbers
--
-- * @Str@ - strings
--
-- * @Tab@ - 1-dimensional arrays
--
-- * @Spec@ and @Wspec@ - sound spectrums
--
--  A signal is a stream of numbers. Signals carry sound or time varied
--  control values. Numbers are constants. 1-dimensional arrays contain some useful
--  data which is calculated at the initial run of the program.
--
-- There is only one compound type. It's a tuple of Csound values. The empty tuple
-- is signified with special type called @Unit@.
--
module Csound.Types(
    -- * Primitive types
    Sig, D, Tab, Str, Spec, Wspec,
    BoolSig, BoolD, Val(..), SigOrD,

    Sig2, Sig3, Sig4, Sig5, Sig6, Sig8,
    Sig2_2, Sig2_3, Sig2_4, Sig2_5, Sig2_6, Sig2_7, Sig2_8,
    -- ** Constructors
    double, int, text,

    -- ** Constants
    idur, getSampleRate, getControlRate, getBlockSize,

    -- ** BPM
    getBpm, setBpm, syn, takt,

    -- ** Converters
    ar, kr, ir, sig,

    -- ** Init values
    withInits, withDs, withSigs, withTabs,
    withD, withSig, withTab, withSeed,

    -- ** Numeric functions
    quot', rem', div', mod', ceil', floor', round', int', frac',

    -- ** Logic functions
    boolSig, when1, whens, whenElse, whenD1, whenDs, whileDo, untilDo, whileDoD, untilDoD, whenElseD, compareWhenD,
    equalsTo, notEqualsTo, lessThan, greaterThan, lessThanEquals, greaterThanEquals,

    -- ** Aliases
    -- | Handy for functions that return tuples to specify the utput type
    --
    -- > (aleft, aright) = ar2 $ diskin2 "file.wav" 1
    --
    -- or
    --
    -- > asig = ar1 $ diskin2 "file.wav" 1
    ar1, ar2, ar4, ar6, ar8,

    -- * Tuples
    Tuple(..), makeTupleMethods, Unit, unit, atTuple,
    -- *** Logic functions
    ifTuple, guardedTuple, caseTuple,

    -- * Instruments

    -- | An instrument is a function that takes a tpule of csound values as an argument
    -- and returns a tuple of signals as an output. The type of the instrument is:
    --
    -- > (Arg a, Out b) => a -> b

    -- ** Arguments
    Arg, atArg,
    -- *** Logic functions
    ifArg, guardedArg, caseArg,

    -- ** Monophonic arguments
    MonoArg(..), MonoAdsr, adsrMonoSynt, monoAdsr,

    -- ** Outputs
    Sigs,

    -- * Arrays
    Arr, newLocalArr, newGlobalArr, newLocalCtrlArr, newGlobalCtrlArr,
    writeArr, readArr, modifyArr, mixArr,
    -- ** Type inference helpers
    Arr1, DArr1, Arr2, DArr2, Arr3, DArr3,
    arr1, darr1, arr2, darr2, arr3, darr3,

    -- ** Traverse and fold
    foreachArr, foreachArrD, forRowArr, forColumnArr, forRowArrD, forColumnArrD,
    foldArr, foldRowArr, foldColumnArr, foldRowsArrD, foldColumnsArrD,

    -- ** Array opcodes
    fillLocalArr, fillGlobalArr, fillLocalCtrlArr, fillGlobalCtrlArr,
    maparrayNew, lenarray, copyf2array, copya2ftab, minarray, maxarray, sumarray,
    scalearray, slicearrayNew,

    maparrayCopy, slicearrayCopy,

    -- ** Spectral opcodes
    SpecArr,

    fftNew, fftinvNew, rfftNew, rifftNew, pvs2tab, tab2pvs, cmplxprodNew,
    rect2polNew, pol2rectNew, pol2rect2New, windowArrayNew,
    r2cNew, c2rNew, magsArrayNew, phsArrayNew,

    fftCopy, fftinvCopy, rfftCopy, rifftCopy, cmplxprodCopy,
    rect2polCopy, pol2rectCopy, pol2rect2Copy, windowArrayCopy,
    r2cCopy, c2rCopy, magsArrayCopy, phsArrayCopy
) where

import Data.Boolean
import Csound.Typed.Types
import Csound.Typed.Control

-- | Gets an init-rate value from the list by index.
atArg :: (Tuple a, Arg a) => [a] -> D -> a
atArg :: [a] -> D -> a
atArg [a]
as D
ind = [(BoolD, a)] -> a -> a
forall b. (Tuple b, Arg b) => [(BoolD, b)] -> b -> b
guardedArg ([BoolD] -> [a] -> [(BoolD, a)]
forall a b. [a] -> [b] -> [(a, b)]
zip ((Int -> BoolD) -> [Int] -> [BoolD]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (\Int
x -> Int -> D
int Int
x D -> D -> BoolD
forall a bool. (EqB a, bool ~ BooleanOf a) => a -> a -> bool
==* D
ind) [Int
0 .. ]) [a]
as) ([a] -> a
forall a. [a] -> a
head [a]
as)

-- | Gets an control/audio-rate value from the list by index.
atTuple :: (Tuple a) => [a] -> Sig -> a
atTuple :: [a] -> Sig -> a
atTuple [a]
as Sig
ind = [(BoolSig, a)] -> a -> a
forall b. Tuple b => [(BoolSig, b)] -> b -> b
guardedTuple ([BoolSig] -> [a] -> [(BoolSig, a)]
forall a b. [a] -> [b] -> [(a, b)]
zip ((Int -> BoolSig) -> [Int] -> [BoolSig]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (\Int
x -> D -> Sig
sig (Int -> D
int Int
x) Sig -> Sig -> BoolSig
forall a bool. (EqB a, bool ~ BooleanOf a) => a -> a -> bool
==* Sig
ind) [Int
0 .. ]) [a]
as) ([a] -> a
forall a. [a] -> a
head [a]
as)


whenElseD :: BoolD -> SE () -> SE () -> SE ()
whenElseD :: BoolD -> SE () -> SE () -> SE ()
whenElseD BoolD
condition SE ()
ifDo SE ()
elseDo = [(BoolD, SE ())] -> SE () -> SE ()
whenDs [(BoolD
condition, SE ()
ifDo)] SE ()
elseDo

whenElse :: BoolSig -> SE () -> SE () -> SE ()
whenElse :: BoolSig -> SE () -> SE () -> SE ()
whenElse BoolSig
condition SE ()
ifDo SE ()
elseDo = [(BoolSig, SE ())] -> SE () -> SE ()
whens [(BoolSig
condition, SE ()
ifDo)] SE ()
elseDo

-- | Performs tree search f the first argument lies within the interval it performs the corresponding procedure.
compareWhenD :: D -> [(D, SE ())] -> SE ()
compareWhenD :: D -> [(D, SE ())] -> SE ()
compareWhenD D
val [(D, SE ())]
conditions = case [(D, SE ())]
conditions of
    [] -> () -> SE ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()
    [(D
_condition, SE ()
ifDo)] -> SE ()
ifDo
    (D
condition1, SE ()
do1):(D
_condition2, SE ()
do2): [] -> BoolD -> SE () -> SE () -> SE ()
whenElseD (D
val D -> D -> BooleanOf D
forall a. OrdB a => a -> a -> BooleanOf a
`lessThan` D
condition1) SE ()
do1 SE ()
do2
    [(D, SE ())]
_ -> BoolD -> SE () -> SE () -> SE ()
whenElseD (D
val D -> D -> BooleanOf D
forall a. OrdB a => a -> a -> BooleanOf a
`lessThan` D
rootcondition) (D -> [(D, SE ())] -> SE ()
compareWhenD D
val [(D, SE ())]
less) (D -> [(D, SE ())] -> SE ()
compareWhenD D
val [(D, SE ())]
more)
    where
        ([(D, SE ())]
less, [(D, SE ())]
more) = Int -> [(D, SE ())] -> ([(D, SE ())], [(D, SE ())])
forall a. Int -> [a] -> ([a], [a])
splitAt ([(D, SE ())] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [(D, SE ())]
conditions Int -> Int -> Int
forall a. Integral a => a -> a -> a
`div` Int
2) [(D, SE ())]
conditions
        rootcondition :: D
rootcondition = (D, SE ()) -> D
forall a b. (a, b) -> a
fst ((D, SE ()) -> D) -> (D, SE ()) -> D
forall a b. (a -> b) -> a -> b
$ [(D, SE ())] -> (D, SE ())
forall a. [a] -> a
last [(D, SE ())]
less

-- | It's used to synchronize changes with BPM.
-- Useful with LFO's or delay times.
syn :: Sig -> Sig
syn :: Sig -> Sig
syn Sig
x = (Sig
bpm Sig -> Sig -> Sig
forall a. Fractional a => a -> a -> a
/ Sig
60) Sig -> Sig -> Sig
forall a. Num a => a -> a -> a
* Sig
x
    where bpm :: Sig
bpm = Sig
getBpm

-- | Calculates seconditions in ratio to global BPM.
-- It measures time according to changes in the BPM.
-- It's reciprocal to @syn@.
takt :: Sig -> Sig
takt :: Sig -> Sig
takt = Sig -> Sig
forall a. Fractional a => a -> a
recip (Sig -> Sig) -> (Sig -> Sig) -> Sig -> Sig
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Sig -> Sig
syn