haskore-supercollider 0.0.2 → 0.1
raw patch · 18 files changed
+385/−131 lines, 18 filesdep +containersdep +opensoundcontrol-htdep +transformersdep −mtldep ~arraydep ~data-accessordep ~haskore
Dependencies added: containers, opensoundcontrol-ht, transformers, utility-ht
Dependencies removed: mtl
Dependency ranges changed: array, data-accessor, haskore, haskore-realtime, hosc, hsc3, random, supercollider-ht
Files
- Makefile +1/−1
- haskore-supercollider.cabal +29/−11
- src/Haskore/General/IdGenerator.hs +85/−0
- src/Haskore/General/IdGenerator/Modulo.hs +43/−0
- src/Haskore/General/IdGenerator/Set.hs +52/−0
- src/Haskore/General/IdGenerator/Simple.hs +46/−0
- src/Haskore/Interface/SuperCollider/Channel/State.hs +2/−2
- src/Haskore/Interface/SuperCollider/Note.hs +10/−8
- src/Haskore/Interface/SuperCollider/Play.hs +37/−37
- src/Haskore/Interface/SuperCollider/Play/Channel.hs +9/−9
- src/Haskore/Interface/SuperCollider/Play/Install.hs +11/−11
- src/Haskore/Interface/SuperCollider/Play/Life.hs +6/−6
- src/Haskore/Interface/SuperCollider/Render.hs +30/−2
- src/Haskore/Interface/SuperCollider/Schedule.hs +6/−38
- src/Haskore/Interface/SuperCollider/Schedule/Channel.hs +5/−3
- src/Haskore/Interface/SuperCollider/Schedule/Install.hs +1/−1
- src/Haskore/Interface/SuperCollider/SoundMap.hs +2/−2
- src/Haskore/Interface/SuperCollider/Timer.hs +10/−0
Makefile view
@@ -1,7 +1,7 @@ .PHONY: ghci jack jack-rt supercollider supercollider-rt scj ghci:- ghci -i:src+ ghci -i:src src/Haskore/Interface/SuperCollider/Example.hs jack: # -n 2 is default, larger values are not supported
haskore-supercollider.cabal view
@@ -1,11 +1,10 @@ Name: haskore-supercollider-Version: 0.0.2+Version: 0.1 License: GPL License-File: LICENSE Author: Henning Thielemann <haskell@henning-thielemann.de> Homepage: http://www.haskell.org/haskellwiki/SuperCollider-Package-URL: http://darcs.haskell.org/haskore-supercollider/-Category: Sound+Category: Sound, Music Synopsis: Haskore back-end for SuperCollider Description: This package lets you play Haskore music via Supercollider@@ -14,13 +13,21 @@ We support realtime replay and rendering to disk. Stability: Experimental Tested-With: GHC==6.4.1, GHC==6.8.2-Cabal-Version: >=1.2+Cabal-Version: >=1.6 Build-Type: Simple- Extra-Source-Files: Makefile Readme +Source-Repository head+ type: darcs+ location: http://darcs.haskell.org/haskore-supercollider/++Source-Repository this+ type: darcs+ location: http://darcs.haskell.org/haskore-supercollider/+ tag: 0.1+ Flag splitBase description: Choose the new smaller, split-up base package. @@ -30,21 +37,27 @@ Library Build-Depends:- haskore-realtime >= 0.0.2 && < 0.1,- haskore >=0.0.5 && <0.1,+ haskore-realtime >= 0.1 && < 0.2,+ haskore >=0.1 && <0.2, -- for SuperCollider support- hosc >=0.1 && <0.2, hsc3 >=0.1 && <0.2, supercollider-ht >=0.0 && <0.1,+ hosc >=0.6 && <0.7, hsc3 >=0.6 && <0.7,+ opensoundcontrol-ht >=0.1 && <0.2, supercollider-ht >=0.1 && <0.2, bytestring >=0.9 && <1.0, -- dependency on non-negative for Haddock non-negative >=0.0.1 && <0.1, event-list >=0.0.6 && <0.1,- data-accessor >=0.1 && <0.2,+ data-accessor >=0.2 && <0.3,+ utility-ht >=0.0.3 && <0.1, unix >= 2.0 && <3,- mtl >=1.0 && <2+ transformers >=0.0 && <0.2 If flag(splitBase) Build-Depends:- base >= 3, random >= 1.0 && < 1.1, array >= 0.1 && < 1, process >= 1.0 && < 1.1+ base >= 3,+ array >= 0.1 && <1.0,+ containers >=0.1 && <1.0,+ random >= 1.0 && <2.0,+ process >= 1.0 && <1.1 Else Build-Depends: base >= 1.0 && < 2@@ -71,6 +84,11 @@ Haskore.Interface.SuperCollider.Schedule.Install, Haskore.Interface.SuperCollider.Schedule.Channel Other-modules:+ Haskore.Interface.SuperCollider.Timer,+ Haskore.General.IdGenerator,+ Haskore.General.IdGenerator.Modulo,+ Haskore.General.IdGenerator.Set,+ Haskore.General.IdGenerator.Simple, Haskore.Interface.SuperCollider.Example.Air, Haskore.Interface.SuperCollider.Example.Morph
+ src/Haskore/General/IdGenerator.hs view
@@ -0,0 +1,85 @@+{- | Identifier generator++Generates unique elements but elements can be declared as unused, again.++-}++module Haskore.General.IdGenerator where++import Data.Set (Set)+import qualified Data.Set as Set+import Control.Monad.Trans.State(State, state, evalState, modify, get, )+import Control.Monad (when, )+import Data.Tuple.HT (mapFst, )++{- |++The generator is a state monad+where the state consists of the set of the explicitly unused elements+and a lower bound for another set of ids that are still unused.+Essentially, the Set stores all recycled ids,+and the lower bound stores the ids not used so far.+All elements in the explicit set must be below the bound.++-}++type T i a = State (St i) a++type St i = (Set i, i)++run :: i -> T i a -> a+run start gen = evalState gen (Set.empty, start)++{- |++Reserve a new id.++-}++alloc :: (Ord i, Enum i) => T i i+alloc =+ state $ \(set, next) ->+ if Set.null set+ then (next, (set, succ next))+ else let (newId, newSet) = Set.deleteFindMin set+ in (newId, (newSet, next))++{- |++Return an id.++We call reduce in order to prevent the set from growing too much.+We call it only once in order to prevent a heavy CPU lead+when the last id of a sequence is returned.+So the reduction is spread over several calls to 'free'.++-}++free :: (Ord i, Enum i) => i -> T i ()+free oldId =+ do s <- get+ when (isFree s oldId)+ (error "IdGenerator.free: id freed twice")+ modify (mapFst (Set.insert oldId))+ modify reduce++{- |++If the largest free id and the lower bound of free ids are successive elements+then we can decrease the lower bound.+This procedure can be iterated.+This way we can save storage in the set.++-}++reduce :: (Ord i, Enum i) => St i -> St i+reduce (set, next) =+ if not (Set.null set) && Set.findMax set == pred next+ then (Set.deleteMax set, pred next)+ else (set, next)++isFree :: (Ord i) => St i -> i -> Bool+isFree (set,next) i = Set.member i set || i >= next++isValid :: (Ord i) => St i -> Bool+isValid (set,next) = Set.findMax set < next
+ src/Haskore/General/IdGenerator/Modulo.hs view
@@ -0,0 +1,43 @@+{- | Identifier generator++A simple test of whether identifiers can be re-used in SuperCollider.+This has no practical use.++-}++module Haskore.General.IdGenerator.Modulo where++import Control.Monad.Trans.State (State, evalState, modify, get, )++{- |++The generator is a simple state monad.++-}++type T i a = State i a++run :: i -> T i a -> a+run = flip evalState++{- |++Reserve a new id.++-}++alloc :: (Integral i) => T i i+alloc =+ do newId <- get+ modify (flip mod 50 . succ)+ return (newId+2)++{- |++Unreserve an id.+In this implementation it performs essentially nothing.++-}++free :: i -> T i ()+free _ = return ()
+ src/Haskore/General/IdGenerator/Set.hs view
@@ -0,0 +1,52 @@+{- | Identifier generator++Generates unique elements but elements can be declared as unused, again.++-}++module Haskore.General.IdGenerator.Set where++import Data.Set (Set)+import qualified Data.Set as Set+import Control.Monad.Trans.RWS(RWS, evalRWS, modify, get, ask, )+import Control.Monad (when, )++{- |++The generator is a reader+state monad+where the state consists of the allocated identifiers+and the reader source is the least element ever used.++-}++type T i a = RWS i () (Set i) a++run :: i -> T i a -> a+run start gen = fst $ evalRWS gen start Set.empty++{- |++Reserve a new id.++-}++alloc :: (Ord i, Enum i) => T i i+alloc =+ do start <- ask+ allocated <- get+ let newId = head $ filter (not . flip Set.member allocated) [start ..]+ modify (Set.insert newId)+ return newId++{- |++Deallocate an id.++-}++free :: (Ord i, Enum i) => i -> T i ()+free oldId =+ do allocated <- get+ when (not $ Set.member oldId allocated)+ (error "IdGeneratorSet.free: deallocated free identifier")+ modify (Set.delete oldId)
+ src/Haskore/General/IdGenerator/Simple.hs view
@@ -0,0 +1,46 @@+{- | Identifier generator++Generates unique elements without recycling of identifiers.++-}++module Haskore.General.IdGenerator.Simple where++import Control.Monad.Trans.State (State, evalState, modify, get, )+import Control.Monad (when, )++{- |++The generator is a simple state monad.++-}++type T i a = State i a++run :: i -> T i a -> a+run = flip evalState++{- |++Reserve a new id.++-}++alloc :: (Enum i) => T i i+alloc =+ do newId <- get+ modify succ+ return newId++{- |++Unreserve an id.+In this implementation it performs essentially nothing.++-}++free :: (Ord i) => i -> T i ()+free oldId =+ do freeId <- get+ when (freeId <= oldId)+ (error "IdGeneratorSimple.free: freed unreserved id")
src/Haskore/Interface/SuperCollider/Channel/State.hs view
@@ -4,8 +4,8 @@ -} module Haskore.Interface.SuperCollider.Channel.State where -import qualified Control.Monad.State as State-import Control.Monad.State (StateT)+import qualified Control.Monad.Trans.State as State+import Control.Monad.Trans.State (StateT) import qualified Haskore.Interface.SuperCollider.Channel as ChannelMng import Haskore.Interface.SuperCollider.Channel
src/Haskore/Interface/SuperCollider/Note.hs view
@@ -12,9 +12,11 @@ import qualified Numeric.NonNegative.Wrapper as NonNeg -import Haskore.General.Utility- (compareRecord, compareField, equalRecord, equalField)+import qualified Data.Record.HT as Record+import Data.Ord.HT (comparing, )+import Data.Eq.HT (equating, ) + data T = Cons { parameters :: [Attribute],@@ -32,15 +34,15 @@ instance Eq T where (==) =- equalRecord- [equalField pitch,- equalField velocity]+ Record.equal+ [equating pitch,+ equating velocity] instance Ord T where compare =- compareRecord- [compareField pitch,- compareField velocity]+ Record.compare+ [comparing pitch,+ comparing velocity] type FromNote dyn note = dyn -> Pitch.Relative -> note -> T
src/Haskore/Interface/SuperCollider/Play.hs view
@@ -25,23 +25,23 @@ -- import Sound.SC3.UGen.UGen (UGen) -import Sound.OpenSoundControl.Transport (Transport) import qualified Sound.OpenSoundControl.Transport.Monad as Trans--- import qualified Sound.OpenSoundControl.Transport.UDP as UDP--- import qualified Sound.OpenSoundControl.UDPMonad as UDP-import Sound.OpenSoundControl.OSC (OSC)+import Sound.OpenSoundControl.OSC (OSC(Bundle))+import qualified Sound.OpenSoundControl.Time as OSCTime + import qualified Haskore.Melody as Melody -- import qualified Haskore.Music.Rhythmic as RhyMusic import qualified Haskore.Music as Music -import qualified Haskore.RealTime.EventList.TimeBody as TimeList+import qualified Haskore.Interface.SuperCollider.Timer as SCTimer+import qualified Haskore.RealTime.Timer as Timer+import qualified Haskore.RealTime.EventList.TimeBody as TimeList -import qualified Haskore.RealTime.Timer as Timer-import qualified Haskore.RealTime.Timer.Thread as TimerThread+import qualified Numeric.NonNegative.Wrapper as NonNeg --- import Control.Monad.Trans (liftIO)--- import Control.Monad (when)+import Control.Monad.Trans (MonadIO, )+import Control.Monad (liftM, ) @@ -83,14 +83,14 @@ Schedule.fromMelody sound -performanceTrans :: Transport t =>+performanceTrans :: (Trans.C m, MonadIO m) => Time -> [OSC] -> SCPf.T Time ->- Trans.IO t ()+ m () performanceTrans latency installMsgs = scheduleWithPlayer- (messagesGrouped TimerThread.timer latency) .+ (messagesGrouped SCTimer.timer latency) . Schedule.fromPerformance installMsgs [] performance ::@@ -110,7 +110,7 @@ schedule latency = SCPlay.withSC3 . scheduleWithPlayer- (messagesGrouped TimerThread.timer latency)+ (messagesGrouped SCTimer.timer latency) shutUp :: IO ()@@ -131,23 +131,23 @@ -- should be moved to Hsc or supercollider-ht timeStamp :: Time -> Time -> [OSC] -> OSC-timeStamp start t = Schedule.timeStamp (start+t)+timeStamp start t = Bundle $ OSCTime.UTCr $ NonNeg.toNumber (start+t) installSound ::- (Transport t, SoundMap.SoundParameters params) =>+ (Trans.C m, SoundMap.SoundParameters params) => String -> Sound params ->- Trans.IO t ()+ m () installSound name instr = SCPlay.simpleSync $ Schedule.installSoundMsg name Schedule.defaultChannel instr -playAtom :: Transport t =>+playAtom :: Trans.C m => SCPlay.NodeId -> String -> [(String,Double)]- -> Trans.IO t ()+ -> m () playAtom sid name params = Trans.send (Schedule.atomPlayMsg sid name params) @@ -186,10 +186,10 @@ -} -scheduleWithPlayer :: Transport t =>- (TimeList.T Time OSC -> Trans.IO t ()) ->+scheduleWithPlayer :: Trans.C m =>+ (TimeList.T Time OSC -> m ()) -> Schedule.T ->- Trans.IO t ()+ m () scheduleWithPlayer player sc = do {- both variants do only work, if only synchronous commands are contained -}@@ -218,12 +218,12 @@ that is, the maximal expected delay of creating and sending messages to the SuperCollider server. -}-messagesGrouped :: Transport t =>- Timer.T ->+messagesGrouped :: (Trans.C m) =>+ Timer.T m -> Time ->- TimeList.T Time OSC -> Trans.IO t ()+ TimeList.T Time OSC -> m () messagesGrouped timer latency =- fmap (const ()) .+ liftM (const ()) . TimeList.runTimeStampGrouped timer (\time -> Trans.send . timeStamp latency time) {-@@ -237,12 +237,12 @@ This results in splitted events which actually should occur at the same time. This makes SuperCollider switching the order messages in certain occasions. -}-messagesGroupedManual :: Transport t =>- Timer.T ->+messagesGroupedManual :: (Trans.C m) =>+ Timer.T m -> Time ->- TimeList.T Time OSC -> Trans.IO t ()+ TimeList.T Time OSC -> m () messagesGroupedManual timer latency =- fmap (const ()) .+ liftM (const ()) . -- (\ pf -> liftIO Timer.getTimeSeconds >>= \startTime -> TimeList.runTimeStamp timer (\time ->@@ -258,22 +258,22 @@ (Trans.send . timeStamp latency time)) -- pf) . TimeList.collectCoincident -messagesSingly :: Transport t =>- Timer.T ->+messagesSingly :: (Trans.C m) =>+ Timer.T m -> Time ->- TimeList.T Time OSC -> Trans.IO t ()+ TimeList.T Time OSC -> m () messagesSingly timer latency =- fmap (const ()) .+ liftM (const ()) . TimeList.runTimeStamp timer (\time -> -- (liftIO $ print $ eventToMark e) >> (Trans.send . timeStamp latency time . (:[]))) -messagesSimple :: Transport t =>- Timer.T ->+messagesSimple :: (Trans.C m) =>+ Timer.T m -> TimeList.T Time OSC ->- Trans.IO t ()+ m () messagesSimple timer =- fmap (const ()) .+ liftM (const ()) . TimeList.run timer Trans.send
src/Haskore/Interface/SuperCollider/Play/Channel.hs view
@@ -20,8 +20,7 @@ import Sound.OpenSoundControl.Transport (Transport) import Sound.OpenSoundControl.Transport.UDP (UDP)-import Sound.OpenSoundControl.Transport.File (File)-import qualified Sound.OpenSoundControl.Transport.Monad as Trans+import qualified Sound.OpenSoundControl.Transport.File as File import qualified Haskore.Interface.SuperCollider.Channel.State as ChannelState import qualified Haskore.Interface.SuperCollider.Channel as Channel@@ -45,14 +44,15 @@ import Haskore.Music.Rhythmic (qn) import Haskore.Melody as Melody -import qualified Haskore.RealTime.Timer.Thread as TimerThread--- import qualified Haskore.RealTime.Timer.Immediate as TimerImmediate+import qualified Haskore.Interface.SuperCollider.Timer as SCTimer import qualified Haskore.General.IdGenerator as IdGen -import qualified Control.Monad.State as State-import Control.Monad.State (StateT, evalStateT, lift, liftM2)-import Control.Monad.Reader (ReaderT)+import qualified Control.Monad.Trans.State as State+import Control.Monad.Trans.State (StateT, evalStateT, )+import Control.Monad.Trans.Reader (ReaderT, )+import Control.Monad.Trans (lift, )+import Control.Monad (liftM2, ) @@ -122,7 +122,7 @@ always adds new nodes to the head. This way, the effect is run after the instrument nodes. -} Play.scheduleWithPlayer- (Play.messagesGrouped TimerThread.timer Play.defaultLatency)+ (Play.messagesGrouped SCTimer.timer Play.defaultLatency) (Schedule.fromPerformance [Schedule.installUGenMsg effectsName Schedule.defaultChannel effect]@@ -135,7 +135,7 @@ run act = SCPlay.withSC3 (evalStateT act Channel.least) -writeScript :: FilePath -> Environment File a -> IO a+writeScript :: FilePath -> Environment File.T a -> IO a writeScript fn act = SCPlay.withSC3File fn (evalStateT act Channel.least)
src/Haskore/Interface/SuperCollider/Play/Install.hs view
@@ -16,7 +16,6 @@ import Sound.SC3.UGen.UGen (UGen) -import Sound.OpenSoundControl.Transport (Transport) import qualified Sound.OpenSoundControl.Transport.Monad as Trans import Haskore.Interface.SuperCollider.Schedule.Install@@ -37,48 +36,49 @@ import qualified Haskore.Music as Music import Haskore.Melody as Melody +import Control.Monad.Trans (MonadIO, ) installSound ::- (Transport t, SoundMap.SoundParameters params) =>+ (Trans.C m, SoundMap.SoundParameters params) => (parameterTuple -> AttributeList, graph -> SoundMap.Sound params) -> String -> graph ->- Trans.IO t (Sound params parameterTuple)+ m (Sound params parameterTuple) installSound (makeAttributeList, makeSoundUGen) name instr = Play.installSound name (makeSoundUGen instr) >> return (Sound name makeAttributeList) installSound0 ::- (Transport t, SoundMap.SoundParameters params) =>+ (Trans.C m, SoundMap.SoundParameters params) => String -> SoundMap.Sound params ->- Trans.IO t (Sound params ())+ m (Sound params ()) installSound0 = installSound SoundMap.with0Attributes installSound1 ::- (Transport t, SoundMap.SoundParameters params) =>+ (Trans.C m, SoundMap.SoundParameters params) => String -> (UGen -> SoundMap.Sound params) ->- Trans.IO t (Sound params Double)+ m (Sound params Double) installSound1 = installSound SoundMap.with1Attribute installSound2 ::- (Transport t, SoundMap.SoundParameters params) =>+ (Trans.C m, SoundMap.SoundParameters params) => String -> (UGen -> UGen -> SoundMap.Sound params) ->- Trans.IO t (Sound params (Double,Double))+ m (Sound params (Double,Double)) installSound2 = installSound SoundMap.with2Attributes -playMusic :: Transport t =>- RhyMusic.T DrumAttributes InstrumentAttributes -> Trans.IO t ()+playMusic :: (Trans.C m, MonadIO m) =>+ RhyMusic.T DrumAttributes InstrumentAttributes -> m () playMusic = Play.performanceTrans Play.defaultLatency [] . SCPf.fixNodeIds .
src/Haskore/Interface/SuperCollider/Play/Life.hs view
@@ -59,7 +59,7 @@ import qualified Haskore.Basic.Duration as Dur import Haskore.Basic.Duration ((%+)) -import qualified Haskore.RealTime.Timer.Thread as TimerThread+import qualified Haskore.Interface.SuperCollider.Timer as SCTimer import qualified Haskore.General.IdGenerator as IdGen @@ -152,7 +152,7 @@ let numChan = SCPlay.mceDegree ugen chan <- Channel.next ChannelEnv.manager numChan SCPlay.withSC3 $- SCPlay.simpleSync $ SCPlay.d_recv' name $+ SCPlay.simpleSync $ SCPlay.d_recv_synthdef name $ SCIO.out (SCUGen.Constant (fromIntegral chan)) ugen return (chan, numChan) @@ -226,7 +226,7 @@ always adds new nodes to the head. This way, the effect is run after the instrument nodes. -} Play.scheduleWithPlayer- (Play.messagesGrouped TimerThread.timer Play.defaultLatency)+ (Play.messagesGrouped SCTimer.timer Play.defaultLatency) (Schedule.fromPerformance [Schedule.installUGenMsg effectsName Schedule.defaultChannel effect]@@ -268,14 +268,14 @@ -} playKeyboard :: ISched.Instrument () -> IO () playKeyboard instr =- let recurse =+ let recourse = do char <- getChar if char == '\004' then putStrLn "" else do putChar '\008' playKey instr char- recurse- in recurse+ recourse+ in recourse
src/Haskore/Interface/SuperCollider/Render.hs view
@@ -8,6 +8,7 @@ import qualified Haskore.Interface.SuperCollider.Schedule as Schedule import qualified Haskore.Interface.SuperCollider.Play as Play +import Haskore.Interface.SuperCollider.Schedule (Time) import Haskore.Interface.SuperCollider.SoundMap (Instrument) import qualified Sound.SC3.Server.NRT as SCNRT@@ -16,12 +17,20 @@ -- import Sound.OpenSoundControl.Transport (Transport) -- import qualified Sound.OpenSoundControl.Transport.Monad as Trans +import Sound.OpenSoundControl.OSC (OSC(Bundle))+import qualified Sound.OpenSoundControl.Time as OSCTime+ import qualified Data.ByteString.Lazy as B import qualified Haskore.Melody as Melody import qualified Haskore.RealTime.Timer.Immediate as TimerImmediate+import qualified Haskore.RealTime.EventList.TimeBody as TimeList +import qualified Data.EventList.Absolute.TimeBody as AbsoluteEventList++import qualified Numeric.NonNegative.Wrapper as NonNeg+ import System.Cmd (rawSystem) import System.Exit (ExitCode) @@ -92,6 +101,25 @@ byteStringFromSchedule :: Schedule.T -> B.ByteString byteStringFromSchedule =- SCNRT.encodeNRT .- Schedule.toStream+ SCNRT.encodeNRT . scheduleToStream +scheduleToStream ::+ Schedule.T ->+ [OSC]+scheduleToStream sc =+ timeStamp 0 (Schedule.initial sc) :+ messagesToStream (Schedule.body sc)++messagesToStream ::+ TimeList.T Time OSC ->+ [OSC]+messagesToStream =+ map (uncurry timeStamp) .+ AbsoluteEventList.toPairList .+ {- first absolutize, then collectCoincident in order to catch+ coincidences caused by rounding -}+ AbsoluteEventList.collectCoincident .+ TimeList.toAbsoluteEventList 0++timeStamp :: Time -> [OSC] -> OSC+timeStamp = Bundle . OSCTime.NTPr . NonNeg.toNumber
src/Haskore/Interface/SuperCollider/Schedule.hs view
@@ -9,13 +9,9 @@ -- for Play module installUGenMsg, installSoundMsg, defaultChannel, atomPlayMsg,- timeStamp, - -- for Render module- toStream,- -- for suppression of "unused" warnings :-)- fromMusicMsgs, messagesToStream, eventToMark,+ fromMusicMsgs, eventToMark, -- testing -- fromMelodyPerformance,@@ -28,9 +24,7 @@ import Sound.SC3.UGen.UGen (UGen) --- import qualified Sound.OpenSoundControl.Transport.UDP as UDP--- import qualified Sound.OpenSoundControl.UDPMonad as UDP-import Sound.OpenSoundControl.OSC (OSC(Bundle))+import Sound.OpenSoundControl.OSC (OSC) import qualified Haskore.Interface.SuperCollider.Note as Note import qualified Haskore.Interface.SuperCollider.Performance as SCPf@@ -46,17 +40,16 @@ import qualified Haskore.Music as Music import qualified Haskore.Performance.BackEnd as PfBE-import qualified Haskore.RealTime.EventList.TimeBody as TimeList+import qualified Haskore.RealTime.EventList.TimeBody as TimeList import qualified Haskore.RealTime.EventList.TimeTime as TimeListPad-import qualified Data.EventList.Absolute.TimeBody as AbsoluteEventList import qualified Haskore.General.IdGenerator as IdGen import qualified Numeric.NonNegative.Wrapper as NonNeg -import Control.Monad (liftM2)+import Control.Monad (liftM2, ) -import Data.Maybe(fromMaybe,maybeToList)+import Data.Maybe(fromMaybe, maybeToList, ) {- * Schedule data structure -}@@ -235,32 +228,7 @@ TimeListPad.mapBody (uncurry eventToMsg) -toStream ::- T ->- [OSC]-toStream sc =- timeStamp 0 (initial sc) :- messagesToStream (body sc) -messagesToStream ::- TimeList.T Time OSC ->- [OSC]-messagesToStream =- map (uncurry timeStamp) .- AbsoluteEventList.toPairList .- {- first absolutize, then collectCoincident in order to catch- coincidences caused by rounding -}- AbsoluteEventList.collectCoincident .- TimeList.toAbsoluteEventList 0--timeStamp :: Time -> [OSC] -> OSC-timeStamp = Bundle . NonNeg.toNumber------ {- * Construction of OpenSoundControl messages -} stopMsg :: OSC@@ -289,7 +257,7 @@ UGen -> OSC installUGenMsg name chan =- SCPlay.d_recv' name .+ SCPlay.d_recv_synthdef name . Channel.writeUGen chan installSoundMsg ::
src/Haskore/Interface/SuperCollider/Schedule/Channel.hs view
@@ -42,9 +42,11 @@ import qualified Haskore.General.IdGenerator as IdGen -import qualified Control.Monad.State as State-import Control.Monad.State (StateT, runStateT, lift, liftM2, get, put)-import Control.Monad.Writer (Writer, tell, runWriter)+import qualified Control.Monad.Trans.State as State+import Control.Monad.Trans.State (StateT, runStateT, get, put, )+import Control.Monad.Trans.Writer (Writer, tell, runWriter, )+import Control.Monad.Trans (lift, )+import Control.Monad (liftM2, )
src/Haskore/Interface/SuperCollider/Schedule/Install.hs view
@@ -28,7 +28,7 @@ import Haskore.Melody as Melody -import Control.Monad.Writer (MonadWriter, Writer, tell, runWriter)+import Control.Monad.Trans.Writer (Writer, tell, runWriter)
src/Haskore/Interface/SuperCollider/SoundMap.hs view
@@ -13,8 +13,8 @@ import Sound.SC3.UGen.UGen (UGen) -import Haskore.General.Utility (toMaybe)-import Data.Maybe (mapMaybe)+import Data.Maybe.HT (toMaybe, )+import Data.Maybe (mapMaybe, ) {- * Generic definitions -}
+ src/Haskore/Interface/SuperCollider/Timer.hs view
@@ -0,0 +1,10 @@+module Haskore.Interface.SuperCollider.Timer where++import qualified Haskore.RealTime.Timer as Timer+import qualified Haskore.RealTime.Timer.Thread as TimerThread++import Control.Monad.Trans (MonadIO, )+++timer :: MonadIO io => Timer.T io+timer = Timer.liftIO TimerThread.timer