lambdasound-1.0.0: src/LambdaSound/Create.hs
module LambdaSound.Create
( -- *** Basic sounds
time,
progress,
sampleIndex,
constant,
silence,
-- *** Iterating
iterateSound,
iterateSoundPulse,
-- *** Unfolding
unfoldlSound,
unfoldlSoundPulse,
unfoldrSound,
unfoldrSoundPulse,
iUnfoldlSound,
iUnfoldlSoundPulse,
iUnfoldrSound,
iUnfoldrSoundPulse,
)
where
import Data.Coerce (coerce)
import Data.Massiv.Array qualified as M
import LambdaSound.Sound
-- | A 'Sound' with @0@ volume
silence :: Sound I Pulse
silence = constant 0
-- | A constant 'Sound'
constant :: a -> Sound I a
constant a = makeSound $ const (const a)
-- | Iterate over the samples to create the sound.
--
-- The 'Pulse' version is faster then the non-'Pulse' version
iterateSoundPulse :: (Pulse -> Pulse) -> Pulse -> Sound I Pulse
iterateSoundPulse f s = fillWholeSound $ \si ->
M.iterateN (M.Sz1 si.samples) f s
-- | Iterate over the samples to create the sound.
iterateSound :: (a -> a) -> a -> Sound I a
iterateSound f s = makeSoundVector $ \si ->
M.delay $ M.compute @M.B $ M.iterateN (M.Sz1 si.samples) f s
-- | Unfold the samples of a sound from the start to the end
--
-- The 'Pulse' version is faster then the non-'Pulse' version
unfoldlSoundPulse :: (s -> (s, Pulse)) -> s -> Sound I Pulse
unfoldlSoundPulse f s = fillWholeSound $ \si ->
M.unfoldlS_ (M.Sz1 si.samples) f s
-- | Unfold the samples of a sound from the start to the end
unfoldlSound :: (s -> (s, a)) -> s -> Sound I a
unfoldlSound f s = makeSoundVector $ \si ->
M.delay $ M.compute @M.B $ M.unfoldlS_ (M.Sz1 si.samples) f s
-- | Unfold the samples of a sound from the end to start
--
-- The 'Pulse' version is faster then the non-'Pulse' version
unfoldrSoundPulse :: (s -> (Pulse, s)) -> s -> Sound I Pulse
unfoldrSoundPulse f s = fillWholeSound $ \si ->
M.unfoldrS_ (M.Sz1 si.samples) f s
-- | Unfold the samples of a sound from the end to start
unfoldrSound :: (s -> (a, s)) -> s -> Sound I a
unfoldrSound f s = makeSoundVector $ \si ->
M.delay $ M.compute @M.B $ M.unfoldrS_ (M.Sz1 si.samples) f s
-- | Unfold the samples of a sound from the start to the end with the index starting at 0
--
-- The 'Pulse' version is faster then the non-'Pulse' version
iUnfoldlSoundPulse :: (Int -> s -> (s, Pulse)) -> s -> Sound I Pulse
iUnfoldlSoundPulse f s = fillWholeSound $ \si ->
M.iunfoldlS_ (M.Sz1 si.samples) f s
-- | Unfold the samples of a sound from the start to the end with the index starting at 0
iUnfoldlSound :: (Int -> s -> (s, a)) -> s -> Sound I a
iUnfoldlSound f s = makeSoundVector $ \si ->
M.delay $ M.compute @M.B $ M.iunfoldlS_ (M.Sz1 si.samples) f s
-- | Unfold the samples of a sound from the end to the start with the index starting at 0
--
-- The 'Pulse' version is faster then the non-'Pulse' version
iUnfoldrSoundPulse :: (s -> Int -> (Pulse, s)) -> s -> Sound I Pulse
iUnfoldrSoundPulse f s = fillWholeSound $ \si ->
M.iunfoldrS_ (M.Sz1 si.samples) f s
-- | Unfold the samples of a sound from the end to the start with the index starting at 0
iUnfoldrSound :: (s -> Int -> (a, s)) -> s -> Sound I a
iUnfoldrSound f s = makeSoundVector $ \si ->
M.delay $ M.compute @M.B $ M.iunfoldrS_ (M.Sz1 si.samples) f s
-- | Get the time for each sample which can be used for sinus wave calculations (e.g. 'sineWave')
time :: Sound I Time
time = makeSound $ \si index ->
coerce $ fromIntegral index * si.period
-- | Get the 'Progress' of a 'Sound'.
-- 'Progress' of '0' means that the sound has just started.
-- 'Progress' of '1' means that the sound has finished.
-- 'Progress' greater than '1' or smaller than '0' is invalid.
progress :: Sound I Progress
progress = makeSound $ \si index ->
fromIntegral index / fromIntegral si.samples
-- | Tells you the sample index for each sample
sampleIndex :: Sound I Int
sampleIndex = makeSound (const id)