{-# LANGUAGE TemplateHaskell #-}
-- | This module contains the types used in the higher-level API of this library.
module Codec.Audio.Opus.Types
 ( -- * Sampling Rate
   SamplingRate, HasSamplingRate(..)
 , opusSR8k, opusSR12k, opusSR16k, opusSR24k, opusSR48k
   -- * Coding Mode
 , CodingMode, HasCodingMode(..), app_voip, app_audio, app_lowdelay
   -- * Exception
 , OpusException(..), ErrorCode, _ErrorCodeException
   -- * EncoderConfig
 , FrameSize
 , EncoderConfig, HasEncoderConfig(..), mkEncoderConfig
   -- * DecoderConfig
 , DecoderConfig, HasDecoderConfig(..), mkDecoderConfig
   -- * StreamConfig
 , StreamConfig, HasStreamConfig(..), mkStreamConfig
   -- * DecoderStreamConfig
 , DecoderStreamConfig, HasDecoderStreamConfig(..), mkDecoderStreamConfig
 ) where

import           Codec.Audio.Opus.Internal.Opus

import           Lens.Micro
import           Lens.Micro.TH
import           Control.Monad.Catch
import           Data.Typeable                  (Typeable)


-- | A potential error that can happen during encoding or decoding, as reported
-- by the Opus library. The descriptions of each error have been taken from the
-- [Opus documentation](https://opus-codec.org/docs/opus_api-1.5/group__opus__errorcodes.html).
data OpusException
  = OpusBadArg
  -- ^ One or more invalid/out of range arguments.
  | OpusBufferToSmall
  -- ^ Not enough bytes allocated in the buffer.
  | OpusInternalError
  -- ^ An internal error was detected.
  | OpusInvalidPacket
  -- ^ The compressed data passed is corrupted.
  | OpusUnimplemented
  -- ^ Invalid/unsupported request number.
  | OpusInvalidState
  -- ^ An encoder or decoder structure is invalid or already freed.
  | OpusAllocFail
  -- ^ Memory allocation has failed.
  deriving (OpusException -> OpusException -> Bool
(OpusException -> OpusException -> Bool)
-> (OpusException -> OpusException -> Bool) -> Eq OpusException
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: OpusException -> OpusException -> Bool
== :: OpusException -> OpusException -> Bool
$c/= :: OpusException -> OpusException -> Bool
/= :: OpusException -> OpusException -> Bool
Eq, Int -> OpusException -> ShowS
[OpusException] -> ShowS
OpusException -> String
(Int -> OpusException -> ShowS)
-> (OpusException -> String)
-> ([OpusException] -> ShowS)
-> Show OpusException
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> OpusException -> ShowS
showsPrec :: Int -> OpusException -> ShowS
$cshow :: OpusException -> String
show :: OpusException -> String
$cshowList :: [OpusException] -> ShowS
showList :: [OpusException] -> ShowS
Show, Typeable)

instance Exception OpusException

-- | A 'Traversal' that maps a function @f@ onto the contained 'OpusException'
-- if the input 'ErrorCode' can be converted into it.
_ErrorCodeException :: Traversal' ErrorCode OpusException
_ErrorCodeException :: Traversal' ErrorCode OpusException
_ErrorCodeException OpusException -> f OpusException
f ErrorCode
e
  | Just OpusException
exc <- ErrorCode -> Maybe OpusException
errorCodeException ErrorCode
e = OpusException -> ErrorCode
errorCodeException' (OpusException -> ErrorCode) -> f OpusException -> f ErrorCode
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> OpusException -> f OpusException
f OpusException
exc
  | Bool
otherwise = ErrorCode -> f ErrorCode
forall a. a -> f a
forall (f :: * -> *) a. Applicative f => a -> f a
pure ErrorCode
e

-- | Convert an 'OpusException' into an 'ErrorCode'.
errorCodeException' :: OpusException -> ErrorCode
errorCodeException' :: OpusException -> ErrorCode
errorCodeException' OpusException
OpusBadArg        = ErrorCode
opus_bad_arg
errorCodeException' OpusException
OpusBufferToSmall = ErrorCode
opus_buffer_too_small
errorCodeException' OpusException
OpusInternalError = ErrorCode
opus_internal_error
errorCodeException' OpusException
OpusInvalidPacket = ErrorCode
opus_invalid_packet
errorCodeException' OpusException
OpusUnimplemented = ErrorCode
opus_unimplemented
errorCodeException' OpusException
OpusInvalidState  = ErrorCode
opus_invalid_state
errorCodeException' OpusException
OpusAllocFail     = ErrorCode
opus_alloc_fail

-- | Convert an 'ErrorCode' into an 'OpusException'. Returns Nothing if it is
-- not a known error code.
errorCodeException :: ErrorCode -> Maybe OpusException
errorCodeException :: ErrorCode -> Maybe OpusException
errorCodeException ErrorCode
a
  | ErrorCode
a ErrorCode -> ErrorCode -> Bool
forall a. Eq a => a -> a -> Bool
== ErrorCode
opus_bad_arg = OpusException -> Maybe OpusException
forall a. a -> Maybe a
Just OpusException
OpusBadArg
  | ErrorCode
a ErrorCode -> ErrorCode -> Bool
forall a. Eq a => a -> a -> Bool
== ErrorCode
opus_buffer_too_small = OpusException -> Maybe OpusException
forall a. a -> Maybe a
Just OpusException
OpusBufferToSmall
  | ErrorCode
a ErrorCode -> ErrorCode -> Bool
forall a. Eq a => a -> a -> Bool
== ErrorCode
opus_internal_error = OpusException -> Maybe OpusException
forall a. a -> Maybe a
Just OpusException
OpusInternalError
  | ErrorCode
a ErrorCode -> ErrorCode -> Bool
forall a. Eq a => a -> a -> Bool
== ErrorCode
opus_invalid_packet = OpusException -> Maybe OpusException
forall a. a -> Maybe a
Just OpusException
OpusInvalidPacket
  | ErrorCode
a ErrorCode -> ErrorCode -> Bool
forall a. Eq a => a -> a -> Bool
== ErrorCode
opus_unimplemented = OpusException -> Maybe OpusException
forall a. a -> Maybe a
Just OpusException
OpusUnimplemented
  | ErrorCode
a ErrorCode -> ErrorCode -> Bool
forall a. Eq a => a -> a -> Bool
== ErrorCode
opus_invalid_state = OpusException -> Maybe OpusException
forall a. a -> Maybe a
Just OpusException
OpusInvalidState
  | ErrorCode
a ErrorCode -> ErrorCode -> Bool
forall a. Eq a => a -> a -> Bool
== ErrorCode
opus_alloc_fail = OpusException -> Maybe OpusException
forall a. a -> Maybe a
Just OpusException
OpusAllocFail
  | Bool
otherwise = Maybe OpusException
forall a. Maybe a
Nothing


-- | A 'HasSamplingRate' typeclass, generated from the definition of
-- 'SamplingRate' using Template Haskell. This allows us to use 'samplingRate'
-- to access the 'SamplingRate' field of a data type such as 'EncoderConfig'.
makeClassy ''SamplingRate

-- | A 'HasCodingMode' typeclass, generated from the definition of 'CodingMode'
-- using Template Haskell. This allows us to use 'codingMode' to access the
-- 'CodingMode' field of a data type such as 'EncoderConfig'.
makeClassy ''CodingMode

-- | The configuration of an Opus encoder. Use 'mkEncoderConfig' to create a new
-- 'EncoderConfig'.
data EncoderConfig = EncoderConfig
  { EncoderConfig -> SamplingRate
_encoderSamplingRate :: SamplingRate
  -- ^ sampling rate of input signal
  , EncoderConfig -> Bool
_encoderIsStereo     :: Bool
  -- ^ stereo mode? ('True' => 2 channels, 'False' => 1 channel)
  , EncoderConfig -> CodingMode
_encoderCodingMode   :: CodingMode
  -- ^ Coding mode. (See 'app_voip', 'app_audio', 'app_lowdelay')
  } deriving (EncoderConfig -> EncoderConfig -> Bool
(EncoderConfig -> EncoderConfig -> Bool)
-> (EncoderConfig -> EncoderConfig -> Bool) -> Eq EncoderConfig
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: EncoderConfig -> EncoderConfig -> Bool
== :: EncoderConfig -> EncoderConfig -> Bool
$c/= :: EncoderConfig -> EncoderConfig -> Bool
/= :: EncoderConfig -> EncoderConfig -> Bool
Eq, Int -> EncoderConfig -> ShowS
[EncoderConfig] -> ShowS
EncoderConfig -> String
(Int -> EncoderConfig -> ShowS)
-> (EncoderConfig -> String)
-> ([EncoderConfig] -> ShowS)
-> Show EncoderConfig
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> EncoderConfig -> ShowS
showsPrec :: Int -> EncoderConfig -> ShowS
$cshow :: EncoderConfig -> String
show :: EncoderConfig -> String
$cshowList :: [EncoderConfig] -> ShowS
showList :: [EncoderConfig] -> ShowS
Show)

-- | A 'HasEncoderConfig' typeclass, generated from the definition of
-- 'EncoderConfig' using Template Haskell. This allows us to use 'encoderConfig'
-- to access the 'EncoderConfig' field of e.g. 'StreamConfig'.
makeClassy 'EncoderConfig

-- | Create a new 'EncoderConfig' with the given sampling rate, stereo mode, and
-- coding mode. Set the second argument to True for stereo mode, and False for
-- mono mode.
mkEncoderConfig :: SamplingRate -> Bool -> CodingMode -> EncoderConfig
mkEncoderConfig :: SamplingRate -> Bool -> CodingMode -> EncoderConfig
mkEncoderConfig = SamplingRate -> Bool -> CodingMode -> EncoderConfig
EncoderConfig

-- | An 'EncoderConfig' has a reference to the 'SamplingRate' it is meant to be
-- used with.
instance HasSamplingRate EncoderConfig where
  samplingRate :: Lens' EncoderConfig SamplingRate
samplingRate = (SamplingRate -> f SamplingRate)
-> EncoderConfig -> f EncoderConfig
forall c. HasEncoderConfig c => Lens' c SamplingRate
Lens' EncoderConfig SamplingRate
encoderSamplingRate

-- | An 'EncoderConfig' has a reference to the 'CodingMode' it is meant to be
-- used with.
instance HasCodingMode EncoderConfig where
  codingMode :: Lens' EncoderConfig CodingMode
codingMode = (CodingMode -> f CodingMode) -> EncoderConfig -> f EncoderConfig
forall c. HasEncoderConfig c => Lens' c CodingMode
Lens' EncoderConfig CodingMode
encoderCodingMode

-- | The configuration of an Opus decoder. Use 'mkDecoderConfig' to create a new
-- 'DecoderConfig'.
data DecoderConfig = DecoderConfig
  { DecoderConfig -> SamplingRate
_decoderSamplingRate :: SamplingRate
  , DecoderConfig -> Bool
_decoderIsStereo     :: Bool
  } deriving (DecoderConfig -> DecoderConfig -> Bool
(DecoderConfig -> DecoderConfig -> Bool)
-> (DecoderConfig -> DecoderConfig -> Bool) -> Eq DecoderConfig
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: DecoderConfig -> DecoderConfig -> Bool
== :: DecoderConfig -> DecoderConfig -> Bool
$c/= :: DecoderConfig -> DecoderConfig -> Bool
/= :: DecoderConfig -> DecoderConfig -> Bool
Eq, Int -> DecoderConfig -> ShowS
[DecoderConfig] -> ShowS
DecoderConfig -> String
(Int -> DecoderConfig -> ShowS)
-> (DecoderConfig -> String)
-> ([DecoderConfig] -> ShowS)
-> Show DecoderConfig
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> DecoderConfig -> ShowS
showsPrec :: Int -> DecoderConfig -> ShowS
$cshow :: DecoderConfig -> String
show :: DecoderConfig -> String
$cshowList :: [DecoderConfig] -> ShowS
showList :: [DecoderConfig] -> ShowS
Show)

-- | A 'HasDecoderConfig' typeclass, generated from the definition of
-- 'DecoderConfig' using Template Haskell. This allows us to use 'decoderConfig'
-- to access the 'DecoderConfig' field of e.g. 'DecoderStreamConfig'.
makeClassy 'DecoderConfig

-- | Create a new 'DecoderConfig' with the given sampling rate and stereo mode.
-- Set the second argument to True for stereo mode, and False for mono mode.
mkDecoderConfig :: SamplingRate -> Bool -> DecoderConfig
mkDecoderConfig :: SamplingRate -> Bool -> DecoderConfig
mkDecoderConfig = SamplingRate -> Bool -> DecoderConfig
DecoderConfig

-- | A 'DecoderConfig' has a reference to the 'SamplingRate' it is meant to be
-- used with.
instance HasSamplingRate DecoderConfig where
  samplingRate :: Lens' DecoderConfig SamplingRate
samplingRate = (SamplingRate -> f SamplingRate)
-> DecoderConfig -> f DecoderConfig
forall c. HasDecoderConfig c => Lens' c SamplingRate
Lens' DecoderConfig SamplingRate
decoderSamplingRate

-- | A type alias for the size of an Opus frame in integers.
type FrameSize = Int

-- | The configuration of an Opus encoder stream. Use 'mkStreamConfig' to
-- create a new 'StreamConfig'.
data StreamConfig = StreamConfig
  { StreamConfig -> EncoderConfig
_streamEncoderConfig :: EncoderConfig
  , StreamConfig -> Int
_streamFrameSize     :: FrameSize
  , StreamConfig -> Int
_streamOutSize       :: Int
  } deriving (StreamConfig -> StreamConfig -> Bool
(StreamConfig -> StreamConfig -> Bool)
-> (StreamConfig -> StreamConfig -> Bool) -> Eq StreamConfig
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: StreamConfig -> StreamConfig -> Bool
== :: StreamConfig -> StreamConfig -> Bool
$c/= :: StreamConfig -> StreamConfig -> Bool
/= :: StreamConfig -> StreamConfig -> Bool
Eq, Int -> StreamConfig -> ShowS
[StreamConfig] -> ShowS
StreamConfig -> String
(Int -> StreamConfig -> ShowS)
-> (StreamConfig -> String)
-> ([StreamConfig] -> ShowS)
-> Show StreamConfig
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> StreamConfig -> ShowS
showsPrec :: Int -> StreamConfig -> ShowS
$cshow :: StreamConfig -> String
show :: StreamConfig -> String
$cshowList :: [StreamConfig] -> ShowS
showList :: [StreamConfig] -> ShowS
Show)

-- | A 'HasStreamConfig' typeclass, generated from the definition of
-- 'StreamConfig' using Template Haskell.
makeClassy ''StreamConfig

-- | Create a new 'StreamConfig' with the given 'EncoderConfig', frame size, and
-- output size.
mkStreamConfig :: EncoderConfig -> FrameSize -> Int -> StreamConfig
mkStreamConfig :: EncoderConfig -> Int -> Int -> StreamConfig
mkStreamConfig = EncoderConfig -> Int -> Int -> StreamConfig
StreamConfig

-- | An 'StreamConfig' has a reference to the 'EncoderConfig' it was created
-- with.
instance HasEncoderConfig StreamConfig where
  encoderConfig :: Lens' StreamConfig EncoderConfig
encoderConfig = (EncoderConfig -> f EncoderConfig)
-> StreamConfig -> f StreamConfig
forall c. HasStreamConfig c => Lens' c EncoderConfig
Lens' StreamConfig EncoderConfig
streamEncoderConfig

-- | An 'StreamConfig' has a reference to the 'SamplingRate' it is meant to be
-- used with.
instance HasSamplingRate StreamConfig where
  samplingRate :: Lens' StreamConfig SamplingRate
samplingRate = (EncoderConfig -> f EncoderConfig)
-> StreamConfig -> f StreamConfig
forall c. HasEncoderConfig c => Lens' c EncoderConfig
Lens' StreamConfig EncoderConfig
encoderConfig ((EncoderConfig -> f EncoderConfig)
 -> StreamConfig -> f StreamConfig)
-> ((SamplingRate -> f SamplingRate)
    -> EncoderConfig -> f EncoderConfig)
-> (SamplingRate -> f SamplingRate)
-> StreamConfig
-> f StreamConfig
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (SamplingRate -> f SamplingRate)
-> EncoderConfig -> f EncoderConfig
forall c. HasSamplingRate c => Lens' c SamplingRate
Lens' EncoderConfig SamplingRate
samplingRate

-- | An 'StreamConfig' has a reference to the 'CodingMode' it is meant to be
-- used with.
instance HasCodingMode StreamConfig where
  codingMode :: Lens' StreamConfig CodingMode
codingMode = (EncoderConfig -> f EncoderConfig)
-> StreamConfig -> f StreamConfig
forall c. HasEncoderConfig c => Lens' c EncoderConfig
Lens' StreamConfig EncoderConfig
encoderConfig ((EncoderConfig -> f EncoderConfig)
 -> StreamConfig -> f StreamConfig)
-> ((CodingMode -> f CodingMode)
    -> EncoderConfig -> f EncoderConfig)
-> (CodingMode -> f CodingMode)
-> StreamConfig
-> f StreamConfig
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (CodingMode -> f CodingMode) -> EncoderConfig -> f EncoderConfig
forall c. HasCodingMode c => Lens' c CodingMode
Lens' EncoderConfig CodingMode
codingMode

-- | The configuration of an Opus decoder stream. Use 'mkDecoderStreamConfig' to
-- create a new 'DecoderStreamConfig'.
data DecoderStreamConfig = DecoderStreamConfig
  { DecoderStreamConfig -> DecoderConfig
_deStreamDecoderConfig :: DecoderConfig
  , DecoderStreamConfig -> Int
_deStreamFrameSize     :: FrameSize
  , DecoderStreamConfig -> Int
_deStreamDecodeFec     :: Int
  } deriving (DecoderStreamConfig -> DecoderStreamConfig -> Bool
(DecoderStreamConfig -> DecoderStreamConfig -> Bool)
-> (DecoderStreamConfig -> DecoderStreamConfig -> Bool)
-> Eq DecoderStreamConfig
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: DecoderStreamConfig -> DecoderStreamConfig -> Bool
== :: DecoderStreamConfig -> DecoderStreamConfig -> Bool
$c/= :: DecoderStreamConfig -> DecoderStreamConfig -> Bool
/= :: DecoderStreamConfig -> DecoderStreamConfig -> Bool
Eq, Int -> DecoderStreamConfig -> ShowS
[DecoderStreamConfig] -> ShowS
DecoderStreamConfig -> String
(Int -> DecoderStreamConfig -> ShowS)
-> (DecoderStreamConfig -> String)
-> ([DecoderStreamConfig] -> ShowS)
-> Show DecoderStreamConfig
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> DecoderStreamConfig -> ShowS
showsPrec :: Int -> DecoderStreamConfig -> ShowS
$cshow :: DecoderStreamConfig -> String
show :: DecoderStreamConfig -> String
$cshowList :: [DecoderStreamConfig] -> ShowS
showList :: [DecoderStreamConfig] -> ShowS
Show)

-- | A 'HasDecoderStreamConfig' typeclass, generated from the definition of
-- 'DecoderStreamConfig' using Template Haskell.
makeClassy ''DecoderStreamConfig

-- | Create a new 'DecoderStreamConfig' with the given 'DecoderConfig', frame
-- size, and FEC decode flag.
mkDecoderStreamConfig :: DecoderConfig -> FrameSize -> Int -> DecoderStreamConfig
mkDecoderStreamConfig :: DecoderConfig -> Int -> Int -> DecoderStreamConfig
mkDecoderStreamConfig = DecoderConfig -> Int -> Int -> DecoderStreamConfig
DecoderStreamConfig

-- | A 'DecoderStreamConfig' has a reference to the 'DecoderConfig' it was
-- created with.
instance HasDecoderConfig DecoderStreamConfig where
    decoderConfig :: Lens' DecoderStreamConfig DecoderConfig
decoderConfig = (DecoderConfig -> f DecoderConfig)
-> DecoderStreamConfig -> f DecoderStreamConfig
forall c. HasDecoderStreamConfig c => Lens' c DecoderConfig
Lens' DecoderStreamConfig DecoderConfig
deStreamDecoderConfig

-- | A 'DecoderStreamConfig' has a reference to the 'SamplingRate' it is meant
-- to be used with.
instance HasSamplingRate DecoderStreamConfig where
    samplingRate :: Lens' DecoderStreamConfig SamplingRate
samplingRate = (DecoderConfig -> f DecoderConfig)
-> DecoderStreamConfig -> f DecoderStreamConfig
forall c. HasDecoderConfig c => Lens' c DecoderConfig
Lens' DecoderStreamConfig DecoderConfig
decoderConfig ((DecoderConfig -> f DecoderConfig)
 -> DecoderStreamConfig -> f DecoderStreamConfig)
-> ((SamplingRate -> f SamplingRate)
    -> DecoderConfig -> f DecoderConfig)
-> (SamplingRate -> f SamplingRate)
-> DecoderStreamConfig
-> f DecoderStreamConfig
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (SamplingRate -> f SamplingRate)
-> DecoderConfig -> f DecoderConfig
forall c. HasSamplingRate c => Lens' c SamplingRate
Lens' DecoderConfig SamplingRate
samplingRate