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

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

module DobutokO.Sound.Effects.Echo where

#ifdef __GLASGOW_HASKELL__
#if __GLASGOW_HASKELL__>=710
/* code that applies only to GHC 7.10.* and higher versions */
import GHC.Base (mconcat)
#endif
#endif

import Numeric (showFFloat)
import Data.List (intersperse)

#ifdef __GLASGOW_HASKELL__
#if __GLASGOW_HASKELL__==708
/* code that applies only to GHC 7.8.* */
mconcat = concat
#endif
#endif

data EchoTail a = ET a a deriving EchoTail a -> EchoTail a -> Bool
(EchoTail a -> EchoTail a -> Bool)
-> (EchoTail a -> EchoTail a -> Bool) -> Eq (EchoTail a)
forall a. Eq a => EchoTail a -> EchoTail a -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: EchoTail a -> EchoTail a -> Bool
$c/= :: forall a. Eq a => EchoTail a -> EchoTail a -> Bool
== :: EchoTail a -> EchoTail a -> Bool
$c== :: forall a. Eq a => EchoTail a -> EchoTail a -> Bool
Eq

instance Show (EchoTail Float) where
  show :: EchoTail Float -> String
show (ET Float
delay Float
decay) = [String] -> String
forall a. Monoid a => [a] -> a
mconcat [Maybe Int -> Float -> ShowS
forall a. RealFloat a => Maybe Int -> a -> ShowS
showFFloat Maybe Int
forall a. Maybe a
Nothing (Float -> Float
forall a. Num a => a -> a
abs Float
delay) String
" ", Maybe Int -> Float -> ShowS
forall a. RealFloat a => Maybe Int -> a -> ShowS
showFFloat Maybe Int
forall a. Maybe a
Nothing (Float -> Float
forall a. Num a => a -> a
abs Float
decay) String
" "]

type EchoTail1 = EchoTail Float

data Echo a b = E1 a a [b] deriving Echo a b -> Echo a b -> Bool
(Echo a b -> Echo a b -> Bool)
-> (Echo a b -> Echo a b -> Bool) -> Eq (Echo a b)
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
forall a b. (Eq a, Eq b) => Echo a b -> Echo a b -> Bool
/= :: Echo a b -> Echo a b -> Bool
$c/= :: forall a b. (Eq a, Eq b) => Echo a b -> Echo a b -> Bool
== :: Echo a b -> Echo a b -> Bool
$c== :: forall a b. (Eq a, Eq b) => Echo a b -> Echo a b -> Bool
Eq

instance Show (Echo Float EchoTail1) where
  show :: Echo Float (EchoTail Float) -> String
show (E1 Float
gin Float
gout [EchoTail Float]
ys) 
    | [EchoTail Float] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [EchoTail Float]
ys = String
""
    | Bool
otherwise = [String] -> String
forall a. Monoid a => [a] -> a
mconcat [String
"echo ", Maybe Int -> Float -> ShowS
forall a. RealFloat a => Maybe Int -> a -> ShowS
showFFloat Maybe Int
forall a. Maybe a
Nothing (Float -> Float
forall a. Num a => a -> a
abs Float
gin) String
" ", Maybe Int -> Float -> ShowS
forall a. RealFloat a => Maybe Int -> a -> ShowS
showFFloat Maybe Int
forall a. Maybe a
Nothing (Float -> Float
forall a. Num a => a -> a
abs Float
gout) String
" ", [String] -> String
forall a. Monoid a => [a] -> a
mconcat ([String] -> String)
-> ([EchoTail Float] -> [String]) -> [EchoTail Float] -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> [String] -> [String]
forall a. a -> [a] -> [a]
intersperse String
" " ([String] -> [String])
-> ([EchoTail Float] -> [String]) -> [EchoTail Float] -> [String]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (EchoTail Float -> String) -> [EchoTail Float] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map EchoTail Float -> String
forall a. Show a => a -> String
show ([EchoTail Float] -> String) -> [EchoTail Float] -> String
forall a b. (a -> b) -> a -> b
$ [EchoTail Float]
ys]

