import Control.Monad import Data.Function import Data.List import qualified Sound.Analysis.Meapsoft as M import Sound.OpenSoundControl import Sound.SC3 import System.Environment grain :: UGen -> UGen grain b = p * e where s = Control KR "start" 0.0 d = Control KR "dur" 1.0 g = Control KR "gain" 1.0 r = bufRateScale KR b q = bufSampleRate KR b z = envTrapezoid 0.95 0.5 d g e = envGen KR 1 1 0 1 RemoveSynth z p = playBuf 1 b r 1 (s * q) NoLoop DoNothing mk_grain :: (Transport t) => t -> Double -> Double -> IO () mk_grain fd s d = let xs = [ ("start", s) , ("dur", d) ] in send fd (s_new "grain" (-1) AddToTail 1 xs) tone :: UGen tone = p * e where f = Control KR "freq" 0.0 d = Control KR "dur" 1.0 g = Control KR "gain" 0.1 z = envTrapezoid 0.95 0.5 d g e = envGen KR 1 1 0 1 RemoveSynth z p = saw AR (MCE [f, f*2, f*3]) * (MCE [0.5, 0.2, 0.1]) mk_tone :: (Transport t) => t -> Double -> Double -> IO () mk_tone fd f d = let xs = [ ("freq", f) , ("dur", d) ] in send fd (s_new "tone" (-1) AddToTail 1 xs) -- (Temporal_Scalar, [Segments], [Freq]) type Spec = (Double, [(Double, Double)], [Double]) plyr :: Transport t => t -> Spec -> IO () plyr _ (_, [], _) = return () plyr fd (t, (s,d):xs, f:fs) = do mk_grain fd s d mk_tone fd f (d * t * 0.25) pauseThread (d * t) plyr fd (t, xs, fs) plyr _ _ = undefined run_grn :: FilePath -> FilePath -> (M.MEAP -> Spec) -> IO () run_grn sf ff rule = withSC3 g where g fd = do reset fd let g0 = out 0 (grain 10) g1 = out 0 tone async fd (b_allocRead 10 sf 0 0) async fd (d_recv (synthdef "grain" g0)) async fd (d_recv (synthdef "tone" g1)) (Right m) <- M.read_meap ff plyr fd (rule m) col :: String -> M.MEAP -> [Double] col n m = let f = M.required_feature n (M.features m) j = M.feature_column f in M.column_l m j freq_1 :: M.MEAP -> [Double] freq_1 = col "AvgFreqSimple" -- forwards rule_1 :: M.MEAP -> Spec rule_1 c = (0.75, M.segments_l c, freq_1 c) freq_2 :: M.MEAP -> [Double] freq_2 = col "AvgSpecCentroid" -- backwards rule_2 :: M.MEAP -> Spec rule_2 c = (0.5, reverse (M.segments_l c), reverse (freq_2 c)) gen_order_1 :: M.MEAP -> String -> [Int] gen_order_1 m f = let cs = zip [0..] (col f m) cs' = sortBy (compare `on` snd) cs in map fst cs' apply_order :: [Int] -> [a] -> [a] apply_order o xs = map (\i -> xs !! i) o srt_rule :: String -> (M.MEAP -> [Double]) -> M.MEAP -> Spec srt_rule n r m = let o = gen_order_1 m n s = apply_order o (M.segments_l m) f = apply_order o (r m) in (0.5, s, f) -- sorted by segment length (ascending) rule_3 :: M.MEAP -> Spec rule_3 = srt_rule "chunk_length" freq_1 -- sorted by frequency (ascending) rule_4 :: M.MEAP -> Spec rule_4 = srt_rule "AvgFreqSimple" freq_1 -- sorted by spectral centroid (ascending) rule_5 :: M.MEAP -> Spec rule_5 = srt_rule "AvgSpecCentroid" freq_2 -- sorted by spectral stability (ascending) rule_6 :: M.MEAP -> Spec rule_6 = srt_rule "SpectralStability" freq_2 gen_sel_1 :: M.MEAP -> String -> (Double -> Bool) -> [Int] gen_sel_1 m f p = let cs = zip [0..] (col f m) cs' = filter (p . snd) cs in map fst cs' sel_rule :: String -> (Double -> Bool) -> (M.MEAP -> [Double]) -> M.MEAP -> Spec sel_rule n p r m = let o = gen_sel_1 m n p s = apply_order o (M.segments_l m) f = apply_order o (r m) in (0.5, s, f) -- filtered by frequency (> 600) rule_7 :: M.MEAP -> Spec rule_7 = sel_rule "AvgFreqSimple" (> 600) freq_1 -- filtered by spectral centroid (> 1200) rule_8 :: M.MEAP -> Spec rule_8 = sel_rule "AvgSpecCentroid" (> 1200) freq_2 interleave :: [a] -> [a] -> [a] interleave [] b = b interleave a [] = a interleave (a:as) (b:bs) = a : b : interleave as bs -- interleaving of rules 4 & 5 rule_9 :: M.MEAP -> Spec rule_9 m = let (_, s4, f4) = rule_4 m (_, s5, f5) = rule_5 m in (0.75, interleave s4 s5, interleave f4 f5) reverse_spec :: Spec -> Spec reverse_spec (t, x, f) = (t, reverse x, reverse f) -- reverse of rule 9 rule_10 :: M.MEAP -> Spec rule_10 = reverse_spec . rule_9 scale_start_only :: Double -> Spec -> Spec scale_start_only n (t, x, f) = (t, map g x, f) where g (s, d) = (s * n, d) -- rule 10 with start times compressed but durations kept equal rule_11 :: M.MEAP -> Spec rule_11 = (scale_start_only 0.5) . rule_10 scale_dur_only :: Double -> Spec -> Spec scale_dur_only n (t, x, f) = (t, map g x, f) where g (s, d) = (s, d * n) -- rule 7 with durations compressed but start times retained rule_12 :: M.MEAP -> Spec rule_12 = (scale_dur_only 0.5) . rule_7 fix_dur :: Double -> Spec -> Spec fix_dur n (t, x, f) = (t, map g x, f) where g (s, _) = (s, n) -- rule 7 with durations fixed at 0.25 seconds rule_13 :: M.MEAP -> Spec rule_13 = (fix_dur 0.25) . rule_7 rules :: [M.MEAP -> Spec] rules = [ rule_1 , rule_2 , rule_3 , rule_4 , rule_5 , rule_6 , rule_7 , rule_8 , rule_9 , rule_10 , rule_11 , rule_12 , rule_13 ] main :: IO () main = do a <- getArgs unless (length a == 3) (error "audio-file feature-file rule-number") let [w_fn, f_fn, r] = a rn = read r - 1 unless (rn >= 0 && rn < length rules) (error "unknown rule") run_grn w_fn f_fn ( rules !! rn )