packages feed

hsc3-auditor-0.11: Sound/SC3/Auditor.hs

-- | Auditor functions common to all sample libraries.
module Sound.SC3.Auditor (OCTPC,ST,CHD,DER,AMP,DUR,NC,INDEX
                         ,P,PP,SAMPLE_LOADER
                         ,au_load_instr
                         ,pp_audition
                         ,pp_duration,pp_indices
                         ,pp_osc,pp_osc_score) where

import Data.List
import qualified Music.Theory.Pitch as T {- hmt -}
import Sound.OpenSoundControl {- hosc -}
import Sound.SC3 {- hsc3 -}

-- | Real number
type R = Double

-- | (Octave,Pitch-class) pair
type OCTPC = (T.Octave,T.PitchClass)

-- | Amplitude
type AMP = R

-- | Index
type INDEX = Int

-- | Number of channels
type NC = Int

-- | Chord
type CHD a = [(a,AMP)]

-- | Duration
type DUR = R

-- | Start time
type ST = R

-- | (Start-time,Chord) pair
type P a = (ST,CHD a)

-- | Derivation function from 'CHD' element to 'INDEX'.
type DER a = a -> INDEX

-- | Set of 'P' and associated 'DER' function.
type PP a = (DER a,[P a])

-- | Function to generate the set of 'OSC' commands required to load
-- the set of 'INDEX'ed files.
type SAMPLE_LOADER = [INDEX] -> [OSC]

-- | Start time of last 'P' at 'PP'.
pp_duration :: PP a -> DUR
pp_duration = fst . last . snd

-- | The set of 'INDEX' referenced to by 'PP'.
pp_indices :: PP a -> [INDEX]
pp_indices (f,x) =
    let g = nub . sort . concatMap (map (f . fst) . snd)
    in map fromIntegral (g x)

chd_osc :: DER a -> CHD a -> [OSC]
chd_osc der xs = do
  let ns = map (fromIntegral . der . fst) xs
      as = map snd xs
      f i a = s_new "s" (-1) AddToTail 1 [("b", i),("a",a)]
  zipWith f ns as

p_osc :: DER a -> P a -> OSC
p_osc f (t,c) = bundle (NTPr t) (chd_osc f c)

-- | Generate set of 'OSC' given 'NC', 'SAMPLE_LOADER' and 'PP'.
pp_osc :: NC -> SAMPLE_LOADER -> PP a -> [OSC]
pp_osc nc ld pp =
    let b = bundle
        ix = pp_indices pp
        group_zero = g_new [(1, AddToTail, 0)]
        sc_init = let h = b (NTPr 0) [group_zero,instr_osc nc]
                  in h : map (b (NTPr 0) . return) (ld ix)
        sc_end = [b (NTPr (pp_duration pp + 12)) [g_freeAll [1]]]
        (der,x) = pp
  in sc_init ++ map (p_osc der) x ++ sc_end

-- | Variant of 'pp_osc' that writes @NRT@ score to named file using
-- 'writeNRT'.
pp_osc_score :: FilePath -> NC -> SAMPLE_LOADER -> PP a -> IO ()
pp_osc_score nm nc ld = writeNRT nm . pp_osc nc ld

-- * Instrument

instr_osc :: NC -> OSC
instr_osc nc = d_recv (synthdef "s" (smplr nc))

smplr :: NC -> UGen
smplr nc =
    let b = control KR "b" 0 -- buffer
        a = control KR "a" 1 -- amplitude
        o = control KR "o" 0 -- output channel
        b_d = bufDur KR b
        b_r = bufRateScale KR b
        c = envCoord [(0,1),(1,1)] b_d 1 EnvLin
        e = envGen KR 1 a 0 1 RemoveSynth c
    in out o (playBuf nc AR b b_r 1 0 NoLoop DoNothing * e)

-- * Audition

-- | Load sample playback instrument to @scsynth@ at 'Transport'.
au_load_instr :: Transport t => NC -> t -> IO ()
au_load_instr nc fd = do
  _ <- async fd (instr_osc nc)
  return ()

au_chd :: (Transport t) => t -> DER a -> (CHD a,DUR) -> IO ()
au_chd fd der (c,d) = do
  putStrLn ("au_chd: " ++ show d)
  mapM_ (send fd) (chd_osc der c)
  pauseThread d

d_dx :: [(ST,a)] -> [(a,DUR)]
d_dx xs =
    let (t,x) = unzip xs
    in zip x (zipWith (-) (drop 1 t) t ++ [0])

-- | Audition 'PP' at @scsynth@ instance at 'Transport'.
pp_audition :: (Transport t) => PP a -> t -> IO ()
pp_audition (der,pp) fd = mapM_ (au_chd fd der) (d_dx pp)