Module

WAGS.Control.Functions

Package
purescript-wags
Repository
mikesol/purescript-wags

#start Source

start :: forall env audio engine m res. Monad m => AudioInterpret audio engine => InitialFrameT env audio engine m res Unit

The initial Frame that is needed to begin any Scene.

piece :: Scene (SceneI Unit Unit) FFIAudio (Effect Unit) Frame0
piece =
  WAGS.do
    start -- initial frame
    { time } <- env
    create (scene time) $> Right unit
    @> loop
        ( const
            $ WAGS.do
                { time } <- env
                ivoid $ change (scene time)
        )

#modifyRes Source

modifyRes :: forall env audio engine proof m res i. Monad m => AudioInterpret audio engine => (res -> res) -> FrameT env audio engine proof m res i i res

Modifies the residual for a frame and returns the result. If a frame never modifies its residual, the value of mempty for res is returned to the scene.

#makeScene Source

makeScene :: forall env audio engine proofA m res i currentIdx graph changeBit skolems a. Monad m => Monoid res => AudioInterpret audio engine => GraphIsRenderable graph => FrameT env audio engine proofA m res i (UniverseC currentIdx graph changeBit skolems) (Either (SceneT env audio engine proofA m res) a) -> (forall proofB. FrameT env audio engine proofB m res i (UniverseC currentIdx graph changeBit skolems) a -> SceneT env audio engine proofB m res) -> SceneT env audio engine proofA m res

Make a scene. The infix operator for this operation is @>.

This function uses the GraphIsRenderable typeclass to assert that an audio graph is renderable by the web audio engine. This means, amongst other things, that it has a unique output device (ie speaker), that it does not have any dangling units not connected to a loudspeaker, etc.

It accepts as arguments:

  • a frame to render
  • a function that accepts a frame from the next moment in time (proofB) and returns a scene.

From these arguments, it produces a SceneT.

piece :: Scene (SceneI Unit Unit) FFIAudio (Effect Unit) Frame0
piece =
  WAGS.do
    start
    { time } <- env
    create (scene time) $> Right unit
    @> loop -- here, @> is the infix version of `makeScene`
        ( const
            $ WAGS.do
                { time } <- env
                ivoid $ change (scene time)
        )

#makeScene' Source

makeScene' :: forall env audio engine proofA m res i currentIdx graph changeBit skolems a. Monad m => Monoid res => AudioInterpret audio engine => GraphIsRenderable graph => FrameT env audio engine proofA m res i (UniverseC currentIdx graph changeBit skolems) a -> (forall proofB. FrameT env audio engine proofB m res i (UniverseC currentIdx graph changeBit skolems) a -> SceneT env audio engine proofB m res) -> SceneT env audio engine proofA m res

Similar to makeScene', but without the possibility to branch to a new scene. Aliased as @|>.

#loop Source

loop :: forall env audio engine proofA i m res currentIdx graph changeBit skolems edge a. Monad m => Monoid res => AudioInterpret audio engine => TerminalIdentityEdge graph edge => GraphIsRenderable graph => (forall proofB j. a -> FrameT env audio engine proofB m res (UniverseC currentIdx graph j skolems) (UniverseC currentIdx graph (Succ j) skolems) a) -> FrameT env audio engine proofA m res i (UniverseC currentIdx graph changeBit skolems) a -> SceneT env audio engine proofA m res

Loops audio.

In WAGS, a "loop" is a universe whose changeBit increments by 1. That means that the structure of the graph is similar (no units added, none taken away) while some or none of its internal content (ie frequencies, gains, etc) has changed. This is accomplished using the change family of functions in WAGS.Change.

piece :: Scene (SceneI Unit Unit) FFIAudio (Effect Unit) Frame0
piece =
  WAGS.do
    start -- initial frame
    { time } <- env
    create (scene time) $> Right unit
    @> loop -- we loop by changing the scene based on `time` in the `env`
        ( const
            $ WAGS.do
                { time } <- env
                ivoid $ change (scene time)
        )

#branch Source

branch :: forall env audio engine proofA i m res currentIdx graph changeBit skolems a. Monad m => Monoid res => AudioInterpret audio engine => GraphIsRenderable graph => (forall proofB j. a -> FrameT env audio engine proofB m res (UniverseC currentIdx graph j skolems) (UniverseC currentIdx graph j skolems) (Either (FrameT env audio engine proofB m res i (UniverseC currentIdx graph j skolems) Unit -> SceneT env audio engine proofB m res) (FrameT env audio engine proofB m res (UniverseC currentIdx graph j skolems) (UniverseC currentIdx graph (Succ j) skolems) a))) -> FrameT env audio engine proofA m res i (UniverseC currentIdx graph changeBit skolems) a -> SceneT env audio engine proofA m res

Accepts a "branch" frame for making a scene, where Left is a new scene and Right is the incoming scene with the change bit incremented by 1. Useful for the common pattern where we loop an audio graph until something in the environment changes, at which point we move on to a new graph.

simpleScene =
  ( WAGS.do
      start
      e <- env
      create (scene0 e) $> Right unit
  )
    @> ( branch \_ -> WAGS.do
          { time } <- env
          pr <- proof
          withProof pr
            $ if time < 0.3 then
                Right
                  (
                      WAGS.do
                        e <- env
                        ivoid $ change (scene0 e)
                  )
              else
                Left
                  ( loop
                      ( const
                          $ WAGS.do
                              e <- env
                              ivoid $ change (scene1 e)
                      )
                  )
      )

#inSitu Source

