Loop or Freeze Cycles?

I often use patches that involve randomness and it would be great to find a way to loop or freeze cycles to let them play for a while. repeatCycles does this but I often want to repeat more than one cycle, so I think I'm looking for a function like repeatCycles but lets you define how many cycles you'd like to repeat. Any ideas?

I found this thread, which seems related, but not totally applicable as far as I can tell:

Thanks.

yeah like maybe some way to extend linger beyond 1...like, d1 $ linger 4 $ complexRandomPattern

1 Like

If you have a function like repeatCycles that only works on one cycle, but you'd like to make it work on more, then you can use fast and slow in combination like this:

slow 2 $ repeatCycles 2 $ fast 2 $ ...

That would repeat every two cycles, twice.

There's a helper function outside that makes this easier:

outside 2 (repeatCycles 2) $ ...

Ahhhh, so beautifully simple. Thanks Alex!

Hey @yaxu... Another question for you (or anyone really!):

With the goal of being able to loop what's currently playing in an evolving pattern, I've been using outside 2 (repeatCycles 2) commented out, then placed in and re-evaluted when I want to loop. The problem with that is that I'm always behind and the currently playing pattern has changed by time repeatCycles has been triggered.

Is there a way to freeze/loop what's currently playing, and not what's coming up next? I thought about assigning OSC to control repeatCycles but I run into the issue of nothing playing if I enter repeatCycles 0.

Any thoughts?
Thanks!

Heh I love questions in the 'how to do this obvious thing which tidal can't do' category.

I can see why the outside / repeatCycles isn't doing what you want. The way outside works means manipulates time, so you end up in a different part of the timeline, so the same bit doesn't loop.

Try this:

import qualified Data.Map.Strict as Map

freezeloop :: Show a => a -> Pattern Time -> IO ()
freezeloop ident loops = do now <- (toRational . floor) <$> getnow
                            pats <- MV.readMVar $ sPMapMV tidal
                            let pat = Map.lookup (show ident) pats
                            maybe (putStrLn $ "No pattern with ident " ++ show ident) 
                                  (p ident . timeLoop loops . rotL now . pattern)
                                  pat

Then this works:

d1 $ stack [sound "newnotes*8" # speed (rand + 1),
            sound "cp"
           ]

-- freeze pattern with ident 1, loop two cycles starting from the current one:  
freezeloop 1 2

Have a play to see how that feels but I have a feeling we'll need some modulo to really get the cycles you want looping

1 Like

This might be a more flexible approach:

import qualified Data.Map.Strict as Map
import qualified Control.Concurrent.MVar as MV

grab :: Show a => a -> IO ControlPattern
grab ident = do now <- floor <$> getnow
                putStrLn $ "Grabbing pattern " ++ show ident ++ " at cycle " ++ show now
                pats <- MV.readMVar $ sPMapMV tidal
                let pat = Map.lookup (show ident) pats
                return $ maybe (error $ "No pattern with ident " ++ show ident) 
                               (rotL (toRational now) . pattern)
                               pat

Then you can do:

pat <- grab 1

And once you have it you can play around with it at will:

d1 $ timeLoop 4 $ pat -- loop from the cycle you grabbed
d1 $ timeLoop 2 $ pat -- switch to looping just two cycles
d1 $ timeLoop 4 $ rotL 1 pat -- loop from the cycle before

It will also print out the cycle number so you can return to it at a future session if you want using e.g. rotL and resetCycles. There are no real random numbers, Tidal is totally deterministic so it'll be exactly the same each session.

2 Likes

I was/am really interested of the above, but I get this error on both versions:

t>
Not in scope: ‘MV.readMVar’
No module named ‘MV’ is imported.

Ha. Thanks so much @yaxu !!
I'm afraid I'm getting the same errors as @pyrrhic however.

Oops will update the above but it needs a:

import qualified Control.Concurrent.MVar as MV
1 Like

Thanks Alex!
That cleared up the MV error.

I'm getting another one when evaluating: grab :: Show a => a -> IO ControlPattern (and the larger block with grab below it) that says:

error: Warning: GHCi | Variable not in scope: grab :: a1 -> IO ControlPattern

Any ideas about that error? I wonder if I'm not evaluating the block correctly?

Funny, I get different errors on the same ...

These are ok:

import qualified Data.Map.Strict as Map
import qualified Control.Concurrent.MVar as MV

But this:

grab :: Show a => a -> IO ControlPattern
grab ident = do now <- floor <$> getnow
putStrLn $ "Grabbing pattern " ++ show ident ++ " at cycle " ++ show now
pats <- MV.readMVar $ sPMapMV tidal
let pat = Map.lookup (show ident) pats
return $ maybe (error $ "No pattern with ident " ++ show ident)
(rotL (toRational now) . pattern)
pat

Gives:

t>
Variable not in scope: getnow :: IO Double

I get that same error if I evaluate that whole block in one go vs just the first line, FWIW.

Ah, ok, good observation.

Ok looking a bit closer I think the problem with the lack of MV and getnow, is that you are supercool people with custom BootTidal.hs, and that's had a couple of things added to it.

You're probably missing a couple of things from the 'stock' BootTidal.hs:
https://github.com/tidalcycles/Tidal/blob/main/BootTidal.hs

If you copy across that big block of defines in the middle (replacing the one you have already, unless you have made edits there..) then put the import qualified Control.Concurrent.MVar as MV at the top, you should be good to go.. and also have the handy panic command

1 Like

Ha! Yeah, that was totally it.
(And yes, I'm so cool idk how to fix code :sunglasses:)

My first test with this are really great, thanks Alex! I love being able to play with and switch up the loops. I'm going to play around and digest it, but so far soooo good.

Speaking of (super cool) custom BootTidal's, hopefully there's no harm in sticking this new stuff in there, cause that's what I'm gonna do right now lol.

Yep I'll be adding it there shortly myself!

1 Like

2 posts were split to a new topic: Ambiguous module name

I did the above and ended up with this:

t> /Users/a/.atom/packages/tidalcycles/lib/BootTidal.hs:13:13: error:
Variable not in scope: hush :: m a0
|
13 | let only = (hush >>)
| ^^^^

I have now broken the Tidalcycles installs on 2 out of 3 computers :joy: :skull:

I guess you have things in the wrong order, or have missed something.. I'd just start again with a fresh BootTidal.hs