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) -----------------------------------------------------------