{-# LANGUAGE UndecidableInstances #-} -- | Sub-types of 'Audio' for uncompressed audio. module Data.MediaBus.Media.Audio.Raw ( Raw , Pcm , pcmMediaBuffer , IsPcmValue(..) ) where import Control.DeepSeq import Control.Lens import Data.MediaBus.Media.Media import Data.MediaBus.Media.Audio import Data.MediaBus.Media.Blank import Data.MediaBus.Media.Buffer import Data.MediaBus.Media.Channels import Data.MediaBus.Media.Samples import Data.MediaBus.Media.Segment import Data.MediaBus.Basics.Ticks import Data.Typeable import qualified Data.Vector.Storable as V import qualified Data.Vector.Storable.Mutable as M import Test.QuickCheck -- | An indicator for uncompressed audio with a given per sample encoding type. data Raw encoding -- | A family of multi-channel audio samples, this will be stored in a 'MediaBuffer' -- if audio is represented by @Audio r (Pcm c t)@ data family Pcm c t -- | Types of per channel PCM audio sample value. class (CanBeBlank a, CanBeSample a, Arbitrary a) => IsPcmValue a where -- | Calculate the average of two pcm samples pcmAverage :: a -> a -> a -- | All 'Pcm' audio is audio. An 'Audio' instance with 'Pcm's in a 'MediaBuffer'. newtype instance Audio r c (Raw t) = MkPcm {_pcmMediaBuffer :: MediaBuffer (Pcm c t)} -- | An isomorphism for 'Audio' and 'MediaBuffer' pcmMediaBuffer :: Iso (Audio r c (Raw t)) (Audio r' c' (Raw t')) (MediaBuffer (Pcm c t)) (MediaBuffer (Pcm c' t')) pcmMediaBuffer = iso _pcmMediaBuffer MkPcm instance (KnownRate r, CanBeSample (Pcm c t), CanBeBlank (Pcm c t)) => CanGenerateBlankMedia (Audio r c (Raw t)) where blankFor dt = MkPcm $ createMediaBuffer $ let numberOfSamples = ceiling (dt * fromIntegral (rateVal (MkRateProxy :: RateProxy r))) in M.replicate numberOfSamples blank instance (KnownRate r, CanBeSample (Pcm c t)) => HasDuration (Audio r c (Raw t)) where getDuration (MkPcm !buf) = let pd = getPeriodDuration (Proxy :: Proxy (Audio r c (Raw t))) n = fromIntegral $ mediaBufferLength buf in pd * n instance CanBeSample (Pcm c t) => NFData (Audio r c (Raw t)) where rnf (MkPcm !buf) = rnf buf instance CanBeSample (Pcm c t) => Eq (Audio r c (Raw t)) where (==) (MkPcm !buf1) (MkPcm !buf2) = buf1 == buf2 instance (Typeable t, KnownRate r, KnownChannelLayout c, CanBeSample (Pcm c t)) => IsMedia (Audio r c (Raw t)) instance (Typeable t, KnownRate r, KnownChannelLayout c) => Show (MediaDescription (Audio r c (Raw t))) where showsPrec d _ = showParen (d > 10) (showString "pcm-audio " . showsPrec 11 (typeRep (Proxy :: Proxy t)) . showString " " . showsPrec 11 (MkRateProxy :: RateProxy r) . showString " " . showsPrec 11 (MkRateProxy :: RateProxy r)) instance (Typeable t, KnownRate r, KnownChannelLayout c, CanBeSample (Pcm c t)) => Show (Audio r c (Raw t)) where showsPrec d (MkPcm !c) = showParen (d > 10) $ shows (MkShowMedia :: MediaDescription (Audio r c (Raw t))) . showsPrec 11 c instance (CanBeSample (Pcm ca a), CanBeSample (Pcm cb b)) => HasMediaBuffer (Audio r ca (Raw a)) (Audio r' cb (Raw b)) where type MediaBufferFrom (Audio r ca (Raw a)) = (MediaBuffer (Pcm ca a)) type MediaBufferTo (Audio r' cb (Raw b)) = (MediaBuffer (Pcm cb b)) mediaBuffer = pcmMediaBuffer instance (CanBeSample (Pcm c t), CanBeSample (Pcm c' t')) => EachSample (Audio r c (Raw t)) (Audio r' c' (Raw t')) where type SamplesFrom (Audio r c (Raw t)) = (Pcm c t) type SamplesTo (Audio r' c' (Raw t')) = (Pcm c' t') eachSample = pcmMediaBuffer . each instance ( CanBeSample (Pcm c t) , CanBeSample (Pcm c' t') , EachSampleL (Audio r c (Raw t)) (Audio r' c' (Raw t')) (Pcm c t) (Pcm c' t') , EachChannelL (Pcm c t) (Pcm c' t') t t' ) => EachChannel (Audio r c (Raw t)) (Audio r' c' (Raw t')) where type ChannelsFrom (Audio r c (Raw t)) = ChannelsFrom (Pcm c t) type ChannelsTo (Audio r' c' (Raw t')) = ChannelsTo (Pcm c' t') eachChannel = eachSample . eachChannel instance (CanBeSample (Pcm c t), KnownRate r) => CanSegment (Audio r c (Raw t)) where splitAfterDuration proxy buf@(MkPcm (MkMediaBuffer !bufV)) | getDuration buf >= tPacket = let (!nextPacket, !rest) = V.splitAt n bufV in Just ( segmentContent . pcmMediaBuffer . mediaBufferVector # V.force nextPacket , pcmMediaBuffer . mediaBufferVector # rest) | otherwise = Nothing where !tPacket = getStaticDuration proxy !n = ceiling (tPacket / tSample) !tSample = getPeriodDuration (Proxy :: Proxy (Audio r c (Raw t))) instance CanBeSample (Pcm c t) => Monoid (Audio r c (Raw t)) where mempty = pcmMediaBuffer # mempty mappend x y = pcmMediaBuffer # mappend (x ^. pcmMediaBuffer) (y ^. pcmMediaBuffer)