hsc3-lang-0.15: Sound/SC3/Lang/Pattern/P/Event.hs
-- | @sclang@ event pattern functions.
--
-- SC3 /event/ patterns: `padd` (Padd), `pbind` (Pbind), `pkey`
-- (Pkey), `pmono` (Pmono), `pmul` (Pmul), `ppar` (Ppar), `pstretch`
-- (Pstretch), `ptpar` (Ptpar). `pedit`, `pinstr`, `pmce2`, `psynth`,
-- `punion`.
module Sound.SC3.Lang.Pattern.P.Event where
import qualified Data.Foldable as F {- base -}
import Data.Maybe {- base -}
import Data.Monoid {- base -}
import Sound.OSC {- hsc3 -}
import Sound.SC3 {- hsc3 -}
import Sound.SC3.Lang.Control.Duration
import Sound.SC3.Lang.Control.Event
import Sound.SC3.Lang.Control.Instrument
import Sound.SC3.Lang.Core
import Sound.SC3.Lang.Pattern.P
-- * SC3 Event Patterns
-- | NewType for event patterns.
newtype P_Event = P_Event {p_Event :: P Event}
-- | 'P_Event' is audible, 'P' 'Event' could be as well but it'd be an orphan instance.
instance Audible P_Event where
play_at _ = e_play . Event_Seq . unP . p_Event
pplay :: Transport m => P Event -> m ()
pplay = play . P_Event
-- | 'audition' of 'P_Event'.
paudition :: P Event -> IO ()
paudition = audition . P_Event
-- | Synonym for ('Key','P Field').
type P_Bind = (Key,P Field)
{-|
Padd. Add a value to an existing key, or set the key if it doesn't exist.
> > p = Padd(\freq,801,Pbind(\freq,Pseq([100],1)));
> > p.asStream.all(()) == [('freq':901)]
> let p = padd (K_freq,801) (pbind [(K_freq,return 100)])
> in p == pbind [(K_freq,return 901)]
> > Padd(\freq,Pseq([401,801],2),Pbind(\freq,100)).play
> paudition (padd (K_freq,pseq [401,801] 2) (pbind [(K_freq,100)]))
> let {d = pseq [pshuf 'α' [-7,-3,0,2,4,7] 2
> ,pseq [0,1,2,3,4,5,6,7] 1] 1
> ;p = pbind [(K_dur,0.15),(K_degree,d)]
> ;t n = padd (K_mtranspose,n) p}
> in paudition (pseq [p,t 1,t 2] inf)
-}
padd :: P_Bind -> P Event -> P Event
padd (k,p) = pzipWith (\i j -> e_edit k 0 (+ i) j) p
{-| Pbind. SC3 pattern to assign keys to a set of 'Field' patterns
making an 'Event' pattern.
Each input pattern is assigned to key in the resulting event pattern.
There are a set of reserved keys that have particular roles in the
pattern library.
> > p = Pbind(\x,Pseq([1,2,3],1),\y,Pseed(Pn(100,1),Prand([4,5,6],inf)));
> > p.asStream.all(()) == [('y':4,'x':1),('y':6,'x':2),('y':4,'x':3)]
> let p = pbind [(K_param "x",prand 'α' [100,300,200] inf)
> ,(K_param "y",pseq [1,2,3] 1)]
> in pkey (K_param "x") p == toP [200,200,300]
'K_param' can be elided if /OverloadedStrings/ are in place.
> :set -XOverloadedStrings
> ptake 2 (pbind [("x",pwhitei 'α' 0 9 inf)
> ,("y",pseq [1,2,3] inf)])
'Event's implement variations on the @SC3@ 'Dur' and
'Sound.SC3.Lang.Control.Pitch.Pitch' models.
> > Pbind(\freq,Prand([300,500,231.2,399.2],inf),
> > \dur,0.1).play;
> paudition (pbind [(K_freq,prand 'α' [300,500,231.2,399.2] inf)
> ,(K_dur,0.1)])
> > Pbind(\freq, Prand([300,500,231.2,399.2],inf),
> > \dur,Prand([0.1,0.3],inf)).play;
> paudition (pbind [(K_freq,prand 'α' [300,500,231.2,399.2] inf)
> ,(K_dur,prand 'β' [0.1,0.3] inf)])
> > Pbind(\freq,Prand([1,1.2,2,2.5,3,4],inf) * 200,
> > \dur,0.1).play;
> paudition (pbind [(K_freq,prand 'α' [1,1.2,2,2.5,3,4] inf * 200)
> ,(K_dur,0.1)])
> paudition (pbind [(K_freq,pseq [440,550,660,770] 2)
> ,(K_dur,pseq [0.1,0.15,0.1] inf)
> ,(K_amp,pseq [0.1,0.05] inf)
> ,(K_param "pan",pseq [-1,0,1] inf)])
A finite binding stops the `Event` pattern.
> > Pbind(\freq,Prand([300,500,231.2,399.2],inf),
> > \dur,Pseq([0.1,0.2],3)).play;
> paudition (pbind [(K_freq,prand 'α' [300,500,231.2,399.2] inf)
> ,(K_dur,pseq [0.1,0.2] 3)])
> > Pbind(\freq,Prand([300,500,231.2,399.2],inf),
> > \dur,Prand([0.1,0.3],inf)).play
All infinite inputs:
> paudition (pbind [(K_freq,prand 'α' [300,500,231.2,399.2] inf)
> ,(K_dur,prand 'β' [0.1,0.3] inf)])
Implicit /field/ patterns is this context are infinite.
> paudition (pbind [(K_freq,prand 'α' [1,1.2,2,2.5,3,4] inf * 200)
> ,(K_dur,0.1)])
> let test = let {freq = control KR "freq" 440
> ;amp = control KR "amp" 0.1
> ;nharms = control KR "nharms" 10
> ;pan = control KR "pan" 0
> ;gate = control KR "gate" 1
> ;s = blip AR freq nharms * amp
> ;e = linen gate 0.01 0.6 0.4 RemoveSynth
> ;o = offsetOut 0 (pan2 s pan e)}
> in synthdef "test" o
> paudition (pbind [(K_instr,psynth test)
> ,(K_freq,prand 'α' [1,1.2,2,2.5,3,4] inf * 200)
> ,(K_dur,0.1)])
> paudition (pbind [(K_instr,psynth test)
> ,(K_param "nharms",pseq [4,10,40] inf)
> ,(K_dur,pseq [1,1,2,1] inf / 10)
> ,(K_freq,pn (pseries 1 1 16 * 50) 4)
> ,(K_sustain,pseq [1/10,0.5,1,2] inf)])
> let acid = let {freq = control KR "freq" 1000
> ;gate = control KR "gate" 1
> ;pan = control KR "pan" 0
> ;cut = control KR "cut" 4000
> ;res = control KR "res" 0.8
> ;amp = control KR "amp" 1
> ;s = rlpf (pulse AR freq 0.05) cut res
> ;d = envLinen 0.01 1 0.3 1
> ;e = envGen KR gate amp 0 1 RemoveSynth d
> ;o = out 0 (pan2 s pan e)}
> in synthdef "acid" o
> > Pbind(\instrument,\acid,
> > \dur,Pseq([0.25,0.5,0.25],4),
> > \root,-24,
> > \degree,Pseq([0,3,5,7,9,11,5,1],inf),
> > \pan,Pfunc({1.0.rand2}),
> > \cut,Pxrand([1000,500,2000,300],inf),
> > \rez,Pfunc({0.7.rand +0.3}),
> > \amp,0.2).play
> paudition (pbind [(K_instr,psynth acid)
> ,(K_dur,pseq [0.25,0.5,0.25] 4)
> ,(K_root,-24)
> ,(K_degree,pseq [0,3,5,7,9,11,5,1] inf)
> ,(K_param "pan",pwhite 'α' (-1.0) 1.0 inf)
> ,(K_param "cut",pxrand 'β' [1000,500,2000,300] inf)
> ,(K_param "res",pwhite 'γ' 0.3 1.0 inf)
> ,(K_amp,0.2)])
> > Pseq([Pbind(\instrument,\acid,
> > \dur,Pseq([0.25,0.5,0.25],4),
> > \root,-24,
> > \degree,Pseq([0,3,5,7,9,11,5,1],inf),
> > \pan,Pfunc({1.0.rand2}),
> > \cut,Pxrand([1000,500,2000,300],inf),
> > \rez,Pfunc({0.7.rand + 0.3}),
> > \amp,0.2),
> > Pbind(\instrument,\acid,
> > \dur,Pseq([0.25],6),
> > \root,-24,
> > \degree,Pseq([18,17,11,9],inf),
> > \pan,Pfunc({1.0.rand2}),
> > \cut,1500,
> > \rez,Pfunc({0.7.rand + 0.3}),
> > \amp,0.16)],inf).play
> paudition (pseq [pbind [(K_instr,psynth acid)
> ,(K_dur,pseq [0.25,0.5,0.25] 4)
> ,(K_root,-24)
> ,(K_degree,pseq [0,3,5,7,9,11,5,1] inf)
> ,(K_param "pan",pwhite 'α' (-1.0) 1.0 inf)
> ,(K_param "cut",pxrand 'β' [1000,500,2000,300] inf)
> ,(K_param "res",pwhite 'γ' 0.3 1.0 inf)
> ,(K_amp,0.2)]
> ,pbind [(K_instr,psynth acid)
> ,(K_dur,pn 0.25 6)
> ,(K_root,-24)
> ,(K_degree,pser [18,17,11,9] inf)
> ,(K_param "pan",pwhite 'δ' (-1.0) 1.0 inf)
> ,(K_param "cut",1500)
> ,(K_param "res",pwhite 'ε' 0.3 1.0 inf)
> ,(K_amp,0.16)]] inf)
> > Pbind(\instrument, \acid,
> > \dur, Pseq([0.25,0.5,0.25], inf),
> > \root, [-24,-17],
> > \degree, Pseq([0,3,5,7,9,11,5,1], inf),
> > \pan, Pfunc({1.0.rand2}),
> > \cut, Pxrand([1000,500,2000,300], inf),
> > \rez, Pfunc({0.7.rand +0.3}),
> > \amp, 0.2).play;
> paudition (pbind [(K_instr,psynth acid)
> ,(K_dur,pseq [0.25,0.5,0.25] inf)
> ,(K_root,pmce2 (-24) (-17))
> ,(K_degree,pseq [0,3,5,7,9,11,5,1] inf)
> ,(K_param "pan",pwhite 'α' (-1.0) 1.0 inf)
> ,(K_param "cut",pxrand 'β' [1000,500,2000,300] inf)
> ,(K_param "res",pwhite 'γ' 0.3 1.0 inf)
> ,(K_amp,0.2)])
A persistent synthesis node with /freq/ and /amp/ controls.
> import Sound.SC3.ID
> let {freq = control KR "freq" 440
> ;amp = control KR "amp" 0.6
> ;n = pinkNoise 'α' AR * amp}
> in audition (out 0 (pan2 (moogFF n freq 2 0) 0 1))
A pattern to set /freq/ and /amp/ controls at the most recently
instantiated synthesis node.
> :set -XOverloadedStrings
> paudition (pbind [(K_type,prepeat "n_set")
> ,(K_id,(-1))
> ,(K_freq,pwhite 'α' 100 1000 inf)
> ,(K_dur,0.2)
> ,(K_amp,toP [1,0.99 .. 0.1])])
> let berlinb =
> let {k = control KR
> ;o = k "out" 0
> ;f = k "freq" 80
> ;a = k "amp" 0.01
> ;p = k "pan" 0
> ;g = k "gate" 1
> ;env = decay2 g 0.05 8 * 0.0003
> ;syn = rlpf (lfPulse AR f 0 (sinOsc KR 0.12 (mce2 0 (pi/2)) * 0.48 + 0.5))
> (f * (sinOsc KR 0.21 0 * 18 + 20))
> 0.07
> ;syn_env = syn * env
> ;kil = detectSilence (mceChannel 0 syn_env) 0.1 0.2 RemoveSynth}
> in mrg2 (out o (a * mix (panAz 4 syn_env (mce2 p (p + 1)) 1 2 0.5))) kil
> paudition (ppar [pbind [(K_degree,pseq [0,1,2,4,6,3,4,8] inf)
> ,(K_dur,0.5)
> ,(K_octave,3)
> ,(K_instr,psynth (synthdef "berlinb" berlinb))]
> ,pbind [(K_degree,pseq [0,1,2,4,6,3,4,8] inf)
> ,(K_dur,0.5)
> ,(K_octave,pmce2 2 1)
> ,(K_param "pan",pwhite 'a' (-1) 1 inf)
> ,(K_instr,psynth (synthdef "berlinb" berlinb))]])
-}
pbind :: [P_Bind] -> P Event
pbind xs =
let xs' = fmap (\(k,v) -> pzip (undecided k) v) xs
xs'' = ptranspose_st_repeat xs'
in fmap e_from_list xs''
-- | Operator to lift 'F_Value' pattern to 'P_Bind' tuple.
--
-- > let {r = True `pcons` preplicate 3 False :: P Bool}
-- > in pbind [K_rest <| r] == pbind [(K_rest,pseq [1,0,0,0] 1)]
(<|) :: F_Value v => Key -> P v -> P_Bind
(<|) k p = (k,fmap toF p)
infixl 3 <|
{- | Pkey. SC3 pattern to read 'Key' at 'Event' pattern. Note
-- however that in haskell is usually more appropriate to name the
-- pattern using /let/.
> pkey K_freq (pbind [(K_freq,return 440)]) == toP [440]
> pkey K_amp (pbind [(K_amp,toP [0,1])]) == toP [0,1]
> > Pbind(\degree,Pseq([Pseries(-7,1,14),Pseries(7,-1,14)],inf),
> > \dur,0.25,
> > \legato,Pkey(\degree).linexp(-7,7,2.0,0.05)).play
> let {d = pseq [pseries (-7) 1 14,pseries 7 (-1) 14] inf
> ;l = fmap (Sound.SC3.Lang.Math.linexp (-7) 7 2 0.05) d}
> in paudition (pbind [(K_degree,d)
> ,(K_dur,0.25)
> ,(K_legato,l)])
-}
pkey :: Key -> P Event -> P Field
pkey k = fmap (fromJust . e_get k)
{- | Pmono. SC3 pattern that is a variant of 'pbind' for controlling
-- monophonic (persistent) synthesiser nodes.
> let p = [(K_instr,pinstr' (Instr_Ref "default" False))
> ,(K_id,100)
> ,(K_degree,pxrand 'α' [0,2,4,5,7,9,11] inf)
> ,(K_amp,pwrand 'β' [0.05,0.2] [0.7,0.3] inf)
> ,(K_dur,0.25)]
> in paudition (pmono p)
-}
pmono :: [P_Bind] -> P Event
pmono b =
let ty = fmap F_String ("s_new" `pcons` prepeat "n_set")
in pbind ((K_type,ty) : b)
-- | Pmul. SC3 pattern to multiply an existing key by a value, or set
-- the key if it doesn't exist.
--
-- > let p = pbind [(K_dur,0.15),(K_freq,prand 'α' [440,550,660] 6)]
-- > in paudition (pseq [p,pmul (K_freq,2) p,pmul (K_freq,0.5) p] 2)
pmul :: P_Bind -> P Event -> P Event
pmul (k,p) = pzipWith (\i j -> e_edit k 1 (* i) j) p
{-| Ppar. Variant of 'ptpar' with zero start times.
The result of `pmerge` can be merged again, `ppar` merges a list of
patterns.
> let {a = pbind [(K_param "a",pseq [1,2,3] inf)]
> ;b = pbind [(K_param "b",pseq [4,5,6] inf)]
> ;r = toP [e_from_list [(K_param "a",1),(K_fwd',0)]
> ,e_from_list [(K_param "b",4),(K_fwd',1)]]}
> in ptake 2 (ppar [a,b]) == r
> let {p = pbind [(K_dur,0.2),(K_midinote,pseq [62,65,69,72] inf)]
> ;q = pbind [(K_dur,0.4),(K_midinote,pseq [50,45] inf)]
> ;r = pbind [(K_dur,0.6),(K_midinote,pseq [76,79,81] inf)]}
> in paudition (ppar [p,q,r])
Multiple nested `ppar` patterns.
> let {a u = pbind [(K_dur,0.2),(K_param "pan",0.5),(K_midinote,pseq u 1)]
> ;b l = pbind [(K_dur,0.4),(K_param "pan",-0.5),(K_midinote,pseq l 1)]
> ;f u l = ppar [a u,b l]
> ;h = pbind [(K_dur,prand 'α' [0.2,0.4,0.6] inf)
> ,(K_midinote,prand 'β' [72,74,76,77,79,81] inf)
> ,(K_db,-26)
> ,(K_legato,1.1)]
> ;m = pseq [pbind [(K_dur,3.2),(K_freq,return nan)]
> ,prand 'γ' [f [60,64,67,64] [48,43]
> ,f [62,65,69,65] [50,45]
> ,f [64,67,71,67] [52,47]] 12] inf}
> in paudition (ppar [h,m])
-}
ppar :: [P Event] -> P Event
ppar l = ptpar (zip (repeat 0) l)
-- | Pstretch. SC3 pattern to do time stretching. It is equal to
-- 'pmul' at 'K_stretch'.
--
-- > let {d = pseq [pshuf 'α' [-7,-3,0,2,4,7] 2
-- > ,pseq [0,1,2,3,4,5,6,7] 1] 1
-- > ;p = pbind [(K_dur,0.15),(K_degree,d)]}
-- > in paudition (pseq [p,pstretch 0.5 p,pstretch 2 p] inf)
pstretch :: P Field -> P Event -> P Event
pstretch p = pmul (K_stretch,p)
{-| Ptpar. Merge a set of 'Event' patterns each with indicated
-- start 'Time'.
`ptpar` is a variant of `ppar` which allows non-equal start times.
> let {f d p n = pbind [(K_dur,d),(K_param "pan",p),(K_midinote,n)]
> ;a = f 0.2 (-1) (pseries 60 1 15)
> ;b = f 0.15 0 (pseries 58 2 15)
> ;c = f 0.1 1 (pseries 46 3 15)}
> in paudition (ptpar [(0,a),(1,b),(2,c)])
> let {d = pseq [pgeom 0.05 1.1 24,pgeom 0.5 0.909 24] 2
> ;f n a p = pbind [(K_dur,d)
> ,(K_db,a)
> ,(K_param "pan",p)
> ,(K_midinote,pseq [n,n-4] inf)]}
> in audition (ptpar [(0,f 53 (-20) (-0.9))
> ,(2,f 60 (-23) (-0.3))
> ,(4,f 67 (-26) 0.3)
> ,(6,f 74 (-29) 0.9)])
-}
ptpar :: [(Time,P Event)] -> P Event
ptpar l =
case l of
[] -> mempty
[(_,p)] -> p
(pt,p):(qt,q):r -> ptpar ((min pt qt,ptmerge (pt,p) (qt,q)) : r)
-- * Instrument Event Patterns
-- | Pattern from 'Instr'. An 'Instr' is either a 'Synthdef' or a
-- /name/. In the 'Synthdef' case the instrument is asynchronously
-- sent to the server before processing the event, which has timing
-- implications. The pattern constructed here uses the 'Synthdef' for
-- the first element, and the subsequently the /name/.
--
-- > paudition (pbind [(K_instr,pinstr' defaultInstr)
-- > ,(K_degree,toP [0,2,4,7])
-- > ,(K_dur,0.25)])
pinstr' :: Instr -> P Field
pinstr' i = toP (map F_Instr (i_repeat i))
{-| 'Instr' pattern from instrument /name/. See also `psynth` (where
the /sine/ instrument below is defined).
> let {si = return (F_Instr (Instr_Ref "sine" True))
> ;di = return (F_Instr (Instr_Ref "default" True))
> ;i = pseq [si,si,di] inf
> ;p = pbind [(K_instr,i),(K_degree,pseq [0,2,4,7] inf),(K_dur,0.25)]}
> in paudition p
-}
pinstr :: String -> P Field
pinstr s = pinstr' (Instr_Ref s True)
{-| `Synthdef`s can be used directly as an instrument using `psynth`.
The default synthdef is at 'Data.Default.def'.
> let sineSynth =
> let {f = control KR "freq" 440
> ;g = control KR "gate" 1
> ;a = control KR "amp" 0.1
> ;d = envASR 0.01 1 1 (EnvNum (-4))
> ;e = envGen KR g a 0 1 RemoveSynth d
> ;o = out 0 (sinOsc AR f 0 * e)}
> in synthdef "sine" o
> paudition (pbind [(K_instr,psynth sineSynth)
> ,(K_degree,toP [0,2,4,7])
> ,(K_dur,0.25)])
-}
psynth :: Synthdef -> P Field
psynth s = pinstr' (Instr_Def s True)
-- * MCE Patterns
-- | Two-channel MCE for /field/ patterns.
--
-- > pmce2 (toP [1,2]) (toP [3,4]) == toP [f_array [1,3],f_array [2,4]]
--
-- > let p = pmce2 (pseq [1,2] inf) (pseq [3,4] inf)
-- > in ptake 2 p == toP [f_array [1,3],f_array [2,4]]
pmce2 :: P Field -> P Field -> P Field
pmce2 p = pzipWith (\m n -> F_Vector [m,n]) p
-- | Three-channel MCE for /field/ patterns.
pmce3 :: P Field -> P Field -> P Field -> P Field
pmce3 p q = pzipWith3 (\m n o -> F_Vector [m,n,o]) p q
{-|
Remove one layer of MCE expansion at an /event/ pattern. The
pattern will be expanded only to the width of the initial input.
Holes are filled with rests.
> let {a = pseq [65,69,74] inf
> ;b = pseq [60,64,67,72,76] inf
> ;c = pseq [pmce3 72 76 79,pmce2 a b] 1}
> in paudition (p_un_mce (pbind [(K_midinote,c)
> ,(K_param "pan",pmce2 (-1) 1)
> ,(K_dur,1 `pcons` prepeat 0.15)]))
`p_un_mce` translates via `ppar`. This allows `dur` related fields to
be MCE values. The underlying event processor also implements one
layer of MCE expansion.
> paudition (p_un_mce
> (pbind [(K_dur,pmce2 0.25 0.2525)
> ,(K_legato,pmce2 0.25 2.5)
> ,(K_freq,pmce2 (pseq [300,400,500] inf)
> (pseq [302,402,502,202] inf))
> ,(K_param "pan",pmce2 (-0.5) 0.5)]))
-}
p_un_mce :: P Event -> P Event
p_un_mce p =
let l' = transpose_fw_def' e_rest (map e_un_mce' (unP p))
in toP (e_par (zip (repeat 0) l'))
-- * Non-SC3 Event Patterns
-- | Edit 'a' at 'Key' in each element of an 'Event' pattern.
pedit :: Key -> (Field -> Field) -> P Event -> P Event
pedit k f = fmap (e_edit' k f)
-- | Pattern of start times of events at event pattern.
--
-- > p_time (pbind [(K_dur,toP [1,2,3,2,1])]) == toP [0,1,3,6,8,9]
-- > p_time (pbind [(K_dur,pseries 0.5 0.5 5)]) == toP [0,0.5,1.5,3,5,7.5]
p_time :: P Event -> P Time
p_time = pscanl (+) 0 . fmap (fwd . e_dur Nothing)
-- | Pattern to extract 'a's at 'Key' from an 'Event'
-- pattern.
--
-- > pkey_m K_freq (pbind [(K_freq,return 440)]) == toP [Just 440]
pkey_m :: Key -> P Event -> P (Maybe Field)
pkey_m k = fmap (e_get k)
{-| Variant of 'ptmerge' with zero start times.
`pmerge` merges two event streams, adding /fwd'/ entries as required.
> let {p = pbind [(K_dur,0.2),(K_midinote,pseq [62,65,69,72] inf)]
> ;q = pbind [(K_dur,0.4),(K_midinote,pseq [50,45] inf)]}
> in paudition (pmerge p q)
-}
pmerge :: P Event -> P Event -> P Event
pmerge p q = ptmerge (0,p) (0,q)
-- | Variant that does not insert key.
pmul' :: P_Bind -> P Event -> P Event
pmul' (k,p) = pzipWith (\i j -> e_edit' k (* i) j) p
-- | Merge two 'Event' patterns with indicated start 'Time's.
ptmerge :: (Time,P Event) -> (Time,P Event) -> P Event
ptmerge (pt,p) (qt,q) =
toP (e_merge (pt,F.toList p) (qt,F.toList q))
-- | Left-biased union of event patterns.
punion :: P Event -> P Event -> P Event
punion = pzipWith (<>)
-- | 'punion' of 'pbind' of 'return', ie. @p_with (K_Instr,psynth s)@.
p_with :: P_Bind -> P Event -> P Event
p_with = punion . pbind . return
-- * NRT
{-| Transform an /event/ pattern into a /non-real time/ SC3 score.
> let n = pNRT (pbind [(K_freq,prand 'α' [300,500,231.2,399.2] inf)
> ,(K_dur,pseq [0.1,0.2] 3)])
> audition n
> mapM_ (putStrLn . bundlePP) (nrt_bundles n)
Infinite 'NRT' scores are productive for 'audition'ing.
> let n' = pNRT (pbind [(K_dur,0.25),(K_freq,pseq [300,600,900] inf)])
> audition n'
> mapM_ (putStrLn . bundlePP) (take 9 (nrt_bundles n'))
-}
pNRT :: P Event -> NRT
pNRT = e_nrt . Event_Seq . unP