type Echo1 = Echo Float EchoTail1  

echoTail1 :: Int -> EchoTail a -> a
echoTail1 :: Int -> EchoTail a -> a
echoTail1 Int
n (ET a
x0 a
x1) 
  | Int
n Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
1 = a
x0
  | Int
n Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
2 = a
x1
  | Bool
otherwise = String -> a
forall a. HasCallStack => String -> a
error String
"DobutokO.Sound.Effects.Echo.echoTail1: Not defined parameter. "
  
echoTailSet1 :: Int -> a -> EchoTail a -> EchoTail a
echoTailSet1 :: Int -> a -> EchoTail a -> EchoTail a
echoTailSet1 Int
n a
x (ET a
x0 a
x1) 
  | Int
n Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
1 = a -> a -> EchoTail a
forall a. a -> a -> EchoTail a
ET a
x a
x1 
  | Int
n Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
2 = a -> a -> EchoTail a
forall a. a -> a -> EchoTail a
ET a
x0 a
x 
  | Bool
otherwise = String -> EchoTail a
forall a. HasCallStack => String -> a
error String
"DobutokO.Sound.Effects.Echo.echoTailSet1: Not defined parameter. "

echo1 :: Int -> Echo a b -> a
echo1 :: Int -> Echo a b -> a
echo1 Int
n (E1 a
x0 a
x1 [b]
_) 
  | Int
n Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
1 = a
x0
  | Int
n Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
2 = a
x1
  | Bool
otherwise = String -> a
forall a. HasCallStack => String -> a
error String
"DobutokO.Sound.Effects.Echo.echo1: Not defined parameter. "
  
echo2 :: Echo a b -> [b]
echo2 :: Echo a b -> [b]
echo2 (E1 a
_ a
_ [b]
ys) = [b]
ys

echoSet1 :: Int -> a -> Echo a b -> Echo a b
echoSet1 :: Int -> a -> Echo a b -> Echo a b
echoSet1 Int
n a
x (E1 a
x0 a
x1 [b]
y) 
  | Int
n Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
1 = a -> a -> [b] -> Echo a b
forall a b. a -> a -> [b] -> Echo a b
E1 a
x a
x1 [b]
y
  | Int
n Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
2 = a -> a -> [b] -> Echo a b
forall a b. a -> a -> [b] -> Echo a b
E1 a
x0 a
x [b]
y
  | Bool
otherwise = String -> Echo a b
forall a. HasCallStack => String -> a
error String
"DobutokO.Sound.Effects.Echo.echoSet1: Not defined parameter. "

echoSet2 :: [b] -> Echo a b -> Echo a b
echoSet2 :: [b] -> Echo a b -> Echo a b
echoSet2 [b]
ys (E1 a
x0 a
x1 [b]
_) = a -> a -> [b] -> Echo a b
forall a b. a -> a -> [b] -> Echo a b
E1 a
x0 a
x1 [b]
ys

showEchQ :: Echo1 -> [String]
showEchQ :: Echo Float (EchoTail Float) -> [String]
showEchQ = String -> [String]
words (String -> [String])
-> (Echo Float (EchoTail Float) -> String)
-> Echo Float (EchoTail Float)
-> [String]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Echo Float (EchoTail Float) -> String
forall a. Show a => a -> String
show

data Echos a b = ES a a [b] deriving Echos a b -> Echos a b -> Bool
(Echos a b -> Echos a b -> Bool)
-> (Echos a b -> Echos a b -> Bool) -> Eq (Echos a b)
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
forall a b. (Eq a, Eq b) => Echos a b -> Echos a b -> Bool
/= :: Echos a b -> Echos a b -> Bool
$c/= :: forall a b. (Eq a, Eq b) => Echos a b -> Echos a b -> Bool
== :: Echos a b -> Echos a b -> Bool
$c== :: forall a b. (Eq a, Eq b) => Echos a b -> Echos a b -> Bool
Eq

