module Sound.Loris ( -- * Types Breakpoint (..) ,LinearEnvelope (..) ,BP4 (..) ,Partial (..) ,PartialList (..) -- * Functions -- ** LinearEnvelope functions ,toLinearEnvelopePtr -- ** Partial functions ,fromPartialPtr ,modifyPartialPtr -- ** PartialList functions ,fromPartialListPtr ,modifyPartialListPtr ,module Sound.Loris.ForeignPtr ) where import Sound.Loris.Foreign import Sound.Loris.ForeignPtr import Control.Applicative import Data.IORef import qualified Data.Vector as V import Foreign.C.Types import Foreign.Ptr -- | Haskell-native version of a single-valued Loris Breakpoint (as in -- a LinearEnvelope) data Breakpoint = Breakpoint { bpTime :: {-# UNPACK #-} !Double ,bpValue :: {-# UNPACK #-} !Double } deriving (Eq, Show) -- | Haskell-native LinearEnvelope data LinearEnvelope = LinearEnvelope [Breakpoint] toLinearEnvelopePtr :: LinearEnvelope -> IO LinearEnvelopePtr toLinearEnvelopePtr (LinearEnvelope bps) = do lpPtr <- createLinearEnvelope mapM_ (\(Breakpoint t v) -> linearEnvelopeInsertBreakpoint lpPtr t v) bps return lpPtr -- | Haskell-native version of a 4-valued Loris Breakpoint (as in -- a Partial.) data BP4 = BP4 { bp4Time :: {-# UNPACK #-} !Double ,bp4Amp :: {-# UNPACK #-} !Double ,bp4Bwd :: {-# UNPACK #-} !Double ,bp4Frq :: {-# UNPACK #-} !Double ,bp4Phs :: {-# UNPACK #-} !Double } deriving (Eq, Show) -- | Haskell-native Loris Partial data Partial = Partial (V.Vector BP4) deriving (Eq, Show) c2d :: CDouble -> Double c2d = realToFrac fromPartialPtr :: PartialPtr -> IO Partial fromPartialPtr p = do pRef <- newIORef [] bpf <- mkBreakpointFunction (f pRef) forEachBreakpoint p bpf nullPtr Partial . V.fromList . reverse <$> readIORef pRef where f pRef bp t _ = do bp' <- (BP4 (c2d t) <$> breakpointGetAmplitude bp <*> breakpointGetBandwidth bp <*> breakpointGetFrequency bp <*> breakpointGetPhase bp) modifyIORef pRef (bp' :) return 0 -- | Modify breakpoints in a partial. The values from each breakpoint -- are taken in order; all times are ignored. modifyPartialPtr :: [BP4] -> PartialPtr -> IO () modifyPartialPtr newbps pp = do pRef <- newIORef newbps bpf <- mkBreakpointFunction (f pRef) forEachBreakpoint pp bpf nullPtr return () where f pRef bp _ _ = do bpList <- readIORef pRef case bpList of [] -> return 0 (BP4 _ a b f p:xs) -> do writeIORef pRef xs breakpointSetAmplitude bp a breakpointSetBandwidth bp b breakpointSetFrequency bp f breakpointSetPhase bp p return 0 data PartialList = PartialList (V.Vector Partial) deriving (Eq, Show) fromPartialListPtr :: PartialListPtr -> IO PartialList fromPartialListPtr p = do pRef <- newIORef [] ppf <- mkPartialFunction (f pRef) forEachPartial p ppf nullPtr PartialList . V.fromList . reverse <$> readIORef pRef where f pRef pp _ = do partial <- fromPartialPtr pp modifyIORef pRef (partial :) return 0 -- | Modify partials in a PartialList. The values from each breakpoint -- within a partial are taken in order; all times are ignored. modifyPartialListPtr :: [Partial] -> PartialListPtr -> IO () modifyPartialListPtr partials p = do pRef <- newIORef partials ppf <- mkPartialFunction (f pRef) forEachPartial p ppf nullPtr return () where f pRef p _ = do pList <- readIORef pRef case pList of [] -> return 0 (Partial bps:xs) -> do writeIORef pRef xs modifyPartialPtr (V.toList bps) p return 0