{-# LANGUAGE DataKinds #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ViewPatterns #-}
{-# LANGUAGE NoIncoherentInstances #-}
{-# LANGUAGE NoMonomorphismRestriction #-}
{-# LANGUAGE NoUndecidableInstances #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE InstanceSigs #-}
module Vivid.Actions (
synth
, synthG
, synthNamed
, synthNamedG
, newSynthBefore
, synthBefore
, newSynthAfter
, synthAfter
, newSynthAtHead
, synthHead
, synthOn
, newSynthAtTail
, synthTail
, newGroup
, newGroupBefore
, newGroupAfter
, newGroupAtHead
, newGroupAtTail
, newParGroup
, newParGroupBefore
, newParGroupAfter
, newParGroupAtHead
, newParGroupAtTail
, set
, play
, free
, freeSynth
, release
, releaseIn
, freeBuf
, quitSCServer
, module Vivid.Actions.Class
, module Vivid.Actions.NRT
, module Vivid.Actions.Scheduled
, makeSynth
) where
import Vivid.OSC
import qualified Vivid.SC.Server.Commands as SCCmd
import Vivid.SC.Server.Types
import Vivid.SC.SynthDef.Types (CalculationRate(..))
import Vivid.SC.Server.Types
import Vivid.Actions.Class
import Vivid.Actions.IO ()
import Vivid.Actions.NRT
import Vivid.Actions.Scheduled
import Vivid.SCServer.Connection (closeSCServerConnection)
import Vivid.SCServer (defaultGroup)
import Vivid.SCServer.Types
import Vivid.SynthDef (getSDHashName, sd )
import Vivid.SynthDef.TypesafeArgs
import Control.Arrow (first)
import qualified Data.ByteString.UTF8 as UTF8
import Data.ByteString (ByteString)
import Data.Int
import Data.Monoid
import qualified Data.Map as Map
import Vivid.SynthDef (makeSynthDef)
import Vivid.SynthDef.Types
import Vivid.UGens.InOut (out)
play :: (VividAction m, MonoOrPoly s) => SDBody' '[] s -> m (Synth '[])
play monoOrPolyVersion = do
let polyVersion = getPoly monoOrPolyVersion
let sdUGens :: [(UGenName, CalculationRate)]
sdUGens =
map (\x -> (_ugenName x, _ugenCalculationRate x)) $
Map.elems $ _sdUGens $ makeSynthDef SDName_Hash () polyVersion
let sdWithOut = sd () $
if any (==(UGName_S "Out", AR)) sdUGens
then polyVersion
else do
foo <- polyVersion
out (0::Int) $ foo
synth sdWithOut ()
class MonoOrPoly s where
getPoly :: SDBody' a s -> SDBody' a [Signal]
instance MonoOrPoly [Signal] where
getPoly :: SDBody' a [Signal] -> SDBody' a [Signal]
getPoly = id
instance MonoOrPoly Signal where
getPoly :: SDBody' a Signal -> SDBody' a [Signal]
getPoly s = do
s' <- s
return [s', s']
freeG :: (VividAction m, SynthOrNodeId n) => n -> m ()
freeG (getNodeId -> nodeId) =
callOSC $ SCCmd.n_free nodeId
free, freeSynth :: VividAction m => Synth a -> m ()
free = freeSynth
freeSynth = freeG
release :: (Elem "gate" args, VividAction m) => Synth args -> m ()
release s = set s (0 ::I "gate")
releaseIn :: (Elem "gate" args, VividAction m, Real n) => n -> Synth args -> m ()
releaseIn releaseSecs s =
set s (toI $ negate $ 1 + abs releaseSecs ::I "gate")
set :: (VividAction m, Subset (InnerVars params) sdArgs, VarList params) => Synth sdArgs -> params -> m ()
set (Synth nodeId) params = do
let (as, _) = makeTypedVarList params
callOSC $ SCCmd.n_set nodeId (map (\(k,v)->(k, Right v)) as)
synth :: (VividAction m, VarList params, Subset (InnerVars params) args) => SynthDef args -> params -> m (Synth args)
synth theSD params = do
Synth <$> synthG theSD params
synthG :: (VividAction m, VarList params) => SynthDef a -> params -> m NodeId
synthG theSD params = do
defineSD theSD
makeSynth (synthName theSD) params SCCmd.AddToHead defaultGroup
synthName :: SynthDef a -> ByteString
synthName theSD = case theSD of
SynthDef (SDName_Named n) _ _ -> n
SynthDef SDName_Hash _ _ -> getSDHashName theSD
synthNamed :: (VividAction m, VarList params) => String -> params -> m (Synth a)
synthNamed name params = Synth <$>
makeSynth (UTF8.fromString name) params SCCmd.AddToHead defaultGroup
synthNamedG :: (VividAction m, VarList params) => String -> params -> m NodeId
synthNamedG name params =
makeSynth (UTF8.fromString name) params SCCmd.AddToHead defaultGroup
makeSynth :: (VividAction m, VarList params, IsNode node) => ByteString -> params -> SCCmd.AddAction -> node -> m NodeId
makeSynth theSynthName params addAction (getNodeId -> targetNodeId) = do
nodeId <- newNodeId
callOSC $ SCCmd.s_new theSynthName nodeId addAction targetNodeId (map (\(k,v)->(k,Right v)) paramList)
pure nodeId
where
paramList :: [(ByteString, Float)]
paramList =
[ (UTF8.fromString k, v) | (k, v) <- (fst $ makeTypedVarList params) ]
newSynthAtHead
, synthHead
, synthOn
, newSynthAtTail
, synthTail
:: (VividAction m, VarList params, Subset (InnerVars params) args, IsGroup group)
=> group -> SynthDef args -> params -> m (Synth args)
newSynthAtHead targetNode theSD params = do
defineSD theSD
Synth <$> makeSynth (synthName theSD) params SCCmd.AddToHead targetNode
synthHead = newSynthAtHead
synthOn = newSynthAtHead
newSynthAtTail targetNode theSD params = do
defineSD theSD
Synth <$> makeSynth (synthName theSD) params SCCmd.AddToTail targetNode
synthTail = newSynthAtTail
newSynthBefore
, synthBefore
, newSynthAfter
, synthAfter
:: (VividAction m, VarList params, Subset (InnerVars params) args, IsNode node)
=> node -> SynthDef args -> params -> m (Synth args)
newSynthBefore targetNode theSD params = do
defineSD theSD
Synth <$> makeSynth (synthName theSD) params SCCmd.AddBefore targetNode
synthBefore = newSynthBefore
newSynthAfter targetNode theSD params = do
defineSD theSD
Synth <$> makeSynth (synthName theSD) params SCCmd.AddAfter targetNode
synthAfter = newSynthAfter
quitSCServer :: IO ()
quitSCServer = do
callOSC $ SCCmd.quit
closeSCServerConnection
freeBuf :: VividAction m => BufferId -> m ()
freeBuf bufId = oscWSync $ \syncId ->
callOSC $ SCCmd.b_free bufId (Just $ SCCmd.sync syncId)
newGroup :: VividAction m => m Group
newGroup = newGroupAtHead defaultGroup
newParGroup :: VividAction m => m ParGroup
newParGroup = newParGroupAtHead defaultGroup
newGroupBefore, newGroupAfter :: (IsNode node, VividAction m) => node -> m Group
newGroupBefore = makeGroup SCCmd.AddBefore
newGroupAfter = makeGroup SCCmd.AddAfter
newGroupAtHead, newGroupAtTail :: (IsGroup group, VividAction m) => group -> m Group
newGroupAtHead = makeGroup SCCmd.AddToHead
newGroupAtTail = makeGroup SCCmd.AddToTail
newParGroupBefore, newParGroupAfter :: (IsNode node, VividAction m) => node -> m ParGroup
newParGroupBefore = makeParGroup SCCmd.AddBefore
newParGroupAfter = makeParGroup SCCmd.AddAfter
newParGroupAtHead, newParGroupAtTail :: (IsGroup group, VividAction m) => group -> m ParGroup
newParGroupAtHead = makeParGroup SCCmd.AddToHead
newParGroupAtTail = makeParGroup SCCmd.AddToTail
makeGroup :: (IsNode target, VividAction m) => SCCmd.AddAction -> target -> m Group
makeGroup = makeSomeKindaGroup SCCmd.g_new Group
makeParGroup :: (IsNode target, VividAction m) => SCCmd.AddAction -> target -> m ParGroup
makeParGroup = makeSomeKindaGroup SCCmd.p_new ParGroup
type GroupCmd = NodeId -> SCCmd.AddAction -> NodeId -> OSC
makeSomeKindaGroup :: (IsNode target, VividAction m) => (GroupCmd) -> (NodeId -> group) -> SCCmd.AddAction -> target -> m group
makeSomeKindaGroup createCommand constructor addAction (getNodeId -> targetNode) = do
nodeId <- newNodeId
callOSC $ createCommand nodeId addAction targetNode
sync
pure $ constructor nodeId