essence-of-live-coding-pulse (empty) → 0.1.0.1
raw patch · 6 files changed
+201/−0 lines, 6 filesdep +basedep +essence-of-live-codingdep +foreign-storesetup-changed
Dependencies added: base, essence-of-live-coding, foreign-store, pulse-simple, transformers
Files
- CHANGELOG.md +5/−0
- LICENSE +30/−0
- Setup.hs +2/−0
- essence-of-live-coding-pulse.cabal +39/−0
- src/LiveCoding/Pulse.hs +96/−0
- src/LiveCoding/Pulse/GHCi.hs +29/−0
+ CHANGELOG.md view
@@ -0,0 +1,5 @@+# Revision history for essence-of-live-coding-pulse++## 0.1.0.0 -- YYYY-mm-dd++* First version. Released on an unsuspecting world.
+ LICENSE view
@@ -0,0 +1,30 @@+Copyright (c) 2019, 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.
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ essence-of-live-coding-pulse.cabal view
@@ -0,0 +1,39 @@+name: essence-of-live-coding-pulse+version: 0.1.0.1+synopsis: General purpose live coding framework - pulse 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 PulseAudio.++license: BSD3+license-file: LICENSE+author: Manuel Bärenz+maintainer: programming@manuelbaerenz.de+homepage: https://www.manuelbaerenz.de/#computerscience+category: FRP, Live coding+build-type: Simple+extra-source-files: CHANGELOG.md+cabal-version: >=1.10++library+ exposed-modules:+ LiveCoding.Pulse+ LiveCoding.Pulse.GHCi+ build-depends:+ base >= 4.11 && <4.13+ , essence-of-live-coding+ , transformers+ , pulse-simple == 0.1.*+ , foreign-store+ hs-source-dirs: src+ default-language: Haskell2010
+ src/LiveCoding/Pulse.hs view
@@ -0,0 +1,96 @@+{-# LANGUAGE Arrows #-}+module LiveCoding.Pulse where++-- base+import Control.Arrow as X+import Control.Concurrent+import Control.Monad (forever)+import Control.Monad.Fix++-- transformers+import Control.Monad.Trans.Reader++-- pulse-simple+import Sound.Pulse.Simple++-- essence-of-live-coding+import LiveCoding++type PulseCell = Cell IO () Float++playPulseCell :: PulseCell -> IO (MVar PulseCell)+playPulseCell pulseCell = do+ var <- newMVar pulseCell+ pulseClient <- simpleNew+ Nothing+ "example"+ Play+ Nothing+ "this is an example application"+ (SampleSpec (F32 LittleEndian) 44100 1)+ Nothing+ Nothing+ forkIO $ forever $ do+ cell <- takeMVar var+ (samples, cell') <- steps cell $ replicate 1024 ()+ simpleWrite pulseClient samples+ putMVar var cell'+ return var++-- TODO Generalisable+updatePulse :: MVar PulseCell -> PulseCell -> IO ()+updatePulse var newCell = do+ oldCell <- takeMVar var+ putMVar var $ hotCodeSwapCell newCell oldCell++-- Returns the sum between -1 and 1+wrapSum :: (Monad m, Data a, RealFloat a) => Cell m a a+wrapSum = Cell+ { cellState = 0+ , cellStep = \accum a ->+ let+ (_, accum') = properFraction $ accum + a+ in return (accum', accum')+ }++modSum :: (Monad m, Data a, Integral a) => a -> Cell m a a+modSum denominator = Cell+ { cellState = 0+ , cellStep = \accum a -> let accum' = (accum + a) `mod` denominator in return (accum', accum')+ }+++clamp :: (Ord a, Num a) => a -> a -> a -> a+clamp lower upper a = min upper $ max lower a++osc :: (Data a, RealFloat a, MonadFix m) => Cell (ReaderT a m) () a+osc = proc _ -> do+ f <- constM ask -< ()+ phase <- wrapSum -< f / 44100+ returnA -< sin $ 2 * pi * phase++osc' :: (Data a, RealFloat a, MonadFix m) => Cell m a a+osc' = proc a -> do+ runReaderC' osc -< (a, ())++data Note+ = A+ | Bb+ | B+ | C+ | Cis+ | D+ | Dis+ | E+ | F+ | Fis+ | G+ | Gis+ deriving (Enum, Show)++f :: Note -> Float+f note = 220 * (2 ** (fromIntegral (fromEnum note) / 12))++o :: Float -> Float+o = (* 2)+
+ src/LiveCoding/Pulse/GHCi.hs view
@@ -0,0 +1,29 @@+module LiveCoding.Pulse.GHCi where++-- base+import Control.Concurrent++-- foreign-store+import Foreign.Store++-- essence-of-live-coding+import LiveCoding.LiveProgram++-- essence-of-live-coding-pulse+import LiveCoding.Pulse++livepulse "" = livepulse "pulseCell"+livepulse pulseCell = return $ unlines+ [ "var <- playPulseCell " ++ pulseCell+ , "savePulse var"+ ]+livereloadpulse "" = livereloadpulse "pulseCell"+livereloadpulse pulseCell = return $ unlines+ [ ":reload"+ , "var <- loadPulse"+ , "updatePulse var " ++ pulseCell+ ]+loadPulse :: IO (MVar PulseCell)+loadPulse = readStore (Store 0)+savePulse :: MVar PulseCell -> IO ()+savePulse var = writeStore (Store 0) var