Tidal icon indicating copy to clipboard operation
Tidal copied to clipboard

setCycle, similar to resetCycle but for jumping to a specific cycle

Open jarmitage opened this issue 3 years ago • 5 comments

import qualified Sound.Tidal.Tempo as T

_setCycle c tempoMV = T.changeTempo tempoMV (\t tempo -> tempo {T.atTime = t, T.atCycle = c})

streamSetCycle c s = do _ <- _setCycle c (sTempoMV s)
                        return ()

setCycle c = streamSetCycle c stream

d1 $ s "bd"

setCycle 10

setCycle 100

setCycle 50

setCycle 150

If you run the above, what you'll notice is that jumping backwards by n cycles seems to work fine, however jumping forwards results in a lot of messages being sent before normal service is resumed.

I'll post an OSC log or two here soon to demonstrate...

jarmitage avatar Sep 02 '20 22:09 jarmitage

To work out what to query the pattern for, tidal first works out what the end of the time arc should be, based on the tempo. Rather than work out the start of the time arc, it just takes the end of the previous time arc. This is so that nothing is lost due to floating point error (cps is still floating point rather than rational), or due to the tempo changing.

This seems to works fine if travelling back in time, I guess because you end up with an arc that ends before it begins and returns nothing, so you lose one tick (1/20th of a second)'s worth of events (that might possibly explain while resetCycles misses the start of the cycle..). It doesn't work if travelling forward in time, because you can end up with a very large arc.

The scheduler does skip frames if it gets too far behind/ahead, but not cycles. I think it's not straightforward to do that, as probably extreme changes in tempo would legitimately result in a large number of cycles being generated..

I think the fix would be adding a flag to the tempo datatype to indicate that the tempo has been reset and that the ticks should too.

yaxu avatar Sep 02 '20 22:09 yaxu

that might possibly explain while resetCycles misses the start of the cycle..

Ah ha!

That all totally makes sense, thanks for explaining. So we're looking for a resetTicks function to go along with this?

jarmitage avatar Sep 03 '20 06:09 jarmitage

That all totally makes sense, thanks for explaining. So we're looking for a resetTicks function to go along with this?

Yes, although that would probably be an internal function, called from within resetCycles / setCycle

yaxu avatar Sep 03 '20 09:09 yaxu

I think the fix would be adding a flag to the tempo datatype to indicate that the tempo has been reset and that the ticks should too.

Just coming back to this. Why is the tempo being reset? Isn't it just the cycles that are being reset/changed?

jarmitage avatar Sep 19 '20 17:09 jarmitage

So something like this?

Add reset flag here:

data Tempo = Tempo {atTime  :: O.Time,
                    atCycle :: Rational,
                    cps     :: O.Time,
                    paused  :: Bool,
                    nudged  :: Double,
                    localUDP   :: O.UDP,
                    remoteAddr :: N.SockAddr,
                    synched :: Bool,
                    reset:: Bool
                   }
  deriving Show

Set flag to True when using _setCycle:

_setCycle c tempoMV = T.changeTempo tempoMV (\t tempo -> tempo {T.atTime = t, T.atCycle = c, reset = True})

Watch for flag in clocked, reset ticks if needed, then reset flag. I don't know how to do this part :)

jarmitage avatar Sep 19 '20 17:09 jarmitage