-- |
-- This module exports all needed datatypes and all the combinators needed to manipulate them.
module LambdaSound.Sound
  ( -- * Sound types
    Sound (..),
    SoundDuration (..),
    Pulse (..),
    Duration (..),
    Progress (..),
    Percentage (..),
    SamplingInfo (..),
    Hz (..),
    Time (..),
    DetermineDuration,

    -- * Make new sounds

    -- Also take a look at @LambdaSound.Create@!
    makeSound,
    makeSoundVector,
    fillWholeSound,
    fillWholeSoundST,
    computeOnce,

    -- * Sounds in sequence
    timedSequentially,
    (>>>),
    sequentially,
    infiniteSequentially,

    -- * Sounds in parallel
    parallel2,
    parallel,

    -- * Volume
    amplify,
    reduce,

    -- * Pitch
    raise,
    diminish,

    -- * Duration
    setDuration,
    (|->),
    getDuration,
    scaleDuration,
    dropDuration,
    adoptDuration,

    -- * Sample order
    reverseSound,
    dropSound,
    takeSound,

    -- * Zipping
    zipSoundWith,
    zipSound,

    -- * Change play behavior of a sound
    changeTempo,
    changeTempoM,

    -- * Modify the samples of a sound
    modifyWholeSound,
    modifyWholeSoundST,

    -- * Access the samples of a sound
    withSamplingInfo,
    withSampledSound,
    withSampledSoundPulse,

    -- * Embed IO
    embedIO,
    embedIOLazily,
  )
where