inSitu :: forall env audio engine proof m r i x z a. Monad m => (FrameT env audio engine proof m r i z a -> SceneT env audio engine proof m r) -> FrameT env audio engine proof m r x z a -> FrameT env audio engine proof m r i x Unit -> SceneT env audio engine proof m r

Often times, the computation in a frame will need to start from universe x and proceed to universe z before continuing to produce a scene. inSitu "thunks" the computation at x.

#universe Source

universe :: forall env audio engine proof m res i. Monad m => AudioInterpret audio engine => FrameT env audio engine proof m res i i (Proxy i)

Get the current universe as a proxy.

#currentIdx Source

currentIdx :: forall env audio engine proof m res currentIdx graph changeBit skolems. Monad m => AudioInterpret audio engine => FrameT env audio engine proof m res (UniverseC currentIdx graph changeBit skolems) (UniverseC currentIdx graph changeBit skolems) (Proxy currentIdx)

Get the current index as a proxy.

#changeBit Source

changeBit :: forall env audio engine proof m res currentIdx graph changeBit skolems. Monad m => AudioInterpret audio engine => FrameT env audio engine proof m res (UniverseC currentIdx graph changeBit skolems) (UniverseC currentIdx graph changeBit skolems) (Proxy changeBit)

Get the changeBit as a proxy.

#env Source

env :: forall env audio engine proof m res i. Monad m => AudioInterpret audio engine => FrameT env audio engine proof m res i i env

Get the environment from a frame.

piece :: Scene (SceneI Unit Unit) FFIAudio (Effect Unit) Frame0
piece =
  WAGS.do
    start
    { time } <- env -- get the environment
    create (scene time) $> Right unit
    @> loop
        ( const
            $ WAGS.do
                { time } <- env
                ivoid $ change (scene time)
        )

#freeze Source

freeze :: forall env audio engine proof m res i currentIdx graph changeBit skolems x. Monad m => Monoid res => AudioInterpret audio engine => GraphIsRenderable graph => FrameT env audio engine proof m res i (UniverseC currentIdx graph changeBit skolems) x -> SceneT env audio engine proof m res

Freezes the current audio frame.

scene = (start :*> create (speaker (sinOsc 440.0))) @|> freeze

#graph Source

graph :: forall env audio engine proof m res currentIdx graph changeBit skolems. Monad m => AudioInterpret audio engine => FrameT env audio engine proof m res (UniverseC currentIdx graph changeBit skolems) (UniverseC currentIdx graph changeBit skolems) (Proxy graph)

Get the current graph as a proxy.

#lift Source

lift :: forall env audio engine proof m res i a. Monad m => AudioInterpret audio engine => m a -> FrameT env audio engine proof m res i i a

Lift a computation from the underlying monad m into FrameT.

#proof Source

proof :: forall env audio engine proof m res i. Monad m => AudioInterpret audio engine => FrameT env audio engine proof m res i i proof

Get the proof term from a frame. Useful to construct a new frame using withProof. The following snippet is taken from the WTK example where proof is used to generate a proof term that is then consumed by withProof in order to make the final Frame.

piece :: { makeRenderingEnv :: MakeRenderingEnv } -> Scene (SceneI Trigger Unit) FFIAudio (Effect Unit) Frame0
piece { makeRenderingEnv } =
  ( WAGS.do
      start
      ivoid $ create $ fullKeyboard klavierIdentity
      k0 <- cursor $ cursors.k0
      k1 <- cursor $ cursors.k1
      k2 <- cursor $ cursors.k2
      k3 <- cursor $ cursors.k3
      k4 <- cursor $ cursors.k4
      k5 <- cursor $ cursors.k5
      k6 <- cursor $ cursors.k6
      k7 <- cursor $ cursors.k7
      k8 <- cursor $ cursors.k8
      k9 <- cursor $ cursors.k9
      myProof <- proof
      withProof myProof
        $ Right
            { audioRefs: k0 /\ k1 /\ k2 /\ k3 /\ k4 /\ k5 /\ k6 /\ k7 /\ k8 /\ k9
            , currentKeys: (Nil :: (List KeyInfo))
            , availableKeys: K0 : K1 : K2 : K3 : K4 : K5 : K6 : K7 : K8 : K9 : Nil
            }
  )
    @> loop
        ( \{ audioRefs, currentKeys, availableKeys } -> WAGS.do
            { time, trigger, active } <- env
            graphProxy <- graph
            let
              { notesOff
              , onsets
              , newCurrentKeys
              , newAvailableKeys
              , futureCurrentKeys
              , futureAvailableKeys
              } = makeRenderingEnv active trigger time availableKeys currentKeys
            ( playKeys
                { graphProxy
                , audioRefs
                , currentTime: time
                , notesOff
                }
                unit
                onsets
                newCurrentKeys
            )
              $> { audioRefs
                , currentKeys: futureCurrentKeys
                , availableKeys: futureAvailableKeys
                }
        )

#withProof Source

withProof :: forall env audio engine proof m res i a. Monad m => AudioInterpret audio engine => proof -> a -> FrameT env audio engine proof m res i i a

Consumes a proof term to construct a FrameT. This pattern is used because FrameT does not implement IxApplicative. Instead, in order to construct a frame, one needs to provide proof that one is at the current moment in time. This is to prevent frames from different timestamps from mixing.

#(@>) Source

Operator alias for WAGS.Control.Functions.makeScene (right-associative / precedence 6)

#(@|>) Source

Operator alias for WAGS.Control.Functions.makeScene' (right-associative / precedence 6)