packages feed

essence-of-live-coding-vivid (empty) → 0.2.6

raw patch · 4 files changed

+181/−0 lines, 4 filesdep +basedep +essence-of-live-codingdep +vivid

Dependencies added: base, essence-of-live-coding, vivid

Files

+ CHANGELOG.md view
@@ -0,0 +1,5 @@+# Revision history for essence-of-live-coding-vivid++## 0.2.5++* Thank you, Miguel Negrão, for extensive support, suggestions, testing, and debugging!
+ LICENSE view
@@ -0,0 +1,30 @@+Copyright (c) 2021, Manuel Bärenz++All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are met:++    * Redistributions of source code must retain the above copyright+      notice, this list of conditions and the following disclaimer.++    * Redistributions in binary form must reproduce the above+      copyright notice, this list of conditions and the following+      disclaimer in the documentation and/or other materials provided+      with the distribution.++    * Neither the name of Manuel Bärenz nor the names of other+      contributors may be used to endorse or promote products derived+      from this software without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ essence-of-live-coding-vivid.cabal view
@@ -0,0 +1,36 @@+name:               essence-of-live-coding-vivid+version:            0.2.6+synopsis: General purpose live coding framework - vivid backend+description:+  essence-of-live-coding is a general purpose and type safe live coding framework.+  .+  You can run programs in it, and edit, recompile and reload them while they're running.+  Internally, the state of the live program is automatically migrated when performing hot code swap.+  .+  The library also offers an easy to use FRP interface.+  It is parametrized by its side effects,+  separates data flow cleanly from control flow,+  and allows to develop live programs from reusable, modular components.+  There are also useful utilities for debugging and quickchecking.+  .+  This package contains the backend for vivid, a Supercollider library.+license:             BSD3+license-file:        LICENSE+author:              Manuel Bärenz+maintainer:          programming@manuelbaerenz.de+copyright:           2021 Manuel Bärenz+category:            Sound+build-type:          Simple+cabal-version:       >=1.10+extra-source-files: CHANGELOG.md++library+    exposed-modules:+        LiveCoding.Vivid++    build-depends:+        base >= 4.7 && < 5+      , vivid >= 0.5.2.0+      , essence-of-live-coding >= 0.2.6+    hs-source-dirs:   src+    default-language: Haskell2010
+ src/LiveCoding/Vivid.hs view
@@ -0,0 +1,110 @@+{- | Support for [@vivid@](https://hackage.haskell.org/package/vivid),+a Haskell library for [SuperCollider](https://supercollider.github.io/).++With this module, you can create cells corresponding to synthesizers.++The synthesizers automatically start and stop on reload.+-}++{-# LANGUAGE Arrows #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE DeriveDataTypeable #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE RecordWildCards #-}+{-# LANGUAGE StandaloneDeriving #-}+module LiveCoding.Vivid where++-- base+import Data.Foldable (traverse_)+import GHC.TypeLits (KnownSymbol)++-- vivid+import Vivid++-- essence-of-live-coding+import LiveCoding.Handle+import LiveCoding++{- | Whether a synthesizer should currently be running or not.++Typically, you will either statically supply the value and change it in the code to start and stop the synth,+or you can connect another cell to it.+-}+data SynthState+  = Started+  | Stopped+  deriving (Eq)++{- | A 'ParametrisedHandle' corresponding to one @vivid@/@SuperCollider@ synthesizer.++Usually, you will want to use 'liveSynth' instead, it is easier to handle.+-}+vividHandleParametrised+  :: (VividAction m, Eq params, VarList params, Subset (InnerVars params) args, Elem "gate" args)+  => ParametrisedHandle (params, SynthDef args, SynthState) m (Maybe (Synth args))+vividHandleParametrised = ParametrisedHandle { .. }+  where+    createParametrised (params, synthDef, Started) = Just <$> synth synthDef params+    createParametrised (params, synthDef, Stopped) = defineSD synthDef >> pure Nothing++    destroyParametrised _ synthMaybe = traverse_ release synthMaybe++    -- Only the synth parameters changed and it's still running.+    -- So simply set new parameters without stopping it.+    changeParametrised (paramsOld, synthDefOld, Started) (paramsNew, synthDefNew, Started) (Just synth)+      | paramsOld /= paramsNew && synthDefOld == synthDefNew = do+          set synth paramsNew+          return $ Just synth+    -- Synthdef or start/stop state changed, need to release and reinitialise+    changeParametrised old new synth = defaultChange createParametrised destroyParametrised old new synth++deriving instance Data SynthState+deriving instance KnownSymbol a => Data (I a)++{- | Create a synthesizer.++When you add 'liveSynth' to your live program,+it will be started upon reload immediately.++Feed the definition of the synthesizer and its current intended state to this cell.+The input has the form @(params, sdbody, synthState)@.++* A change in @params@ will reload the synthesizer quickly,+  unless the types of the parameters change.+* A change in the @sdbody :: 'SDBody' ...@ or the _types_ of the @params@ will 'release' the synthesizer and start a new one.+* The input @synthState :: 'SynthState'@ represent whether the synthesizer should currently be running or not.+  Changes in it quickly start or stop it.+  * When it is started, @'Just' synth@ is returned, where @synth@ represents the running synthesizer.+  * When it is stopped, 'Nothing' is returned.++You have to use 'envGate' in your @sdbody@,+or another way of gating your output signals+in order to ensure release of the synths without clipping.++For an example, have a look at the source code of 'sine'.+-}+liveSynth+  :: ( VividAction m+     , Eq params, Typeable params, VarList params+     , Typeable (InnerVars params), Subset (InnerVars params) (InnerVars params)+     , Elem "gate" (InnerVars params), Data params+     )+  => Cell (HandlingStateT m)+       (params, SDBody' (InnerVars params) [Signal], SynthState)+       (Maybe (Synth (InnerVars params)))+liveSynth = proc (params, sdbody, synthstate) -> do+  paramsFirstValue <- holdFirst -< params+  handlingParametrised vividHandleParametrised -< (params, sd paramsFirstValue sdbody, synthstate)++-- | Example sine synthesizer that creates a sine wave at the given input frequency.+sine :: (VividAction m) => Cell (HandlingStateT m) Float ()+sine = proc frequency -> do+  liveSynth -<+    (+      ( 1 :: I "gate"+      , 2 :: I "fadeSecs"+      , I frequency :: I "freq"+      )+    , out (0 :: Int) [envGate ~* sinOsc (freq_ (V :: V "freq"))]+    , Started)+  returnA -< ()