-- |
-- Module      :  DobutokO.Sound.Effects.Bend
-- Copyright   :  (c) OleksandrZhabenko 2020
-- License     :  MIT
-- Stability   :  Experimental
-- Maintainer  :  olexandr543@yahoo.com
--
-- Helps to create experimental music. 
-- Can be used for applying the \"bend\" SoX effect. 
-- 

{-# OPTIONS_GHC -threaded #-}
{-# LANGUAGE FlexibleInstances #-}

module DobutokO.Sound.Effects.Bend where

import Numeric (showFFloat)
import DobutokO.Sound.Effects.Timespec

data BendTrio a b = Bend3 a b a deriving Eq

instance Show (BendTrio FirstTSpec Float) where
  show (Bend3 x y z) = mconcat [show x, ",", showFFloat Nothing y ",", show z]

type BendTr3 = BendTrio FirstTSpec Float

bendTrio1 :: BendTrio a b -> a
bendTrio1 (Bend3 x _ _) = x

bendTrio2 :: BendTrio a b -> b
bendTrio2 (Bend3 _ y _) = y

bendTrio3 :: BendTrio a b -> a
bendTrio3 (Bend3 _ _ z) = z

bendTrioSet1 :: a -> BendTrio a b -> BendTrio a b
bendTrioSet1 x (Bend3 _ y z) = Bend3 x y z

bendTrioSet2 :: b -> BendTrio a b -> BendTrio a b
bendTrioSet2 y (Bend3 x _ z) = Bend3 x y z

bendTrioSet3 :: a -> BendTrio a b -> BendTrio a b
bendTrioSet3 z (Bend3 x y _) = Bend3 x y z

data FrameRate a = FR a deriving Eq

instance Show (FrameRate Float) where
  show (FR x)
    | compare x 10.0 /= LT && compare x 80.0 /= GT = "-f " ++ showFFloat Nothing x " "
    | otherwise = ""

type FrRate = FrameRate Float

frameRate1 :: FrameRate a -> a
frameRate1 (FR x) = x

frameRateSet1 :: a -> FrameRate a
frameRateSet1 = FR

data OverSample a = OS a deriving Eq

instance Show (OverSample Float) where
  show (OS x)
    | compare x 4.0 /= LT && compare x 32.0 /= GT = "-o " ++ showFFloat Nothing x " "
    | otherwise = ""

type OvSample = OverSample Float

overSample1 :: OverSample a -> a
overSample1 (OS x) = x

overSampleSet1 :: a -> OverSample a
overSampleSet1 = OS

data Bend a b c = Bnd c | Bnd1 a c | Bnd2 b c | Bnd12 a b c deriving Eq

instance Show (Bend FrRate OvSample BendTr3) where
  show (Bnd z) = mconcat ["bend ",show z]
  show (Bnd1 x z) = mconcat ["bend ",show x,show z]
  show (Bnd2 y z) = mconcat ["bend ",show y,show z]
  show (Bnd12 x y z) = mconcat ["bend ", show x, show y, show z]

type BendE = Bend FrRate OvSample BendTr3

bend1 :: Bend a b c -> Maybe a
bend1 (Bnd1 x _) = Just x
bend1 (Bnd12 x _ _) = Just x
bend1 _ = Nothing

bend2 :: Bend a b c -> Maybe b
bend2 (Bnd2 y _) = Just y
bend2 (Bnd12 _ y _) = Just y
bend2 _ = Nothing

bendE1 :: BendE -> FrRate
bendE1 (Bnd1 x _) = x
bendE1 (Bnd12 x _ _) = x
bendE1 _ = FR 25.0

bendE2 :: BendE -> OvSample
bendE2 (Bnd2 y _) = y
bendE2 (Bnd12 _ y _) = y
bendE2 _ = OS 16.0

bend3 :: Bend a b c -> c
bend3 (Bnd z) = z
bend3 (Bnd1 _ z) = z
bend3 (Bnd2 _ z) = z
bend3 (Bnd12 _ _ z) = z

bendSet1 :: a -> Bend a b c -> Bend a b c
bendSet1 _ (Bnd z) = Bnd z
bendSet1 x (Bnd1 _ z) = Bnd1 x z
bendSet1 x (Bnd2 y z) = Bnd12 x y z
bendSet1 x (Bnd12 _ y z) = Bnd12 x y z

bendSet2 :: b -> Bend a b c -> Bend a b c
bendSet2 y (Bnd z) = Bnd2 y z
bendSet2 y (Bnd1 x z) = Bnd12 x y z
bendSet2 y (Bnd2 _ z) = Bnd2 y z
bendSet2 y (Bnd12 x _ z) = Bnd12 x y z

bendSet3 :: c -> Bend a b c -> Bend a b c
bendSet3 z (Bnd _) = Bnd z
bendSet3 z (Bnd1 x _) = Bnd1 x z
bendSet3 z (Bnd2 y _) = Bnd2 y z
bendSet3 z (Bnd12 x y _) = Bnd12 x y z

showBndQ :: BendE -> [String]
showBndQ = words . show