hommage-0.0.5: Sound/Hommage/Filter.hs
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)
-}
---------------------------------------------------------------------------------------------------