Skip to content

Commit

Permalink
introduce additional session state in doTick to only handle tempo cha…
Browse files Browse the repository at this point in the history
…nges happening during the querying of patterns (via cps parameter)
  • Loading branch information
polymorphicengine committed Jun 19, 2024
1 parent 81c1987 commit 5e09ab8
Show file tree
Hide file tree
Showing 2 changed files with 15 additions and 11 deletions.
18 changes: 10 additions & 8 deletions src/Sound/Tidal/Stream/Process.hs
Original file line number Diff line number Diff line change
Expand Up @@ -88,9 +88,9 @@ doTick :: MVar ValueMap -- pattern state
-> Double -- nudge
-> Clock.ClockConfig -- config of the clock
-> Clock.ClockRef -- reference to the clock
-> Link.SessionState
-> (Link.SessionState, Link.SessionState) -- second session state is for keeping track of tempo changes
-> IO ()
doTick stateMV busMV playMV globalFMV cxs listen (st,end) nudge cconf cref ss =
doTick stateMV busMV playMV globalFMV cxs listen (st,end) nudge cconf cref (ss, temposs) =
E.handle (\ (e :: E.SomeException) -> do
hPutStrLn stderr $ "Failed to Stream.doTick: " ++ show e
hPutStrLn stderr $ "Return to previous pattern."
Expand All @@ -112,7 +112,7 @@ doTick stateMV busMV playMV globalFMV cxs listen (st,end) nudge cconf cref ss =
)
-- Then it's passed through the events
(sMap'', es') = resolveState sMap' es
tes <- processCps cconf cref ss es'
tes <- processCps cconf cref (ss, temposs) es'
-- For each OSC target
forM_ cxs $ \cx@(Cx target _ oscs _ _) -> do
-- Latency is configurable per target.
Expand All @@ -124,8 +124,8 @@ doTick stateMV busMV playMV globalFMV cxs listen (st,end) nudge cconf cref ss =
hPutStrLn stderr $ "Failed to send. Is the '" ++ oName target ++ "' target running? " ++ show e
putMVar stateMV sMap'')

processCps :: Clock.ClockConfig -> Clock.ClockRef -> Link.SessionState -> [Event ValueMap] -> IO [ProcessedEvent]
processCps cconf cref ss = mapM processEvent
processCps :: Clock.ClockConfig -> Clock.ClockRef -> (Link.SessionState, Link.SessionState) -> [Event ValueMap] -> IO [ProcessedEvent]
processCps cconf cref (ss, temposs) = mapM processEvent
where
processEvent :: Event ValueMap -> IO ProcessedEvent
processEvent e = do
Expand All @@ -140,7 +140,7 @@ processCps cconf cref ss = mapM processEvent
onPart <- Clock.timeAtBeat cconf ss partStartBeat
when (eventHasOnset e) (do
let cps' = Map.lookup "cps" (value e) >>= getF
maybe (return ()) (\newCps -> Clock.setTempoCPS newCps on cconf ss) (fmap toRational cps')
maybe (return ()) (\newCps -> Clock.setTempoCPS newCps on cconf temposs) (fmap toRational cps')
)
off <- Clock.timeAtBeat cconf ss offBeat
bpm <- Clock.getTempo ss
Expand Down Expand Up @@ -294,6 +294,7 @@ hasSolo = (>= 1) . length . filter psSolo . Map.elems
onSingleTick :: Clock.ClockConfig -> Clock.ClockRef -> MVar ValueMap -> MVar [Int] -> MVar PlayMap -> MVar (ControlPattern -> ControlPattern) -> [Cx] -> Maybe O.Udp -> ControlPattern -> IO ()
onSingleTick clockConf clockRef stateMV busMV _ globalFMV cxs listen pat = do
ss <- Clock.getZeroedSessionState clockConf clockRef
temposs <- Clock.getSessionState clockRef
pMapMV <- newMVar $ Map.singleton "fake"
(PlayState {psPattern = pat,
psMute = False,
Expand All @@ -302,8 +303,9 @@ onSingleTick clockConf clockRef stateMV busMV _ globalFMV cxs listen pat = do
}
)
-- The nowArc is a full cycle
doTick stateMV busMV pMapMV globalFMV cxs listen (0,1) 0 clockConf clockRef ss

doTick stateMV busMV pMapMV globalFMV cxs listen (0,1) 0 clockConf clockRef (ss, temposs)
Link.destroySessionState ss
Link.commitAndDestroyAppSessionState (Clock.rAbletonLink clockRef) temposs


-- Used for Tempo callback
Expand Down
8 changes: 5 additions & 3 deletions tidal-link/src/hs/Sound/Tidal/Clock.hs
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ data ClockConfig
-- | action to be executed on a tick,
-- | given the current timespan, nudge and reference to the clock
type TickAction
= (Time,Time) -> Double -> ClockConfig -> ClockRef -> Link.SessionState -> IO ()
= (Time,Time) -> Double -> ClockConfig -> ClockRef -> (Link.SessionState, Link.SessionState) -> IO ()

-- | possible actions for interacting with the clock
data ClockAction
Expand Down Expand Up @@ -183,7 +183,7 @@ clockProcess = do
sessionState <- liftIO $ Link.createAndCaptureAppSessionState abletonLink
endCycle <- liftIO $ timeToCycles config sessionState logicalEnd

liftIO $ action (startCycle,endCycle) (nudged st) config ref sessionState
liftIO $ action (startCycle,endCycle) (nudged st) config ref (sessionState, sessionState)

liftIO $ Link.commitAndDestroyAppSessionState abletonLink sessionState

Expand Down Expand Up @@ -228,6 +228,9 @@ beatToCycles config beat = beat / (coerce $ cBeatsPerCycle config)
cyclesToBeat :: ClockConfig -> Double -> Double
cyclesToBeat config cyc = cyc * (coerce $ cBeatsPerCycle config)

getSessionState :: ClockRef -> IO Link.SessionState
getSessionState (ClockRef _ abletonLink) = Link.createAndCaptureAppSessionState abletonLink

-- onSingleTick assumes it runs at beat 0.
-- The best way to achieve that is to use forceBeatAtTime.
-- But using forceBeatAtTime means we can not commit its session state.
Expand All @@ -236,7 +239,6 @@ getZeroedSessionState config (ClockRef _ abletonLink) = do
ss <- Link.createAndCaptureAppSessionState abletonLink
nowLink <- liftIO $ Link.clock abletonLink
Link.forceBeatAtTime ss 0 (nowLink + processAhead) (cQuantum config)
Link.destroySessionState ss
return ss
where processAhead = round $ (cProcessAhead config) * 1000000

Expand Down

0 comments on commit 5e09ab8

Please sign in to comment.