instance Show (Echos Float EchoTail1) where
  show :: Echos Float (EchoTail Float) -> String
show (ES Float
gin Float
gout [EchoTail Float]
ys) 
    | [EchoTail Float] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [EchoTail Float]
ys = String
""
    | Bool
otherwise = [String] -> String
forall a. Monoid a => [a] -> a
mconcat [String
"echos ", Maybe Int -> Float -> ShowS
forall a. RealFloat a => Maybe Int -> a -> ShowS
showFFloat Maybe Int
forall a. Maybe a
Nothing (Float -> Float
forall a. Num a => a -> a
abs Float
gin) String
" ", Maybe Int -> Float -> ShowS
forall a. RealFloat a => Maybe Int -> a -> ShowS
showFFloat Maybe Int
forall a. Maybe a
Nothing (Float -> Float
forall a. Num a => a -> a
abs Float
gout) String
" ", [String] -> String
forall a. Monoid a => [a] -> a
mconcat ([String] -> String)
-> ([EchoTail Float] -> [String]) -> [EchoTail Float] -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> [String] -> [String]
forall a. a -> [a] -> [a]
intersperse String
" " ([String] -> [String])
-> ([EchoTail Float] -> [String]) -> [EchoTail Float] -> [String]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (EchoTail Float -> String) -> [EchoTail Float] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map EchoTail Float -> String
forall a. Show a => a -> String
show ([EchoTail Float] -> String) -> [EchoTail Float] -> String
forall a b. (a -> b) -> a -> b
$ [EchoTail Float]
ys]

type Echos1 = Echos Float EchoTail1  

echos1 :: Int -> Echos a b -> a
echos1 :: Int -> Echos a b -> a
echos1 Int
n (ES a
x0 a
x1 [b]
_) 
  | Int
n Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
1 = a
x0
  | Int
n Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
2 = a
x1
  | Bool
otherwise = String -> a
forall a. HasCallStack => String -> a
error String
"DobutokO.Sound.Effects.Echo.echos1: Not defined parameter. "
  
echos2 :: Echos a b -> [b]
echos2 :: Echos a b -> [b]
echos2 (ES a
_ a
_ [b]
ys) = [b]
ys

echosSet1 :: Int -> a -> Echos a b -> Echos a b
echosSet1 :: Int -> a -> Echos a b -> Echos a b
echosSet1 Int
n a
x (ES a
x0 a
x1 [b]
y) 
  | Int
n Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
1 = a -> a -> [b] -> Echos a b
forall a b. a -> a -> [b] -> Echos a b
ES a
x a
x1 [b]
y
  | Int
n Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
2 = a -> a -> [b] -> Echos a b
forall a b. a -> a -> [b] -> Echos a b
ES a
x0 a
x [b]
y
  | Bool
otherwise = String -> Echos a b
forall a. HasCallStack => String -> a
error String
"DobutokO.Sound.Effects.Echo.echosSet1: Not defined parameter. "

echosSet2 :: [b] -> Echos a b -> Echos a b
echosSet2 :: [b] -> Echos a b -> Echos a b
echosSet2 [b]
ys (ES a
x0 a
x1 [b]
_) = a -> a -> [b] -> Echos a b
forall a b. a -> a -> [b] -> Echos a b
ES a
x0 a
x1 [b]
ys

showEchsQ :: Echos1 -> [String]
showEchsQ :: Echos Float (EchoTail Float) -> [String]
showEchsQ = String -> [String]
words (String -> [String])
-> (Echos Float (EchoTail Float) -> String)
-> Echos Float (EchoTail Float)
-> [String]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Echos Float (EchoTail Float) -> String
forall a. Show a => a -> String
show