import Control.Monad.ST
import Data.Coerce (coerce)
import Data.Foldable (foldl')
import Data.Massiv.Array qualified as M
import Data.Massiv.Array.Unsafe qualified as MU
import LambdaSound.Sound.ComputeSound
import LambdaSound.Sound.Types
import System.IO.Unsafe (unsafePerformIO)

-- | 'Sound's may have a duration attached to them.
-- 'T'imed 'Sound's have a duration.
-- 'I'nfinite 'Sound's have no duration.
data SoundDuration = I | T

-- | Determines the duration of two sounds when they are combined
type family DetermineDuration (d1 :: SoundDuration) (d2 :: SoundDuration) where
  DetermineDuration I d = d
  DetermineDuration d I = d
  DetermineDuration T _ = T
  DetermineDuration _ T = T

data Sound (d :: SoundDuration) a where
  TimedSound ::
    !Duration ->
    ComputeSound a ->
    Sound T a
  InfiniteSound ::
    ComputeSound a ->
    Sound I a

-- data SoundType d where
--   InfiniteSoundType :: SoundType I
--   TimedSoundType :: SoundType T

-- class DetermineSoundType d where
--   determineSoundType :: SoundType d

-- instance DetermineSoundType I where
--   determineSoundType = InfiniteSoundType

-- instance DetermineSoundType T where
--   determineSoundType = TimedSoundType

getCS :: Sound d a -> ComputeSound a
getCS :: forall (d :: SoundDuration) a. Sound d a -> ComputeSound a
getCS (InfiniteSound ComputeSound a
cs) = ComputeSound a
cs
getCS (TimedSound Duration
_ ComputeSound a
cs) = ComputeSound a
cs

mapComputation :: (ComputeSound a -> ComputeSound b) -> Sound d a -> Sound d b
mapComputation :: forall a b (d :: SoundDuration).
(ComputeSound a -> ComputeSound b) -> Sound d a -> Sound d b
mapComputation ComputeSound a -> ComputeSound b
f (InfiniteSound ComputeSound a
cs) = ComputeSound b -> Sound 'I b
forall a. ComputeSound a -> Sound 'I a
InfiniteSound (ComputeSound b -> Sound 'I b) -> ComputeSound b -> Sound 'I b
forall a b. (a -> b) -> a -> b
$ ComputeSound a -> ComputeSound b
f ComputeSound a
cs
mapComputation ComputeSound a -> ComputeSound b
f (TimedSound Duration
d ComputeSound a
cs) = Duration -> ComputeSound b -> Sound 'T b
forall a. Duration -> ComputeSound a -> Sound 'T a
TimedSound Duration
d (ComputeSound b -> Sound 'T b) -> ComputeSound b -> Sound 'T b
forall a b. (a -> b) -> a -> b
$ ComputeSound a -> ComputeSound b
f ComputeSound a
cs

instance Show (Sound d Pulse) where
  show :: Sound d Pulse -> String
show (TimedSound Duration
d ComputeSound Pulse
c) = Duration -> ComputeSound Pulse -> String
showSampledCompute Duration
d ComputeSound Pulse
c
  show (InfiniteSound ComputeSound Pulse
c) = Duration -> ComputeSound Pulse -> String
showSampledCompute Duration
3 ComputeSound Pulse
c

showSampledCompute :: Duration -> ComputeSound Pulse -> String
showSampledCompute :: Duration -> ComputeSound Pulse -> String
showSampledCompute Duration
d ComputeSound Pulse
cs = IO String -> String
forall a. IO a -> a
unsafePerformIO (IO String -> String) -> IO String -> String
forall a b. (a -> b) -> a -> b
$ do
  let si :: SamplingInfo
si = Hz -> Duration -> SamplingInfo
makeSamplingInfo (Duration -> Hz
forall a b. Coercible a b => a -> b
coerce (Duration -> Hz) -> Duration -> Hz
forall a b. (a -> b) -> a -> b
$ Duration
25 Duration -> Duration -> Duration
forall a. Fractional a => a -> a -> a
/ Duration
d) Duration
d
  Vector S Pulse
floats <- SamplingInfo -> ComputeSound Pulse -> IO (Vector S Pulse)
sampleComputeSound SamplingInfo
si ComputeSound Pulse
cs
  String -> IO String
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (String -> IO String) -> String -> IO String
forall a b. (a -> b) -> a -> b
$ [Pulse] -> String
forall a. Show a => a -> String
show ([Pulse] -> String) -> [Pulse] -> String
forall a b. (a -> b) -> a -> b
$ Vector S Pulse -> [Pulse]
forall ix r e. (Index ix, Source r e) => Array r ix e -> [e]
M.toList Vector S Pulse
floats

instance Semigroup (Sound d Pulse) where
  -- \| Combines two sounds in a parallel manner (see 'parallel2')
  <> :: Sound d Pulse -> Sound d Pulse -> Sound d Pulse
(<>) = Sound d Pulse -> Sound d Pulse -> Sound d Pulse
forall (d :: SoundDuration).
Sound d Pulse -> Sound d Pulse -> Sound d Pulse
parallel2

instance Monoid (Sound I Pulse) where
  mempty :: Sound 'I Pulse
mempty = Pulse -> Sound 'I Pulse
forall a. a -> Sound 'I a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Pulse
0

instance Monoid (Sound T Pulse) where
  mempty :: Sound 'T Pulse
mempty = Duration -> ComputeSound Pulse -> Sound 'T Pulse
forall a. Duration -> ComputeSound a -> Sound 'T a
TimedSound Duration
0 (ComputeSound Pulse -> Sound 'T Pulse)
-> ComputeSound Pulse -> Sound 'T Pulse
forall a b. (a -> b) -> a -> b
$ (SamplingInfo -> Ix1 -> Pulse) -> ComputeSound Pulse
forall a. (SamplingInfo -> Ix1 -> a) -> ComputeSound a
makeWithIndexFunction ((SamplingInfo -> Ix1 -> Pulse) -> ComputeSound Pulse)
-> (SamplingInfo -> Ix1 -> Pulse) -> ComputeSound Pulse
forall a b. (a -> b) -> a -> b
$ (Ix1 -> Pulse) -> SamplingInfo -> Ix1 -> Pulse
forall a b. a -> b -> a
const ((Ix1 -> Pulse) -> SamplingInfo -> Ix1 -> Pulse)
-> (Ix1 -> Pulse) -> SamplingInfo -> Ix1 -> Pulse
forall a b. (a -> b) -> a -> b
$ Pulse -> Ix1 -> Pulse
forall a b. a -> b -> a
const Pulse
0

instance (Num a) => Num (Sound I a) where
  + :: Sound 'I a -> Sound 'I a -> Sound 'I a
(+) = (a -> a -> a)
-> Sound 'I a -> Sound 'I a -> Sound (DetermineDuration 'I 'I) a
forall a b c (d1 :: SoundDuration) (d2 :: SoundDuration).
(a -> b -> c)
-> Sound d1 a -> Sound d2 b -> Sound (DetermineDuration d1 d2) c
zipSoundWith a -> a -> a
forall a. Num a => a -> a -> a
(+)
  * :: Sound 'I a -> Sound 'I a -> Sound 'I a
(*) = (a -> a -> a)
-> Sound 'I a -> Sound 'I a -> Sound (DetermineDuration 'I 'I) a
forall a b c (d1 :: SoundDuration) (d2 :: SoundDuration).
(a -> b -> c)
-> Sound d1 a -> Sound d2 b -> Sound (DetermineDuration d1 d2) c
zipSoundWith a -> a -> a
forall a. Num a => a -> a -> a
(*)
  (-) = (a -> a -> a)
-> Sound 'I a -> Sound 'I a -> Sound (DetermineDuration 'I 'I) a
forall a b c (d1 :: SoundDuration) (d2 :: SoundDuration).
(a -> b -> c)
-> Sound d1 a -> Sound d2 b -> Sound (DetermineDuration d1 d2) c
zipSoundWith (-)
  abs :: Sound 'I a -> Sound 'I a
abs = (a -> a) -> Sound 'I a -> Sound 'I a
forall a b. (a -> b) -> Sound 'I a -> Sound 'I b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap a -> a
forall a. Num a => a -> a
abs
  fromInteger :: Integer -> Sound 'I a
fromInteger Integer
x = (SamplingInfo -> Ix1 -> a) -> Sound 'I a
forall a. (SamplingInfo -> Ix1 -> a) -> Sound 'I a
makeSound ((SamplingInfo -> Ix1 -> a) -> Sound 'I a)
-> (SamplingInfo -> Ix1 -> a) -> Sound 'I a
forall a b. (a -> b) -> a -> b
$ \SamplingInfo
_ Ix1
_ -> Integer -> a
forall a. Num a => Integer -> a
fromInteger Integer
x
  signum :: Sound 'I a -> Sound 'I a
signum = (a -> a) -> Sound 'I a -> Sound 'I a
forall a b. (a -> b) -> Sound 'I a -> Sound 'I b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap a -> a
forall a. Num a => a -> a
signum
  negate :: Sound 'I a -> Sound 'I a
negate = (a -> a) -> Sound 'I a -> Sound 'I a
forall a b. (a -> b) -> Sound 'I a -> Sound 'I b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap a -> a
forall a. Num a => a -> a
negate

instance Functor (Sound d) where
  fmap :: forall a b. (a -> b) -> Sound d a -> Sound d b
fmap a -> b
f = (ComputeSound a -> ComputeSound b) -> Sound d a -> Sound d b
forall a b (d :: SoundDuration).
(ComputeSound a -> ComputeSound b) -> Sound d a -> Sound d b
mapComputation ((ComputeSound a -> ComputeSound b) -> Sound d a -> Sound d b)
-> (ComputeSound a -> ComputeSound b) -> Sound d a -> Sound d b
forall a b. (a -> b) -> a -> b
$ (a -> b) -> ComputeSound a -> ComputeSound b
forall a b. (a -> b) -> ComputeSound a -> ComputeSound b
mapComputeSound a -> b
f

instance Applicative (Sound I) where
  pure :: forall a. a -> Sound 'I a
pure a
a = (SamplingInfo -> Ix1 -> a) -> Sound 'I a
forall a. (SamplingInfo -> Ix1 -> a) -> Sound 'I a
makeSound ((SamplingInfo -> Ix1 -> a) -> Sound 'I a)
-> (SamplingInfo -> Ix1 -> a) -> Sound 'I a
forall a b. (a -> b) -> a -> b
$ \SamplingInfo
_ Ix1
_ -> a
a
  <*> :: forall a b. Sound 'I (a -> b) -> Sound 'I a -> Sound 'I b
(<*>) = ((a -> b) -> a -> b)
-> Sound 'I (a -> b)
-> Sound 'I a
-> Sound (DetermineDuration 'I 'I) b
forall a b c (d1 :: SoundDuration) (d2 :: SoundDuration).
(a -> b -> c)
-> Sound d1 a -> Sound d2 b -> Sound (DetermineDuration d1 d2) c
zipSoundWith (a -> b) -> a -> b
forall a b. (a -> b) -> a -> b
($)

-- | Append two sounds. This is only possible for sounds with a duration.
timedSequentially :: Sound T Pulse -> Sound T Pulse -> Sound T Pulse
timedSequentially :: Sound 'T Pulse -> Sound 'T Pulse -> Sound 'T Pulse
timedSequentially (TimedSound Duration
d1 ComputeSound Pulse
c1) (TimedSound Duration
d2 ComputeSound Pulse
c2) =
  Duration -> ComputeSound Pulse -> Sound 'T Pulse
forall a. Duration -> ComputeSound a -> Sound 'T a
TimedSound (Duration
d1 Duration -> Duration -> Duration
forall a. Num a => a -> a -> a
+ Duration
d2) (ComputeSound Pulse -> Sound 'T Pulse)
-> ComputeSound Pulse -> Sound 'T Pulse
forall a b. (a -> b) -> a -> b
$
    Percentage
-> ComputeSound Pulse -> ComputeSound Pulse -> ComputeSound Pulse
computeSequentially (Duration -> Percentage
forall a b. Coercible a b => a -> b
coerce (Duration -> Percentage) -> Duration -> Percentage
forall a b. (a -> b) -> a -> b
$ Duration
d1 Duration -> Duration -> Duration
forall a. Fractional a => a -> a -> a
/ (Duration
d1 Duration -> Duration -> Duration
forall a. Num a => a -> a -> a
+ Duration
d2)) ComputeSound Pulse
c1 ComputeSound Pulse
c2

-- | Append two infinite sounds where the 'Percentage' in the range @[0,1]@
-- specifies when the first sound ends and the next begins.
infiniteSequentially :: Percentage -> Sound I Pulse -> Sound I Pulse -> Sound I Pulse
infiniteSequentially :: Percentage -> Sound 'I Pulse -> Sound 'I Pulse -> Sound 'I Pulse
infiniteSequentially Percentage
factor' (InfiniteSound ComputeSound Pulse
c1) (InfiniteSound ComputeSound Pulse
c2) =
  ComputeSound Pulse -> Sound 'I Pulse
forall a. ComputeSound a -> Sound 'I a
InfiniteSound (ComputeSound Pulse -> Sound 'I Pulse)
-> ComputeSound Pulse -> Sound 'I Pulse
forall a b. (a -> b) -> a -> b
$
    Percentage
-> ComputeSound Pulse -> ComputeSound Pulse -> ComputeSound Pulse
computeSequentially Percentage
factor ComputeSound Pulse
c1 ComputeSound Pulse
c2
  where
    factor :: Percentage
factor = Percentage -> Percentage -> Percentage
forall a. Ord a => a -> a -> a
max Percentage
0 (Percentage -> Percentage) -> Percentage -> Percentage
forall a b. (a -> b) -> a -> b
$ Percentage -> Percentage -> Percentage
forall a. Ord a => a -> a -> a
min Percentage
1 Percentage
factor'

-- | Same as 'timedSequentially'
(>>>) :: Sound T Pulse -> Sound T Pulse -> Sound T Pulse
>>> :: Sound 'T Pulse -> Sound 'T Pulse -> Sound 'T Pulse
(>>>) = Sound 'T Pulse -> Sound 'T Pulse -> Sound 'T Pulse
timedSequentially

infixl 5 >>>

-- | Combine a list of sounds in a sequential manner.
sequentially :: [Sound T Pulse] -> Sound T Pulse
sequentially :: [Sound 'T Pulse] -> Sound 'T Pulse
sequentially = (Sound 'T Pulse -> Sound 'T Pulse -> Sound 'T Pulse)
-> Sound 'T Pulse -> [Sound 'T Pulse] -> Sound 'T Pulse
forall b a. (b -> a -> b) -> b -> [a] -> b
forall (t :: * -> *) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
foldl' Sound 'T Pulse -> Sound 'T Pulse -> Sound 'T Pulse
timedSequentially Sound 'T Pulse
forall a. Monoid a => a
mempty

-- | Combine two sounds such that they play in parallel. If one 'Sound' is longer than the other,
-- it will be played without the shorter one for its remaining time
parallel2 :: Sound d Pulse -> Sound d Pulse -> Sound d Pulse
parallel2 :: forall (d :: SoundDuration).
Sound d Pulse -> Sound d Pulse -> Sound d Pulse
parallel2 (InfiniteSound ComputeSound Pulse
c1) (InfiniteSound ComputeSound Pulse
c2) = ComputeSound Pulse -> Sound 'I Pulse
forall a. ComputeSound a -> Sound 'I a
InfiniteSound (ComputeSound Pulse -> Sound 'I Pulse)
-> ComputeSound Pulse -> Sound 'I Pulse
forall a b. (a -> b) -> a -> b
$ ComputeSound Pulse
-> Percentage -> ComputeSound Pulse -> ComputeSound Pulse
computeParallel ComputeSound Pulse
c1 Percentage
1 ComputeSound Pulse
c2
parallel2 (TimedSound Duration
d1 ComputeSound Pulse
c1) (TimedSound Duration
d2 ComputeSound Pulse
c2) = Duration -> ComputeSound Pulse -> Sound 'T Pulse
forall a. Duration -> ComputeSound a -> Sound 'T a
TimedSound Duration
newDuration (ComputeSound Pulse -> Sound 'T Pulse)
-> ComputeSound Pulse -> Sound 'T Pulse
forall a b. (a -> b) -> a -> b
$ ComputeSound Pulse
-> Percentage -> ComputeSound Pulse -> ComputeSound Pulse
computeParallel ComputeSound Pulse
longerC (Duration -> Percentage
forall a b. Coercible a b => a -> b
coerce Duration
factor) ComputeSound Pulse
shorterC
  where
    (ComputeSound Pulse
longerC, Duration
factor, ComputeSound Pulse
shorterC) =
      if Duration
d1 Duration -> Duration -> Bool
forall a. Ord a => a -> a -> Bool
>= Duration
d2
        then (ComputeSound Pulse
c1, Duration
d2 Duration -> Duration -> Duration
forall a. Fractional a => a -> a -> a
/ Duration
newDuration, ComputeSound Pulse
c2)
        else (ComputeSound Pulse
c2, Duration
d1 Duration -> Duration -> Duration
forall a. Fractional a => a -> a -> a
/ Duration
newDuration, ComputeSound Pulse
c1)
    newDuration :: Duration
newDuration = Duration -> Duration -> Duration
forall a. Ord a => a -> a -> a
max Duration
d1 Duration
d2

-- | Combine a lists of sounds such that they play in parallel
parallel :: (Monoid (Sound d Pulse)) => [Sound d Pulse] -> Sound d Pulse
parallel :: forall (d :: SoundDuration).
Monoid (Sound d Pulse) =>
[Sound d Pulse] -> Sound d Pulse
parallel = (Sound d Pulse -> Sound d Pulse -> Sound d Pulse)
-> Sound d Pulse -> [Sound d Pulse] -> Sound d Pulse
forall b a. (b -> a -> b) -> b -> [a] -> b
forall (t :: * -> *) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
foldl' Sound d Pulse -> Sound d Pulse -> Sound d Pulse
forall (d :: SoundDuration).
Sound d Pulse -> Sound d Pulse -> Sound d Pulse
parallel2 Sound d Pulse
forall a. Monoid a => a
mempty

-- | Zip two 'Sound's. The duration of the resulting 'Sound' is equivalent
-- to the duration of the shorter 'Sound', cutting away the excess samples from the longer one.
zipSoundWith :: (a -> b -> c) -> Sound d1 a -> Sound d2 b -> Sound (DetermineDuration d1 d2) c
zipSoundWith :: forall a b c (d1 :: SoundDuration) (d2 :: SoundDuration).
(a -> b -> c)
-> Sound d1 a -> Sound d2 b -> Sound (DetermineDuration d1 d2) c
zipSoundWith a -> b -> c
f Sound d1 a
sound1 Sound d2 b
sound2 =
  case (Sound d1 a
sound1, Sound d2 b
sound2) of
    (TimedSound Duration
d1 ComputeSound a
_, TimedSound Duration
d2 ComputeSound b
_) ->
      let d :: Duration
d = Duration -> Duration -> Duration
forall a. Ord a => a -> a -> a
min Duration
d1 Duration
d2
       in case (Duration -> Sound 'T a -> Sound 'T a
forall a. Duration -> Sound 'T a -> Sound 'T a
takeSound Duration
d Sound d1 a
Sound 'T a
sound1, Duration -> Sound 'T b -> Sound 'T b
forall a. Duration -> Sound 'T a -> Sound 'T a
takeSound Duration
d Sound d2 b
Sound 'T b
sound2) of
            (TimedSound Duration
_ ComputeSound a
c1, TimedSound Duration
_ ComputeSound b
c2) -> Duration -> ComputeSound c -> Sound 'T c
forall a. Duration -> ComputeSound a -> Sound 'T a
TimedSound Duration
d (ComputeSound c -> Sound 'T c) -> ComputeSound c -> Sound 'T c
forall a b. (a -> b) -> a -> b
$ (a -> b -> c) -> ComputeSound a -> ComputeSound b -> ComputeSound c
forall a b c.
(a -> b -> c) -> ComputeSound a -> ComputeSound b -> ComputeSound c
zipWithCompute a -> b -> c
f ComputeSound a
c1 ComputeSound b
c2
    (TimedSound Duration
d ComputeSound a
c1, InfiniteSound ComputeSound b
c2) -> Duration -> ComputeSound c -> Sound 'T c
forall a. Duration -> ComputeSound a -> Sound 'T a
TimedSound Duration
d (ComputeSound c -> Sound 'T c) -> ComputeSound c -> Sound 'T c
forall a b. (a -> b) -> a -> b
$ (a -> b -> c) -> ComputeSound a -> ComputeSound b -> ComputeSound c
forall a b c.
(a -> b -> c) -> ComputeSound a -> ComputeSound b -> ComputeSound c
zipWithCompute a -> b -> c
f ComputeSound a
c1 ComputeSound b
c2
    (InfiniteSound ComputeSound a
c1, TimedSound Duration
d ComputeSound b
c2) -> Duration -> ComputeSound c -> Sound 'T c
forall a. Duration -> ComputeSound a -> Sound 'T a
TimedSound Duration
d (ComputeSound c -> Sound 'T c) -> ComputeSound c -> Sound 'T c
forall a b. (a -> b) -> a -> b
$ (a -> b -> c) -> ComputeSound a -> ComputeSound b -> ComputeSound c
forall a b c.
(a -> b -> c) -> ComputeSound a -> ComputeSound b -> ComputeSound c
zipWithCompute a -> b -> c
f ComputeSound a
c1 ComputeSound b
c2
    (InfiniteSound ComputeSound a
c1, InfiniteSound ComputeSound b
c2) -> ComputeSound c -> Sound 'I c
forall a. ComputeSound a -> Sound 'I a
InfiniteSound (ComputeSound c -> Sound 'I c) -> ComputeSound c -> Sound 'I c
forall a b. (a -> b) -> a -> b
$ (a -> b -> c) -> ComputeSound a -> ComputeSound b -> ComputeSound c
forall a b c.
(a -> b -> c) -> ComputeSound a -> ComputeSound b -> ComputeSound c
zipWithCompute a -> b -> c
f ComputeSound a
c1 ComputeSound b
c2

-- | Zip two 'Sound's. The duration of the resulting 'Sound' is equivalent
-- to the duration of the shorter 'Sound', cutting away the excess samples from the longer one.
zipSound :: Sound d1 (a -> b) -> Sound d2 a -> Sound (DetermineDuration d1 d2) b
zipSound :: forall (d1 :: SoundDuration) a b (d2 :: SoundDuration).
Sound d1 (a -> b)
-> Sound d2 a -> Sound (DetermineDuration d1 d2) b
zipSound = ((a -> b) -> a -> b)
-> Sound d1 (a -> b)
-> Sound d2 a
-> Sound (DetermineDuration d1 d2) b
forall a b c (d1 :: SoundDuration) (d2 :: SoundDuration).
(a -> b -> c)
-> Sound d1 a -> Sound d2 b -> Sound (DetermineDuration d1 d2) c
zipSoundWith (a -> b) -> a -> b
forall a b. (a -> b) -> a -> b
($)

-- | Amplifies the volume of the given 'Sound'
amplify :: Float -> Sound d Pulse -> Sound d Pulse
amplify :: forall (d :: SoundDuration).
Float -> Sound d Pulse -> Sound d Pulse
amplify Float
x = (Pulse -> Pulse) -> Sound d Pulse -> Sound d Pulse
forall a b. (a -> b) -> Sound d a -> Sound d b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (Pulse -> Pulse -> Pulse
forall a. Num a => a -> a -> a
* Float -> Pulse
forall a b. Coercible a b => a -> b
coerce Float
x)

-- | Reduces the volume of the given 'Sound'
reduce :: Float -> Sound d Pulse -> Sound d Pulse
reduce :: forall (d :: SoundDuration).
Float -> Sound d Pulse -> Sound d Pulse
reduce Float
x = Float -> Sound d Pulse -> Sound d Pulse
forall (d :: SoundDuration).
Float -> Sound d Pulse -> Sound d Pulse
amplify (Float
1 Float -> Float -> Float
forall a. Fractional a => a -> a -> a
/ Float
x)

-- | Raises the frequency of the 'Sound' by the given factor.
-- Only works if the sound is based on some frequency (e.g. 'sineWave' but not 'noise')
raise :: Float -> Sound d Pulse -> Sound d Pulse
raise :: forall (d :: SoundDuration).
Float -> Sound d Pulse -> Sound d Pulse
raise Float
x = (ComputeSound Pulse -> ComputeSound Pulse)
-> Sound d Pulse -> Sound d Pulse
forall a b (d :: SoundDuration).
(ComputeSound a -> ComputeSound b) -> Sound d a -> Sound d b
mapComputation ((ComputeSound Pulse -> ComputeSound Pulse)
 -> Sound d Pulse -> Sound d Pulse)
-> (ComputeSound Pulse -> ComputeSound Pulse)
-> Sound d Pulse
-> Sound d Pulse
forall a b. (a -> b) -> a -> b
$ \(ComputeSound SamplingInfo
-> MemoComputeSound -> IO (SoundResult Pulse, ComputationInfo)
compute) -> (SamplingInfo
 -> MemoComputeSound -> IO (SoundResult Pulse, ComputationInfo))
-> ComputeSound Pulse
forall a.
(SamplingInfo
 -> MemoComputeSound -> IO (SoundResult a, ComputationInfo))
-> ComputeSound a
ComputeSound ((SamplingInfo
  -> MemoComputeSound -> IO (SoundResult Pulse, ComputationInfo))
 -> ComputeSound Pulse)
-> (SamplingInfo
    -> MemoComputeSound -> IO (SoundResult Pulse, ComputationInfo))
-> ComputeSound Pulse
forall a b. (a -> b) -> a -> b
$ \SamplingInfo
si MemoComputeSound
memo -> do
  SamplingInfo
-> MemoComputeSound -> IO (SoundResult Pulse, ComputationInfo)
compute (SamplingInfo
si {period = coerce x * si.period}) MemoComputeSound
memo

-- | Diminishes the frequency of the 'Sound' by the given factor.
-- Only works if the sound is based on some frequency (e.g. 'pulse' but not 'noise')
diminish :: Float -> Sound d Pulse -> Sound d Pulse
diminish :: forall (d :: SoundDuration).
Float -> Sound d Pulse -> Sound d Pulse
diminish Float
x = Float -> Sound d Pulse -> Sound d Pulse
forall (d :: SoundDuration).
Float -> Sound d Pulse -> Sound d Pulse
raise (Float -> Sound d Pulse -> Sound d Pulse)
-> Float -> Sound d Pulse -> Sound d Pulse
forall a b. (a -> b) -> a -> b
$ Float
1 Float -> Float -> Float
forall a. Fractional a => a -> a -> a
/ Float
x

-- | Sets the duration of the 'Sound'.
-- The resuling sound is a 'T'imed 'Sound'.
setDuration :: Duration -> Sound d a -> Sound T a
setDuration :: forall (d :: SoundDuration) a. Duration -> Sound d a -> Sound 'T a
setDuration Duration
d (TimedSound Duration
_ ComputeSound a
c) = Duration -> ComputeSound a -> Sound 'T a
forall a. Duration -> ComputeSound a -> Sound 'T a
TimedSound (Duration -> Duration -> Duration
forall a. Ord a => a -> a -> a
max Duration
d Duration
0) ComputeSound a
c
setDuration Duration
d (InfiniteSound ComputeSound a
c) = Duration -> ComputeSound a -> Sound 'T a
forall a. Duration -> ComputeSound a -> Sound 'T a
TimedSound (Duration -> Duration -> Duration
forall a. Ord a => a -> a -> a
max Duration
d Duration
0) ComputeSound a
c

-- | Same as `setDuration` but in operator form.
(|->) :: Duration -> Sound d a -> Sound 'T a
|-> :: forall (d :: SoundDuration) a. Duration -> Sound d a -> Sound 'T a
(|->) = Duration -> Sound d a -> Sound 'T a
forall (d :: SoundDuration) a. Duration -> Sound d a -> Sound 'T a
setDuration

infix 7 |->

-- | Drop the duration associated with a 'Sound' and get an infinite sound again.
-- If you have combined timed sounds with a sequence combinator and then drop
-- their 'Duration', the sounds will keep their proportional length to each other.
-- Essentially, the percentage of their play time stays the same.
dropDuration :: Sound d a -> Sound I a
dropDuration :: forall (d :: SoundDuration) a. Sound d a -> Sound 'I a
dropDuration (InfiniteSound ComputeSound a
cs) = ComputeSound a -> Sound 'I a
forall a. ComputeSound a -> Sound 'I a
InfiniteSound ComputeSound a
cs
dropDuration (TimedSound Duration
_ ComputeSound a
cs) = ComputeSound a -> Sound 'I a
forall a. ComputeSound a -> Sound 'I a
InfiniteSound ComputeSound a
cs

-- | Scales the 'Duration' of a 'Sound'.
-- The following makes a sound twice as long:
--
-- > scaleDuration 2 sound
scaleDuration :: Float -> Sound T a -> Sound T a
scaleDuration :: forall a. Float -> Sound 'T a -> Sound 'T a
scaleDuration Float
x (TimedSound Duration
d ComputeSound a
c) = Duration -> ComputeSound a -> Sound 'T a
forall a. Duration -> ComputeSound a -> Sound 'T a
TimedSound (Float -> Duration
forall a b. Coercible a b => a -> b
coerce Float
x Duration -> Duration -> Duration
forall a. Num a => a -> a -> a
* Duration
d) ComputeSound a
c

-- | Get the duration of a 'T'imed 'Sound'
getDuration :: Sound T a -> Duration
getDuration :: forall a. Sound 'T a -> Duration
getDuration (TimedSound Duration
d ComputeSound a
_) = Duration
d

-- | Set the 'Duration' of a 'Sound' to the same as another one 'Sound'
adoptDuration :: Sound d a -> Sound x b -> Sound d b
adoptDuration :: forall (d :: SoundDuration) a (x :: SoundDuration) b.
Sound d a -> Sound x b -> Sound d b
adoptDuration (TimedSound Duration
duration ComputeSound a
_) = Duration -> Sound x b -> Sound 'T b
forall (d :: SoundDuration) a. Duration -> Sound d a -> Sound 'T a
setDuration Duration
duration
adoptDuration (InfiniteSound ComputeSound a
_) = Sound x b -> Sound d b
Sound x b -> Sound 'I b
forall (d :: SoundDuration) a. Sound d a -> Sound 'I a
dropDuration

-- | Reverses a 'Sound' similar to 'reverse' for lists
reverseSound :: Sound d a -> Sound d a
reverseSound :: forall (d :: SoundDuration) a. Sound d a -> Sound d a
reverseSound = (ComputeSound a -> ComputeSound a) -> Sound d a -> Sound d a
forall a b (d :: SoundDuration).
(ComputeSound a -> ComputeSound b) -> Sound d a -> Sound d b
mapComputation ((ComputeSound a -> ComputeSound a) -> Sound d a -> Sound d a)
-> (ComputeSound a -> ComputeSound a) -> Sound d a -> Sound d a
forall a b. (a -> b) -> a -> b
$ (SamplingInfo -> Vector D a -> Vector D a)
-> ComputeSound a -> ComputeSound a
forall a b.
(SamplingInfo -> Vector D a -> Vector D b)
-> ComputeSound a -> ComputeSound b
mapDelayedResult ((SamplingInfo -> Vector D a -> Vector D a)
 -> ComputeSound a -> ComputeSound a)
-> (SamplingInfo -> Vector D a -> Vector D a)
-> ComputeSound a
-> ComputeSound a
forall a b. (a -> b) -> a -> b
$ \SamplingInfo
si ->
  Sz Ix1 -> (Ix1 -> Ix1) -> Vector D a -> Vector D a
forall ix' r' e ix.
(Index ix', Source r' e, Index ix) =>
Sz ix -> (ix -> ix') -> Array r' ix' e -> Array D ix e
MU.unsafeBackpermute (Ix1 -> Sz Ix1
M.Sz1 SamplingInfo
si.samples) (\Ix1
index -> Ix1 -> Ix1
forall a. Enum a => a -> a
pred SamplingInfo
si.samples Ix1 -> Ix1 -> Ix1
forall a. Num a => a -> a -> a
- Ix1
index)

-- | Drop parts of a sound similar to 'drop' for lists
dropSound :: Duration -> Sound T a -> Sound T a
dropSound :: forall a. Duration -> Sound 'T a -> Sound 'T a
dropSound Duration
dropD' (TimedSound Duration
originalD ComputeSound a
cs) =
  Duration -> ComputeSound a -> Sound 'T a
forall a. Duration -> ComputeSound a -> Sound 'T a
TimedSound (Duration
originalD Duration -> Duration -> Duration
forall a. Num a => a -> a -> a
- Duration
dropD) (ComputeSound a -> Sound 'T a) -> ComputeSound a -> Sound 'T a
forall a b. (a -> b) -> a -> b
$
    (SamplingInfo -> ComputeSound a) -> ComputeSound a
forall a. (SamplingInfo -> ComputeSound a) -> ComputeSound a
withSamplingInfoCS ((SamplingInfo -> ComputeSound a) -> ComputeSound a)
-> (SamplingInfo -> ComputeSound a) -> ComputeSound a
forall a b. (a -> b) -> a -> b
$ \SamplingInfo
oldSI ->
      (SamplingInfo -> SamplingInfo) -> ComputeSound a -> ComputeSound a
forall a.
(SamplingInfo -> SamplingInfo) -> ComputeSound a -> ComputeSound a
changeSamplingInfo (\SamplingInfo
si -> SamplingInfo
si {samples = round $ factor * fromIntegral si.samples}) (ComputeSound a -> ComputeSound a)
-> ComputeSound a -> ComputeSound a
forall a b. (a -> b) -> a -> b
$
        (SamplingInfo -> Vector D a -> Vector D a)
-> ComputeSound a -> ComputeSound a
forall a b.
(SamplingInfo -> Vector D a -> Vector D b)
-> ComputeSound a -> ComputeSound b
mapDelayedResult
          ( \SamplingInfo
newSI ->
              Sz Ix1 -> (Ix1 -> Ix1) -> Vector D a -> Vector D a
forall ix' r' e ix.
(Index ix', Source r' e, Index ix) =>
Sz ix -> (ix -> ix') -> Array r' ix' e -> Array D ix e
MU.unsafeBackpermute (Ix1 -> Sz Ix1
M.Sz1 SamplingInfo
oldSI.samples) ((Ix1 -> Ix1) -> Vector D a -> Vector D a)
-> (Ix1 -> Ix1) -> Vector D a -> Vector D a
forall a b. (a -> b) -> a -> b
$ \Ix1
index ->
                Ix1
index Ix1 -> Ix1 -> Ix1
forall a. Num a => a -> a -> a
+ SamplingInfo
newSI.samples Ix1 -> Ix1 -> Ix1
forall a. Num a => a -> a -> a
- SamplingInfo
oldSI.samples
          )
          ComputeSound a
cs
  where
    dropD :: Duration
dropD = Duration -> Duration -> Duration
forall a. Ord a => a -> a -> a
max Duration
0 (Duration -> Duration) -> Duration -> Duration
forall a b. (a -> b) -> a -> b
$ Duration -> Duration -> Duration
forall a. Ord a => a -> a -> a
min Duration
originalD Duration
dropD'
    droppedFactor :: Duration
droppedFactor = Duration -> Duration -> Duration
forall a. Ord a => a -> a -> a
min Duration
1 (Duration -> Duration) -> Duration -> Duration
forall a b. (a -> b) -> a -> b
$ Duration
dropD Duration -> Duration -> Duration
forall a. Fractional a => a -> a -> a
/ Duration
originalD
    factor :: Duration
factor =
      if Duration
droppedFactor Duration -> Duration -> Bool
forall a. Eq a => a -> a -> Bool
== Duration
1
        then Duration
0
        else Duration
1 Duration -> Duration -> Duration
forall a. Fractional a => a -> a -> a
/ (Duration
1 Duration -> Duration -> Duration
forall a. Num a => a -> a -> a
- Duration
droppedFactor)

-- | Take parts of a sound similar to 'take' for lists
takeSound :: Duration -> Sound T a -> Sound T a
takeSound :: forall a. Duration -> Sound 'T a -> Sound 'T a
takeSound Duration
takeD' (TimedSound Duration
originalD ComputeSound a
cs) =
  Duration -> ComputeSound a -> Sound 'T a
forall a. Duration -> ComputeSound a -> Sound 'T a
TimedSound Duration
takeD (ComputeSound a -> Sound 'T a) -> ComputeSound a -> Sound 'T a
forall a b. (a -> b) -> a -> b
$
    (SamplingInfo -> ComputeSound a) -> ComputeSound a
forall a. (SamplingInfo -> ComputeSound a) -> ComputeSound a
withSamplingInfoCS ((SamplingInfo -> ComputeSound a) -> ComputeSound a)
-> (SamplingInfo -> ComputeSound a) -> ComputeSound a
forall a b. (a -> b) -> a -> b
$ \SamplingInfo
oldSI ->
      (SamplingInfo -> SamplingInfo) -> ComputeSound a -> ComputeSound a
forall a.
(SamplingInfo -> SamplingInfo) -> ComputeSound a -> ComputeSound a
changeSamplingInfo
        ( \SamplingInfo
si ->
            SamplingInfo
si
              { samples =
                  if takeD == 0
                    then 0
                    else round $ fromIntegral @_ @Float si.samples * (1 / coerce factor)
              }
        )
        (ComputeSound a -> ComputeSound a)
-> ComputeSound a -> ComputeSound a
forall a b. (a -> b) -> a -> b
$ (SamplingInfo -> Vector D a -> Vector D a)
-> ComputeSound a -> ComputeSound a
forall a b.
(SamplingInfo -> Vector D a -> Vector D b)
-> ComputeSound a -> ComputeSound b
mapDelayedResult
          (\SamplingInfo
_ -> Ix1 -> Sz Ix1 -> Vector D a -> Vector D a
forall r e.
(HasCallStack, Source r e) =>
Ix1 -> Sz Ix1 -> Vector r e -> Vector r e
M.slice' Ix1
0 (Sz Ix1 -> Vector D a -> Vector D a)
-> Sz Ix1 -> Vector D a -> Vector D a
forall a b. (a -> b) -> a -> b
$ Ix1 -> Sz Ix1
M.Sz1 SamplingInfo
oldSI.samples)
          ComputeSound a
cs
  where
    takeD :: Duration
takeD = Duration -> Duration -> Duration
forall a. Ord a => a -> a -> a
max Duration
0 (Duration -> Duration) -> Duration -> Duration
forall a b. (a -> b) -> a -> b
$ Duration -> Duration -> Duration
forall a. Ord a => a -> a -> a
min Duration
takeD' Duration
originalD
    factor :: Duration
factor = Duration
takeD Duration -> Duration -> Duration
forall a. Fractional a => a -> a -> a
/ Duration
originalD

-- | Change how the 'Sound' progresses. For example, you can slow it
-- down in the beginning and speed it up at the end. However, the total
-- duration stays the same.
--
-- Negative 'Progress' is treated as '0' and 'Progress' above '1' is treated as '1'
changeTempo :: (Progress -> Progress) -> Sound d a -> Sound d a
changeTempo :: forall (d :: SoundDuration) a.
(Progress -> Progress) -> Sound d a -> Sound d a
changeTempo Progress -> Progress
f = (ComputeSound a -> ComputeSound a) -> Sound d a -> Sound d a
forall a b (d :: SoundDuration).
(ComputeSound a -> ComputeSound b) -> Sound d a -> Sound d b
mapComputation ((ComputeSound a -> ComputeSound a) -> Sound d a -> Sound d a)
-> (ComputeSound a -> ComputeSound a) -> Sound d a -> Sound d a
forall a b. (a -> b) -> a -> b
$ (SamplingInfo -> Vector D a -> Vector D a)
-> ComputeSound a -> ComputeSound a
forall a b.
(SamplingInfo -> Vector D a -> Vector D b)
-> ComputeSound a -> ComputeSound b
mapDelayedResult ((SamplingInfo -> Vector D a -> Vector D a)
 -> ComputeSound a -> ComputeSound a)
-> (SamplingInfo -> Vector D a -> Vector D a)
-> ComputeSound a
-> ComputeSound a
forall a b. (a -> b) -> a -> b
$ \SamplingInfo
si ->
  Sz Ix1 -> (Ix1 -> Ix1) -> Vector D a -> Vector D a
forall ix' r' e ix.
(Index ix', Source r' e, Index ix) =>
Sz ix -> (ix -> ix') -> Array r' ix' e -> Array D ix e
MU.unsafeBackpermute (Ix1 -> Sz Ix1
M.Sz1 SamplingInfo
si.samples) ((Ix1 -> Ix1) -> Vector D a -> Vector D a)
-> (Ix1 -> Ix1) -> Vector D a -> Vector D a
forall a b. (a -> b) -> a -> b
$ \Ix1
index ->
    Ix1 -> Ix1 -> Ix1
forall a. Ord a => a -> a -> a
min SamplingInfo
si.samples (Ix1 -> Ix1) -> Ix1 -> Ix1
forall a b. (a -> b) -> a -> b
$
      Progress -> Ix1
forall b. Integral b => Progress -> b
forall a b. (RealFrac a, Integral b) => a -> b
round (Progress -> Ix1) -> Progress -> Ix1
forall a b. (a -> b) -> a -> b
$
        Progress -> Progress
f
          (Ix1 -> Progress
forall a b. (Integral a, Num b) => a -> b
fromIntegral Ix1
index Progress -> Progress -> Progress
forall a. Fractional a => a -> a -> a
/ Ix1 -> Progress
forall a b. (Integral a, Num b) => a -> b
fromIntegral SamplingInfo
si.samples)
          Progress -> Progress -> Progress
forall a. Num a => a -> a -> a
* Ix1 -> Progress
forall a b. (Integral a, Num b) => a -> b
fromIntegral SamplingInfo
si.samples

changeTempoM :: Sound I (Progress -> Progress) -> Sound d a -> Sound d a
changeTempoM :: forall (d :: SoundDuration) a.
Sound 'I (Progress -> Progress) -> Sound d a -> Sound d a
changeTempoM (InfiniteSound ComputeSound (Progress -> Progress)
msc1) =
  (ComputeSound a -> ComputeSound a) -> Sound d a -> Sound d a
forall a b (d :: SoundDuration).
(ComputeSound a -> ComputeSound b) -> Sound d a -> Sound d b
mapComputation ((ComputeSound a -> ComputeSound a) -> Sound d a -> Sound d a)
-> (ComputeSound a -> ComputeSound a) -> Sound d a -> Sound d a
forall a b. (a -> b) -> a -> b
$
    (SamplingInfo
 -> Vector D (Progress -> Progress) -> Vector D a -> Vector D a)
-> ComputeSound (Progress -> Progress)
-> ComputeSound a
-> ComputeSound a
forall a b c.
(SamplingInfo -> Vector D a -> Vector D b -> Vector D c)
-> ComputeSound a -> ComputeSound b -> ComputeSound c
mergeDelayedResult
      ( \SamplingInfo
si Vector D (Progress -> Progress)
progressVector Vector D a
valueVector ->
          Comp -> Sz Ix1 -> (Ix1 -> a) -> Vector D a
forall r ix e.
Load r ix e =>
Comp -> Sz ix -> (ix -> e) -> Array r ix e
M.makeArray Comp
M.Seq (Ix1 -> Sz Ix1
M.Sz1 SamplingInfo
si.samples) ((Ix1 -> a) -> Vector D a) -> (Ix1 -> a) -> Vector D a
forall a b. (a -> b) -> a -> b
$ \Ix1
index ->
            Vector D a -> Ix1 -> a
forall ix. Index ix => Array D ix a -> ix -> a
forall r e ix. (Source r e, Index ix) => Array r ix e -> ix -> e
MU.unsafeIndex Vector D a
valueVector (Ix1 -> a) -> Ix1 -> a
forall a b. (a -> b) -> a -> b
$
              Ix1 -> Ix1 -> Ix1
forall a. Ord a => a -> a -> a
min SamplingInfo
si.samples (Ix1 -> Ix1) -> Ix1 -> Ix1
forall a b. (a -> b) -> a -> b
$
                Progress -> Ix1
forall b. Integral b => Progress -> b
forall a b. (RealFrac a, Integral b) => a -> b
round (Progress -> Ix1) -> Progress -> Ix1
forall a b. (a -> b) -> a -> b
$
                  Vector D (Progress -> Progress) -> Ix1 -> Progress -> Progress
forall ix.
Index ix =>
Array D ix (Progress -> Progress) -> ix -> Progress -> Progress
forall r e ix. (Source r e, Index ix) => Array r ix e -> ix -> e
MU.unsafeIndex
                    Vector D (Progress -> Progress)
progressVector
                    Ix1
index
                    (Ix1 -> Progress
forall a b. (Integral a, Num b) => a -> b
fromIntegral Ix1
index Progress -> Progress -> Progress
forall a. Fractional a => a -> a -> a
/ Ix1 -> Progress
forall a b. (Integral a, Num b) => a -> b
fromIntegral SamplingInfo
si.samples)
                    Progress -> Progress -> Progress
forall a. Num a => a -> a -> a
* Ix1 -> Progress
forall a b. (Integral a, Num b) => a -> b
fromIntegral SamplingInfo
si.samples
      )
      ComputeSound (Progress -> Progress)
msc1

-- | Compute a value once and then reuse it while computing all samples
computeOnce :: (SamplingInfo -> a) -> Sound d (a -> b) -> Sound d b
computeOnce :: forall a (d :: SoundDuration) b.
(SamplingInfo -> a) -> Sound d (a -> b) -> Sound d b
computeOnce SamplingInfo -> a
f = (ComputeSound (a -> b) -> ComputeSound b)
-> Sound d (a -> b) -> Sound d b
forall a b (d :: SoundDuration).
(ComputeSound a -> ComputeSound b) -> Sound d a -> Sound d b
mapComputation ((ComputeSound (a -> b) -> ComputeSound b)
 -> Sound d (a -> b) -> Sound d b)
-> (ComputeSound (a -> b) -> ComputeSound b)
-> Sound d (a -> b)
-> Sound d b
forall a b. (a -> b) -> a -> b
$ (SamplingInfo -> Vector D (a -> b) -> Vector D b)
-> ComputeSound (a -> b) -> ComputeSound b
forall a b.
(SamplingInfo -> Vector D a -> Vector D b)
-> ComputeSound a -> ComputeSound b
mapDelayedResult ((SamplingInfo -> Vector D (a -> b) -> Vector D b)
 -> ComputeSound (a -> b) -> ComputeSound b)
-> (SamplingInfo -> Vector D (a -> b) -> Vector D b)
-> ComputeSound (a -> b)
-> ComputeSound b
forall a b. (a -> b) -> a -> b
$ \SamplingInfo
si ->
  let a :: a
a = SamplingInfo -> a
f SamplingInfo
si
   in ((a -> b) -> b) -> Vector D (a -> b) -> Vector D b
forall ix r e' e.
(Index ix, Source r e') =>
(e' -> e) -> Array r ix e' -> Array D ix e
M.map ((a -> b) -> a -> b
forall a b. (a -> b) -> a -> b
$ a
a)

-- | Fill a sound with a vector of sound samples. Keep in mind that the vector has the appropriate length!
fillWholeSound :: (M.Load r M.Ix1 Pulse) => (SamplingInfo -> M.Vector r Pulse) -> Sound I Pulse
fillWholeSound :: forall r.
Load r Ix1 Pulse =>
(SamplingInfo -> Vector r Pulse) -> Sound 'I Pulse
fillWholeSound SamplingInfo -> Vector r Pulse
f = ComputeSound Pulse -> Sound 'I Pulse
forall a. ComputeSound a -> Sound 'I a
InfiniteSound (ComputeSound Pulse -> Sound 'I Pulse)
-> ComputeSound Pulse -> Sound 'I Pulse
forall a b. (a -> b) -> a -> b
$ (SamplingInfo -> MVector RealWorld S Pulse -> IO ())
-> ComputeSound Pulse
fillSoundInMemoryIO ((SamplingInfo -> MVector RealWorld S Pulse -> IO ())
 -> ComputeSound Pulse)
-> (SamplingInfo -> MVector RealWorld S Pulse -> IO ())
-> ComputeSound Pulse
forall a b. (a -> b) -> a -> b
$ \SamplingInfo
si MVector RealWorld S Pulse
dest -> do
  let vector :: Vector r Pulse
vector = SamplingInfo -> Vector r Pulse
f SamplingInfo
si
  MVector RealWorld S Pulse -> Vector r Pulse -> IO ()
forall r' ix' e r ix (m :: * -> *).
(Load r' ix' e, Manifest r e, Index ix, MonadIO m) =>
MArray RealWorld r ix e -> Array r' ix' e -> m ()
M.computeInto MVector RealWorld S Pulse
dest Vector r Pulse
vector

-- | Fill a sound with a vector of sound samples in a mutable fashion.
fillWholeSoundST :: (SamplingInfo -> M.MVector M.RealWorld M.S Pulse -> ST M.RealWorld ()) -> Sound I Pulse
fillWholeSoundST :: (SamplingInfo -> MVector RealWorld S Pulse -> ST RealWorld ())
-> Sound 'I Pulse
fillWholeSoundST SamplingInfo -> MVector RealWorld S Pulse -> ST RealWorld ()
f = ComputeSound Pulse -> Sound 'I Pulse
forall a. ComputeSound a -> Sound 'I a
InfiniteSound (ComputeSound Pulse -> Sound 'I Pulse)
-> ComputeSound Pulse -> Sound 'I Pulse
forall a b. (a -> b) -> a -> b
$ (SamplingInfo -> MVector RealWorld S Pulse -> IO ())
-> ComputeSound Pulse
fillSoundInMemoryIO ((SamplingInfo -> MVector RealWorld S Pulse -> IO ())
 -> ComputeSound Pulse)
-> (SamplingInfo -> MVector RealWorld S Pulse -> IO ())
-> ComputeSound Pulse
forall a b. (a -> b) -> a -> b
$ (ST RealWorld () -> IO ())
-> (MVector RealWorld S Pulse -> ST RealWorld ())
-> MVector RealWorld S Pulse
-> IO ()
forall a b.
(a -> b)
-> (MVector RealWorld S Pulse -> a)
-> MVector RealWorld S Pulse
-> b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap ST RealWorld () -> IO ()
forall a. ST RealWorld a -> IO a
stToIO ((MVector RealWorld S Pulse -> ST RealWorld ())
 -> MVector RealWorld S Pulse -> IO ())
-> (SamplingInfo -> MVector RealWorld S Pulse -> ST RealWorld ())
-> SamplingInfo
-> MVector RealWorld S Pulse
-> IO ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. SamplingInfo -> MVector RealWorld S Pulse -> ST RealWorld ()
f

-- | Modify all samples of a sound so that you can look into the past and future
-- of a sound (e.g. IIR filter).
modifyWholeSound :: (M.Load r M.Ix1 Pulse) => (M.Vector M.S Pulse -> M.Vector r Pulse) -> Sound d Pulse -> Sound d Pulse
modifyWholeSound :: forall r (d :: SoundDuration).
Load r Ix1 Pulse =>
(Vector S Pulse -> Vector r Pulse)
-> Sound d Pulse -> Sound d Pulse
modifyWholeSound Vector S Pulse -> Vector r Pulse
f = (ComputeSound Pulse -> ComputeSound Pulse)
-> Sound d Pulse -> Sound d Pulse
forall a b (d :: SoundDuration).
(ComputeSound a -> ComputeSound b) -> Sound d a -> Sound d b
mapComputation ((ComputeSound Pulse -> ComputeSound Pulse)
 -> Sound d Pulse -> Sound d Pulse)
-> (ComputeSound Pulse -> ComputeSound Pulse)
-> Sound d Pulse
-> Sound d Pulse
forall a b. (a -> b) -> a -> b
$ (Vector S Pulse -> Vector r Pulse)
-> ComputeSound Pulse -> ComputeSound Pulse
forall r.
Load r Ix1 Pulse =>
(Vector S Pulse -> Vector r Pulse)
-> ComputeSound Pulse -> ComputeSound Pulse
mapSoundFromMemory Vector S Pulse -> Vector r Pulse
f

-- | Modify all samples of a sound so that you can look into the past and future
-- of a sound (e.g. IIR filter).
modifyWholeSoundST :: (M.Vector M.S Pulse -> M.MVector M.RealWorld M.S Pulse -> ST M.RealWorld ()) -> Sound d Pulse -> Sound d Pulse
modifyWholeSoundST :: forall (d :: SoundDuration).
(Vector S Pulse -> MVector RealWorld S Pulse -> ST RealWorld ())
-> Sound d Pulse -> Sound d Pulse
modifyWholeSoundST Vector S Pulse -> MVector RealWorld S Pulse -> ST RealWorld ()
f = (ComputeSound Pulse -> ComputeSound Pulse)
-> Sound d Pulse -> Sound d Pulse
forall a b (d :: SoundDuration).
(ComputeSound a -> ComputeSound b) -> Sound d a -> Sound d b
mapComputation ((ComputeSound Pulse -> ComputeSound Pulse)
 -> Sound d Pulse -> Sound d Pulse)
-> (ComputeSound Pulse -> ComputeSound Pulse)
-> Sound d Pulse
-> Sound d Pulse
forall a b. (a -> b) -> a -> b
$ (Vector S Pulse -> MVector RealWorld S Pulse -> IO ())
-> ComputeSound Pulse -> ComputeSound Pulse
mapSoundFromMemoryIO ((Vector S Pulse -> MVector RealWorld S Pulse -> IO ())
 -> ComputeSound Pulse -> ComputeSound Pulse)
-> (Vector S Pulse -> MVector RealWorld S Pulse -> IO ())
-> ComputeSound Pulse
-> ComputeSound Pulse
forall a b. (a -> b) -> a -> b
$ (ST RealWorld () -> IO ())
-> (MVector RealWorld S Pulse -> ST RealWorld ())
-> MVector RealWorld S Pulse
-> IO ()
forall a b.
(a -> b)
-> (MVector RealWorld S Pulse -> a)
-> MVector RealWorld S Pulse
-> b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap ST RealWorld () -> IO ()
forall a. ST RealWorld a -> IO a
stToIO ((MVector RealWorld S Pulse -> ST RealWorld ())
 -> MVector RealWorld S Pulse -> IO ())
-> (Vector S Pulse -> MVector RealWorld S Pulse -> ST RealWorld ())
-> Vector S Pulse
-> MVector RealWorld S Pulse
-> IO ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Vector S Pulse -> MVector RealWorld S Pulse -> ST RealWorld ()
f

-- | Access the sample rate of an infinite sound
withSamplingInfo :: (SamplingInfo -> Sound d a) -> Sound I a
withSamplingInfo :: forall (d :: SoundDuration) a.
(SamplingInfo -> Sound d a) -> Sound 'I a
withSamplingInfo SamplingInfo -> Sound d a
f = ComputeSound a -> Sound 'I a
forall a. ComputeSound a -> Sound 'I a
InfiniteSound (ComputeSound a -> Sound 'I a) -> ComputeSound a -> Sound 'I a
forall a b. (a -> b) -> a -> b
$ (SamplingInfo -> ComputeSound a) -> ComputeSound a
forall a. (SamplingInfo -> ComputeSound a) -> ComputeSound a
withSamplingInfoCS (Sound d a -> ComputeSound a
forall (d :: SoundDuration) a. Sound d a -> ComputeSound a
getCS (Sound d a -> ComputeSound a)
-> (SamplingInfo -> Sound d a) -> SamplingInfo -> ComputeSound a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. SamplingInfo -> Sound d a
f)

-- | Access the samples of a sound.
--
-- The pulse version is slightly faster since you get a storable vector
withSampledSoundPulse :: Sound T Pulse -> (M.Vector M.S Pulse -> Sound I a) -> Sound I a
withSampledSoundPulse :: forall a.
Sound 'T Pulse -> (Vector S Pulse -> Sound 'I a) -> Sound 'I a
withSampledSoundPulse (TimedSound Duration
duration ComputeSound Pulse
cs) = ComputeSound a -> Sound 'I a
forall a. ComputeSound a -> Sound 'I a
InfiniteSound (ComputeSound a -> Sound 'I a)
-> ((Vector S Pulse -> Sound 'I a) -> ComputeSound a)
-> (Vector S Pulse -> Sound 'I a)
-> Sound 'I a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Duration
-> ComputeSound Pulse
-> (Vector S Pulse -> ComputeSound a)
-> ComputeSound a
forall a.
Duration
-> ComputeSound Pulse
-> (Vector S Pulse -> ComputeSound a)
-> ComputeSound a
withSampledSoundPulseCS Duration
duration ComputeSound Pulse
cs ((Vector S Pulse -> ComputeSound a) -> ComputeSound a)
-> ((Vector S Pulse -> Sound 'I a)
    -> Vector S Pulse -> ComputeSound a)
-> (Vector S Pulse -> Sound 'I a)
-> ComputeSound a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Sound 'I a -> ComputeSound a)
-> (Vector S Pulse -> Sound 'I a)
-> Vector S Pulse
-> ComputeSound a
forall a b.
(a -> b) -> (Vector S Pulse -> a) -> Vector S Pulse -> b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap Sound 'I a -> ComputeSound a
forall (d :: SoundDuration) a. Sound d a -> ComputeSound a
getCS

-- | Access the samples of a sound.
withSampledSound :: Sound T a -> (M.Vector M.D a -> Sound I b) -> Sound I b
withSampledSound :: forall a b. Sound 'T a -> (Vector D a -> Sound 'I b) -> Sound 'I b
withSampledSound (TimedSound Duration
duration ComputeSound a
cs) = ComputeSound b -> Sound 'I b
forall a. ComputeSound a -> Sound 'I a
InfiniteSound (ComputeSound b -> Sound 'I b)
-> ((Vector D a -> Sound 'I b) -> ComputeSound b)
-> (Vector D a -> Sound 'I b)
-> Sound 'I b
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Duration
-> ComputeSound a
-> (Vector D a -> ComputeSound b)
-> ComputeSound b
forall a b.
Duration
-> ComputeSound a
-> (Vector D a -> ComputeSound b)
-> ComputeSound b
withSampledSoundCS Duration
duration ComputeSound a
cs ((Vector D a -> ComputeSound b) -> ComputeSound b)
-> ((Vector D a -> Sound 'I b) -> Vector D a -> ComputeSound b)
-> (Vector D a -> Sound 'I b)
-> ComputeSound b
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Sound 'I b -> ComputeSound b)
-> (Vector D a -> Sound 'I b) -> Vector D a -> ComputeSound b
forall a b. (a -> b) -> (Vector D a -> a) -> Vector D a -> b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap Sound 'I b -> ComputeSound b
forall (d :: SoundDuration) a. Sound d a -> ComputeSound a
getCS

-- | Calculate sound samples based on their index.
-- Take a look at @LambdaSound.Create@ for other creation functions.
makeSound :: (SamplingInfo -> Int -> a) -> Sound I a
makeSound :: forall a. (SamplingInfo -> Ix1 -> a) -> Sound 'I a
makeSound SamplingInfo -> Ix1 -> a
f = ComputeSound a -> Sound 'I a
forall a. ComputeSound a -> Sound 'I a
InfiniteSound (ComputeSound a -> Sound 'I a) -> ComputeSound a -> Sound 'I a
forall a b. (a -> b) -> a -> b
$ (SamplingInfo -> Ix1 -> a) -> ComputeSound a
forall a. (SamplingInfo -> Ix1 -> a) -> ComputeSound a
makeWithIndexFunction SamplingInfo -> Ix1 -> a
f

-- | Calculate the samples of the sound as one vector
-- Take a look at @LambdaSound.Create@ for other creation functions.
makeSoundVector :: (SamplingInfo -> M.Vector M.D a) -> Sound I a
makeSoundVector :: forall a. (SamplingInfo -> Vector D a) -> Sound 'I a
makeSoundVector SamplingInfo -> Vector D a
f = ComputeSound a -> Sound 'I a
forall a. ComputeSound a -> Sound 'I a
InfiniteSound (ComputeSound a -> Sound 'I a) -> ComputeSound a -> Sound 'I a
forall a b. (a -> b) -> a -> b
$ (SamplingInfo -> Vector D a) -> ComputeSound a
forall a. (SamplingInfo -> Vector D a) -> ComputeSound a
makeDelayedResult SamplingInfo -> Vector D a
f

-- | Embed an IO calculation when generating an infinite sound.
--
-- This IO action will be run each time the sound is used.
embedIO :: IO (Sound d a) -> Sound I a
embedIO :: forall (d :: SoundDuration) a. IO (Sound d a) -> Sound 'I a
embedIO IO (Sound d a)
ioSound = ComputeSound a -> Sound 'I a
forall a. ComputeSound a -> Sound 'I a
InfiniteSound (ComputeSound a -> Sound 'I a) -> ComputeSound a -> Sound 'I a
forall a b. (a -> b) -> a -> b
$ IO (ComputeSound a) -> ComputeSound a
forall a. IO (ComputeSound a) -> ComputeSound a
embedIOCS (IO (ComputeSound a) -> ComputeSound a)
-> IO (ComputeSound a) -> ComputeSound a
forall a b. (a -> b) -> a -> b
$ Sound d a -> ComputeSound a
forall (d :: SoundDuration) a. Sound d a -> ComputeSound a
getCS (Sound d a -> ComputeSound a)
-> IO (Sound d a) -> IO (ComputeSound a)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> IO (Sound d a)
ioSound

-- | Embed an IO calculation lazily when generating an infinite sound.
--
-- This IO action will not necessarily run each time the sound is used due to memoization.
-- The IO action will run at least once and at most as often as the sound occurs.
embedIOLazily :: IO (Sound d a) -> Sound I a
embedIOLazily :: forall (d :: SoundDuration) a. IO (Sound d a) -> Sound 'I a
embedIOLazily IO (Sound d a)
ioSound = ComputeSound a -> Sound 'I a
forall a. ComputeSound a -> Sound 'I a
InfiniteSound (ComputeSound a -> Sound 'I a) -> ComputeSound a -> Sound 'I a
forall a b. (a -> b) -> a -> b
$ IO (ComputeSound a) -> ComputeSound a
forall a. IO (ComputeSound a) -> ComputeSound a
embedIOLazilyCS (IO (ComputeSound a) -> ComputeSound a)
-> IO (ComputeSound a) -> ComputeSound a
forall a b. (a -> b) -> a -> b
$ Sound d a -> ComputeSound a
forall (d :: SoundDuration) a. Sound d a -> ComputeSound a
getCS (Sound d a -> ComputeSound a)
-> IO (Sound d a) -> IO (ComputeSound a)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> IO (Sound d a)
ioSound