hommage-0.0.5: Sound/Hommage/Sound.hs
module Sound.Hommage.Sound
(
-- * Classes
(==>)
, (.=>)
, Sound (..)
, Effect (..)
, (<+>)
, (<*>)
-- * Sound Generators and Transformers
, WaveForm (..)
, playWaveForm
, Oscillator (..)
, ToFreq (..)
, ToFreqDyn (..)
, Noise (..)
, PlayWav (..)
, OscWav (..)
, PitchWav (..)
, ScratchWav (..)
, Filter (..)
, FilterFFT (..)
, Lowpass (..)
, Highpass (..)
, Bandpass (..)
, Morphfilter (..)
, Stretchfilter (..)
, Envelope (..)
, Amplifier (..)
, AddTo (..)
, Infinite (..)
, Delay (..)
, ToMono (..)
, Average (..)
, SampleAndHold (..)
, Compressor (..)
, Follow (..)
, Panorama (..)
-- , LowpassRect (..)
)
where
import Data.List
import Data.Ratio
--import Control.Monad.Reader
import Sound.Hommage.Signal
import Sound.Hommage.Envelope
import Sound.Hommage.Notation
import Sound.Hommage.Play
import Sound.Hommage.Osc
import Sound.Hommage.Filter
import Sound.Hommage.Sample
import Sound.Hommage.DFTFilter
import Sound.Hommage.FFT
-----------------------------------------------------------
(==>) :: (Sound a, Effect b) => a -> b -> Play Signal
v ==> e = play v >>= \s -> effect e >>= \f -> return (f s)
(<+>) :: (Sound a, Sound b) => a -> b -> Play Signal
a <+> b = play a >>= \s1 -> play b >>= \s2 -> return (mergeSignal s1 s2)
(<*>) :: (Sound a, Sound b) => a -> b -> Play Signal
a <*> b = play a >>= \s1 -> play b >>= \s2 -> return (multSignal s1 s2)
-----------------------------------------------------------
-- | Minimal complete definition: 'play'.
class Sound a where
play :: a -> Play Signal
playMono :: a -> Play [Mono]
playStereo :: a -> Play [Stereo]
playMono a = play a >>= return . signalToMono
playStereo a = play a >>= return . signalToStereo
instance Sound () where
play = const $ return (Mono [])
instance Sound (Play Signal) where
play = id
instance Sound (Play [Mono]) where
play a = a >>= return . Mono
instance Sound (Play [Stereo]) where
play a = a >>= return . Stereo
instance Sound Signal where
play = return
instance Sound [Mono] where
play = return . Mono
instance Sound [Stereo] where
play = return . Stereo
instance Sound Mono where
play = return . Mono . repeat
instance Sound Stereo where
play = return . Stereo . repeat
--instance Sound FilePath where
-- play = return . openWavSignal
instance Sound (Track Signal) where
play = playTrack
instance Sound (Track [Mono]) where
play = fmap Mono . playTrack
instance Sound (Track [Stereo]) where
play = fmap Stereo . playTrack
instance Sound Interpolate where
play i = getDur >>= \d -> return $ Mono $ toEnv i (absDur d)
-----------------------------------------------------------
class Effect a where
effect :: a -> Play (Signal -> Signal)
effectMono :: a -> Play ([Mono] -> [Mono])
effectStereo :: a -> Play ([Stereo] -> [Stereo])
effectMono a = effect a >>= \f -> return ( signalToMono . f . Mono )
effectStereo a = effect a >>= \f -> return ( signalToStereo . f . Stereo )
(.=>) :: (Effect a, Effect b) => a -> b -> Play (Signal -> Signal)
a .=> b = effect a >>= \fa -> effect b >>= \fb -> return (fb . fa)
instance Sound a => Effect (Play Signal -> a) where
effect f = PLAY $ \d e s -> unPlay (play $ f $ return s) d e
instance Sound a => Effect (Play [Mono] -> a) where
effect f = PLAY $ \d e s -> unPlay (play $ f $ return $ signalToMono s) d e
instance Sound a => Effect (Play [Stereo] -> a) where
effect f = PLAY $ \d e s -> unPlay (play $ f $ return $ signalToStereo s) d e
instance Effect (Play (Signal -> Signal)) where
effect = id
--instance Effect (Play Signal -> Play Signal) where
-- effect f = PLAY $ \d e s -> unPlay (f (return s)) d e
--instance Sound a => Effect (Signal -> a) where
-- effect f = PLAY $ \e d s -> unPlay (play $ f s) e d
instance Effect (Signal -> Signal) where
effect = return
instance Effect ([Mono] -> [Mono]) where
effect = return . liftSignal
effectMono = return
instance Effect ([Stereo] -> [Stereo]) where
effectStereo = return
effect f = return (Stereo . f . signalToStereo)
--instance Effect ([Mono] -> [Stereo]) where
-- effect f = return $ eitherSignal (Stereo . f) (Stereo . id) -- ???
--instance Effect ([Stereo] -> [Mono]) where
-- effect f = return $ eitherSignal (Mono . id) (Mono . f) -- ???
--instance Effect ([Mono] -> Signal) where
-- effect f = return $ eitherSignal f Stereo -- ???
--instance Effect ([Stereo] -> Signal) where
-- effect f = return $ eitherSignal Mono f -- ???
-----------------------------------------------------------
newtype PlayWav = PlayWav FilePath
instance Sound PlayWav where
play (PlayWav fp) = return $ openWavSignal fp
-----------------------------------------------------------
data Filter a = Filter a
instance Sound a => Effect (Filter a) where
effect (Filter a) = playMono a >>= \a' -> return $ liftSignal (dftfilter a')
data FilterFFT a = FilterFFT Int a
instance Sound a => Effect (FilterFFT a) where
effect (FilterFFT n a) = playMono a >>= \a' -> return $ liftSignal (ffttv n a')
-----------------------------------------------------------
-- | Width and cutoff.
data Lowpass width cutoff = Lowpass width cutoff
instance (Sound a, Sound b) => Sound (Lowpass a b) where
play (Lowpass a b) = playMono a >>= \a -> playMono b >>= \b -> return $ Mono (lowpass a b)
-----------------------------------------------------------
-- | Width and cutoff.
data Highpass width cutoff = Highpass width cutoff
instance (Sound a, Sound b) => Sound (Highpass a b) where
play (Highpass a b) = playMono a >>= \a -> playMono b >>= \b -> return $ Mono (highpass a b)
-----------------------------------------------------------
data Amplifier volume = Amplifier volume
instance Sound a => Effect (Amplifier a) where
effect (Amplifier a) = play a >>= return . multSignal
---------------------------------------------------------------------------------------------------
data Envelope = Envelope EnvMode EnvShape ADSR
deriving (Eq, Read, Show)
instance Sound Envelope where
play (Envelope em ec adsr) = getDur >>= return . Mono . playADSR em ec adsr . absDur
instance Sound [(Env, EnvLength)] where
play e = getDur >>= \d -> return $ Mono $ runEnv e (absDur d)
-----------------------------------------------------------
data AddTo summand = AddTo summand
instance Sound a => Effect (AddTo a) where
effect (AddTo a) = play a >>= \s -> return (mergeSignal s)
-----------------------------------------------------------
-- | The result will be infinite, with given offset.
data Infinite = Infinite Double
instance Effect Infinite where
effect (Infinite d) = return $ infiniteSignal d
-----------------------------------------------------------
data Noise = Noise
instance Sound Noise where
play _ = return $ Mono $ randomList (-1.0,1.0)
playStereo _ = return $ zipWith (:><:) (randomList (-1.0,1.0)) (randomList (-1.0,1.0))
-----------------------------------------------------------
-- | Turns pitch to frequency.
data ToFreq = ToFreq Double
instance Effect ToFreq where
effect (ToFreq d) = return $ liftSignal (map (noteToFrequency d))
data ToFreqDyn a = ToFreqDyn a
instance Sound a => Effect (ToFreqDyn a) where
effect (ToFreqDyn a) = playMono a >>= \s -> return $ liftSignal (zipWith noteToFrequency s)
-----------------------------------------------------------
data WaveForm = Sinus | Cosinus | Rect | Saw | Tri
deriving (Eq, Read, Show)
playWaveForm :: WaveForm -> [Double] -> [Double]
playWaveForm wf =
case wf of
Sinus -> sinus
Cosinus -> cosinus
Rect -> rect
Saw -> saw
Tri -> tri
instance Effect WaveForm where
effect wf = case wf of
Sinus -> return (liftSignal sinus)
Cosinus -> return (liftSignal cosinus)
Rect -> return (liftSignal rect)
Saw -> return (liftSignal saw)
Tri -> return (liftSignal tri)
-----------------------------------------------------------
data Oscillator = Oscillator WaveForm Double
instance Effect Oscillator where
effect (Oscillator wf d) = return $
(Mono . playWaveForm wf . map (adjustFrequency 1024 d) . signalToMono)
-----------------------------------------------------------
data OscWav = OscWav FilePath Double
instance Effect OscWav where
effect (OscWav fp d) = let w = signalToMono $ openWavSignal fp in
return (Mono . osc (cycle w) .
map (adjustFrequency (fromIntegral $ length w) d) .
signalToMono)
-----------------------------------------------------------
data PitchWav = PitchWav FilePath
instance Effect PitchWav where
effect (PitchWav fp) = return $ pitchWavSignal fp . signalToMono
-----------------------------------------------------------
data ScratchWav = ScratchWav FilePath
instance Effect ScratchWav where
effect (ScratchWav fp) = return $ scratchWavSignal fp . signalToMono
-----------------------------------------------------------
data Delay = AbsDelay Int -- ^ Absolute Delay
| RelDelay Dur -- ^ Relative Delay with respect to the current duration
instance Effect Delay where
effect (AbsDelay n) = return $ eitherSignal (\x -> Mono (replicate n 0.0 ++ x))
(\x -> Stereo (replicate n (0.0:><:0.0) ++ x))
effect (RelDelay d) = getDur >>= \dur -> let n = absDur (d * dur) in seq n $ return $
eitherSignal (\x -> Mono (replicate n 0.0 ++ x))
(\x -> Stereo (replicate n (0.0:><:0.0) ++ x))
-----------------------------------------------------------
data ToMono = ToMono
instance Effect ToMono where
effect ToMono = return $ Mono . signalToMono
-----------------------------------------------------------
data Average = Average Int
instance Effect Average where
effect (Average n) = return $ liftSignal (average n)
-----------------------------------------------------------
data Bandpass width slope cutoff = Bandpass width slope cutoff
instance (Sound a, Sound b, Sound c) => Sound (Bandpass a b c) where
play (Bandpass a b c) = do a' <- playMono a
b' <- playMono b
c' <- playMono c
return $ Mono (bandpass a' b' c')
-----------------------------------------------------------
data SampleAndHold trigger = SampleAndHold trigger
instance Sound a => Effect (SampleAndHold a) where
effect (SampleAndHold a) = playMono a >>= \a' -> return $ liftSignal (sampleAndHold 0 a')
-----------------------------------------------------------
data Compressor a = Compressor a
instance Sound a => Effect (Compressor a) where
effect (Compressor a) = playMono a >>= return . liftSignal . zipWith compress
-----------------------------------------------------------
data Morphfilter cutoff = Morphfilter FilterSpec FilterSpec cutoff
instance Sound a => Sound (Morphfilter a) where
play (Morphfilter fs1 fs2 a) = playMono a >>= \a' ->
return $ Mono (morphpass fs1 fs2 a')
-----------------------------------------------------------
data Stretchfilter cutoff = Stretchfilter FilterSpec cutoff
instance Sound a => Sound (Stretchfilter a) where
play (Stretchfilter fs a) = playMono a >>= \a' ->
return $ Mono (stretchpass fs a')
-----------------------------------------------------------
data Follow a = Follow Double a
instance Sound a => Effect (Follow a) where
effect (Follow d a) = playMono a >>= \a' ->
return $ liftSignal (follow d a')
-----------------------------------------------------------
data Panorama balance = Panorama balance
instance Sound a => Effect (Panorama a) where
effect (Panorama a) = playMono a >>= \a' ->
return $ eitherSignal (Stereo . zipWith balance a' . map monoToStereo)
(Stereo . zipWith balance a')
-----------------------------------------------------------
-- | Width and cutoff.
--data LowpassRect width cutoff = LowpassRect width cutoff
--instance (Sound a, Sound b) => Effect (LowpassRect a b) where
-- effect (LowpassRect a b) = playMono a >>= \a -> playMono b >>= \b -> return $ liftSignal (lowpassrect a b)
-----------------------------------------------------------