module Sound.Hommage.Filter ( -- * Filters lowpass , highpass , bandpass , stretchpass , morphpass -- , vocoder -- , lowpassrect -- * FilterSpec -- , specfilter , FilterSpec , shiftFilterSpec -- * FilterSpec and Lists , filterSpecToList , filterSpecsToLists , interpolFilterLists -- * Other , ffreq , ffreqi , average512 -- * Filterfunctions , lowpassFS , highpassFS , bandpassFS , lowp0FS , lowp1FS , bandp0FS , bandp1FS , highp0FS , highp1FS ) where --import Sound.Hommage.DFTFilter import Data.Complex --import Sound.Hommage.FFT --------------------------------------------------------------------------------------------------- lowpass :: [Double] -> [Double] -> [Double] lowpass s c = concat $ map filterSpecToList $ zipWith lowpassFS (average512 s) (average512 c) highpass :: [Double] -> [Double] -> [Double] highpass s c = concat $ map filterSpecToList $ zipWith highpassFS (average512 s) (average512 c) bandpass :: [Double] -> [Double] -> [Double] -> [Double] bandpass r s c = concat $ map filterSpecToList $ zipWith3 bandpassFS (average512 r) (average512 s) (average512 c) stretchpass:: FilterSpec -> [Double] -> [Double] stretchpass fs c = concat $ map filterSpecToList $ map (flip shiftFilterSpec fs) $ map (2.0**) $ average512 c morphpass:: FilterSpec -> FilterSpec -> [Double] -> [Double] morphpass f1 f2 c = let l1 = filterSpecToList f1 l2 = filterSpecToList f2 in concat $ map (interpolFilterLists l1 l2) $ average512 c --------------------------------------------------------------------------------------------------- {- -- | first argument is width of filter, second is cutoff lowpassfilter :: [Double] -> [Double] -> [Double] -> [Double] lowpassfilter s c = lowpassrect :: [Double] -> [Double] -> [Double] -> [Double] lowpassrect s c = let i = ([]:) $ map filterSpecToList $ zipWith lowpassFS (average512 s) (average512 c) in rect_filter' 9 i {- specfilterFFT :: [FilterSpec] -> [Double] -> [Double] specfilterFFT fs = fftt 8 (concat . zipWith fun fs ) fun :: FilterSpec -> [Complex Double] -> [Complex Double] fun fs ((c0 :+ _) : cs) = zipWith f ((c0 :+ 0) : cs) (filterSpecToList fs) where f (x:+y) v = (x * v) :+ (y * v) -} -- | first argument is width of filter, second is cutoff highpassfilter :: [Double] -> [Double] -> [Double] -> [Double] highpassfilter s c = let i = concat $ map filterSpecToList $ zipWith highpassFS (average512 s) (average512 c) in dftfilter i -- | first argument is width of filter, second is slope, third is cutoff bandpassfilter :: [Double] -> [Double] -> [Double] -> [Double] -> [Double] bandpassfilter r s c = let i = concat $ map filterSpecToList $ zipWith3 bandpassFS (average512 r) (average512 s) (average512 c) in dftfilter i stretchfilter :: FilterSpec -> [Double] -> [Double] -> [Double] stretchfilter fs c = let i = concat $ map filterSpecToList $ map (flip shiftFilterSpec fs) $ map (2.0**) $ average512 c in dftfilter i morphfilter :: FilterSpec -> FilterSpec -> [Double] -> [Double] -> [Double] morphfilter f1 f2 c = let l1 = filterSpecToList f1 l2 = filterSpecToList f2 i = concat $ map (interpolFilterLists l1 l2) $ average512 c in dftfilter i --------------------------------------------------------------------------------------------------- specfilter :: [FilterSpec] -> [Double] -> [Double] specfilter fs = let i = concat $ map filterSpecToList fs in dftfilter i -} --------------------------------------------------------------------------------------------------- -- | for filter coefficient number: (0.0 .. 1.0) -> (1.0 .. 512.0) ffreq :: Double -> Double ffreq k = r where k' = abs k r | k' > 1.0 = 512.0 | otherwise = 2 ** (9.0 * k') -- | floor of 'ffreq' ffreqi :: Double -> Int ffreqi = floor . ffreq -- | the resulting list is 1 \/ 512 as long as the input list. -- 512 elements are read and their average is the next output value. average512 :: [Double] -> [Double] average512 = loop 512 0.0 where loop 0 s xs = (s / 512.0) : loop 512 0.0 xs loop k s (x:xs) = loop (k-1) (s+x) xs loop _ _ _ = [] --mkFilterFun :: (Double -> FilterSpec) -> (Double, Double) -> FilterFun Double --mkFilterFun filt (cutoff, fmod) = withFilterEnv . mkFilterEnv . filt . (+cutoff) . (*fmod) --------------------------------------------------------------------------------------------------- -- | Filtering starts at coeff nr 0 and value 0.0 (constant coeff is always zero). -- The elements in FilterSpec define the next value and how many -- coeffs it takes to reach this value. type FilterSpec = [(Int, Double)] -- | 0..1: lower, 1..: higher shiftFilterSpec :: Double -> FilterSpec -> FilterSpec shiftFilterSpec d fs = map f fs where f (n,v) = (round (d * fromIntegral n), v) -- | Converting a FilterSpec to a list of 512 Doubles filterSpecToList :: FilterSpec -> [Double] filterSpecToList xs = take 512 $ loop 0.0 xs where loop c [] = repeat c loop c ((n,d): ls) = let f = (d-c) / fromIntegral n in take n (iterate (+f) c) ++ loop d ls -- | Converting and interpolating a sequence of FilterSpecs to a list of lists. The first elemet of the -- tuple, an Int, describes how many lists it takes to reach the given FilterSpec. filterSpecsToLists :: [(Int, FilterSpec)] -> [[Double]] filterSpecsToLists = loop (filterSpecToList []) where loop l [] = [] loop l ((n,f):xs) = let f' = filterSpecToList f in fun n l f' ++ loop f' xs fun n f1 f2 = let d = 1.0 / fromIntegral n in take n $ map (interpolFilterLists f1 f2) $ iterate (+d) 0.0 interpolFilterLists :: [Double] -> [Double] -> Double -> [Double] interpolFilterLists f1 f2 n | n >= 1.0 = f2 | n <= 0.0 = f1 | otherwise = let n' = 1.0 - n in zipWith (\a b -> a * n' + b * n) f1 f2 --------------------------------------------------------------------------------------------------- lowpassFS :: Double -> Double -> FilterSpec lowpassFS d c = [(1,1.0), (round fd, 1.0), (round (fd * abs d), 0.0)] where fd = ffreq c highpassFS :: Double -> Double -> FilterSpec highpassFS d c = [(round fd, 0.0), (round (fd * abs d), 1.0)] where fd = ffreq c -- | range, curve, cutoff bandpassFS :: Double -- ^ width of freq-window -> Double -- -> Double -- ^ cutoff -> FilterSpec bandpassFS r s f = [(l1, 0.0), (l2, 1.0), (l3, 1.0), (l4, 0.0)] where m1 = abs r + 1 m2 = m1 + abs s a = ffreqi (f / m2) b = ffreqi (f / m1) c = ffreqi (f * m1) d = ffreqi (f * m2) l1 = a l2 = b - a l3 = c - b l4 = d - c bandpassFS' :: Double -- ^ width of freq-window -> Double -- -> Double -- ^ cutoff -> FilterSpec bandpassFS' r s f = [(1 + round a, 0.0), (1 + round b, 1.0), (1 + round c, 1.0), (1 + round d, 0.0)] where r' = 1.0 + abs r s' = 1.0 + abs s fd = ffreq f a = fd b = fd * s' - a c = b * r' - b d = c * s' - c --------------------------------------------------------------------------------------------------- lowp0FS :: Double -> FilterSpec lowp0FS f = [(0, 1.0), (fr, 1.0), (1, 0.0)] where fr = ffreqi f lowp1FS :: Double -> FilterSpec lowp1FS f = [(0, 1.0), (fr, 1.0), (fr, 0.0)] where fr = ffreqi f bandp0FS :: Double -> FilterSpec bandp0FS f = [(f0-1, 0.0), (f0, 1.0), (fr, 1.0), (1, 0.0)] where fr = ffreqi f f0 = fr - (div fr 2) + 1 bandp1FS :: Double -> FilterSpec bandp1FS f = [(fh, 0.0), (fh, 1.0), (fh, 0.0)] where fr = ffreqi f fh = div fr 2 highp0FS :: Double -> FilterSpec highp0FS f = [(fr, 0.0), (1, 1.0)] where fr = ffreqi f highp1FS :: Double -> FilterSpec highp1FS f = [(fh, 0.0), (fh, 1.0)] where fr = ffreqi f fh = div fr 2 --------------------------------------------------------------------------------------------------- {- -- | first argument is control signal vocoder :: [Double] -> [Double] -> [Double] vocoder xs ys = dftsynthese $ zipWith f (dftanalyse xs) (dftanalyse ys) where f x (a :+ b) = let z = magnitude x in (a*z :+ b*z) -} ---------------------------------------------------------------------------------------------------