# Week 7 Lesson 3 - Composing tracks with the 'ur' function

Here's an introduction to the 'ur' function, which lets you make patterns out of patterns, to make a track. I also talk about issues with 'orbits' and global effects (e.g. reverb, delay) you might have when using `ur`, `seqPLoop` and `stack`. This is still an area of Tidal that could be developed, so I'd be happy to have your ideas about possible features/improvements.

Here's the pattern I deconstruct:

``````d1 \$ ur 16 "[bdsd, ~ claps, ~ [bass bass:crunch] ~ bass]"
[("bdsd", sound "bd [~ sd] bd sd" # squiz 2),
("claps", sound "clap:4*2 clap:4*3"
# delay 0.8 # dt "t" # dfb 0.4
# orbit 4 # speed 4
),
("bass", struct "t(3,8)" \$ sound "dbass" # shape 0.7 # speed "[1, ~ 2]")
]
[("crunch", (# crush 3))
]
``````
13 Likes

thank you alex! that ur seems even more...neat than seqP

alright...i'm german so i'll do a bit of germaning:
you're quite right, "ur-" means something that's higher than something else,
but in value-'cause-it's-older-so-to-say- A N C I E N T, not in height

so...there's plenty o' fish in the sea, but there's only one UR F I S H left, see:
Quastenflosser

the austrians have a quite charming way to express the feeling of being well and cosy when all things align in space/time: leiwand
the superlative of leiwand, like when all that cosy space/time warps into a perfectly traversable wormhole of well-being is: UR L E I W A N D

which is how i feel here, and hopefully soon in tidalcycles as well, cheers

ps: oh dear, i only now realized:
this is just a form of appreciation of conservatism baked into and dragged along in language

9 Likes

@dtlvdoom Brilliant explanation,

small complement:
Ursprung -> Ur-sprung = origin, genesis, source;

3 Likes

When I called the orbits "orbits" I thought at first of the cause of tidalcycles of course. But the idea that caught on was:

things on different orbits are independent and drift past each other.

5 Likes

This is super useful even for live performance!
The fact that you're not able to hear what you're working immediately is a blessing I thin.
Sometimes it requires a lot of agility to turn every second channels off when you want to introduce a rapid change, sequencing it out in a pattern of patterns definitely helps.

• Is it possible to layer two effects on top of another inside of the metapattern?
I've tried
``ur "pat1:fx1:fx2"``

in this case only fx1 seems to work, guess you can always define effects as composite functions separately.

• I'm not sure if I correctly understand the syntax of the metapattern.
When it comes to division of the number of cycles we give to the `ur` function, if we have a pattern `ur 4 "pat1 pat2"` it seems to divide it evenly between them (each gets two cycles out).
For `ur 8 "[pat1, ~ pat2]` pat2 will only play on cycles 5-8.
Not sure what happens if we slow the pattern down or speed it up though.
1 Like

You have no idea how much I've been waiting for that lesson, thank you so much !

I have one related issue (user error I bet ;)) : `ur` works perfectly, as expected... except for the fact that I can't find a way to have several cycle long patterns, say a 4 bar long bassline, to start at their respective beginning. I've tried using `resetCycles`, `reset` and `trigger`, but I can't get constant results. Any tip ? Cheers !

1 Like

No not currently. I could think about adding that.. Right now you'd have to make an fx3 that does both fx1 and fx2.

Yes `pat1` and `~ pat2` are layered up as subpatterns. So `pat2` is only active for the second half. There's lots on the mininotation in week 1: Week 1 - mini-notation - Tidal Club

2 Likes

Hm, here's a version of `ur` called `ur'` that plays each pattern from cycle 0, is that better?

``````import Data.Maybe (fromMaybe)

import Sound.Tidal.Utils (wordsBy)

ur' :: Time -> Pattern String -> [(String, Pattern a)] -> [(String, Pattern a -> Pattern a)] -> Pattern a
ur' t outer_p ps fs = _slow t \$ unwrap \$ adjust <\$> timedValues (getPat . split <\$> outer_p)
where split = wordsBy (==':')
getPat (s:xs) = (match s, transform xs)
-- TODO - check this really can't happen..
getPat _ = error "can't happen?"
match s = fromMaybe silence \$ lookup s ps'
ps' = map (fmap (_fast t)) ps
adjust (a, (pat, f)) = rotR (start a) \$ f a pat
transform (x:xs) a pat = transform xs a \$ transform' x a pat
transform _ _ pat = pat
transform' str (Arc s e) p = inside (pure \$ 1/(e-s)) (matchF str) p
matchF str = fromMaybe id \$ lookup str fs
timedValues = withEvent (\(Event c (Just a) a' v) -> Event c (Just a) a' (a,v)) . filterDigital
``````
2 Likes

Thanks Alex !

Unfortunately it doesn't seem to work either. I get a bit more of predictability / consistency if throwing a `reset 1` in the mix, but then it seems like the bassline starts at its second cycle, rather than at its begining.

The incriminated melodic sequence is something like :

`struct "[t(3,8,<0 2>)]!2" \$ n (toScale [0,1,3,5,7,8,10] "<[0 1 2! 0 1 2] [3 4 5! 3 4 5]>") # s "midi"`

Thanks again !

If you can make a simplified example, demonstrating what you expect vs what happens, I can look into it

Hello @yaxu,

I have a question related to patterning chords but did't know if this lesson is the right place post it (I can change it if not).
The point is I am trying to use ur to create a melody (here a simplified example):

let parts =
[
("a", n "c'maj" # s "superpiano"),
("b", n "a'maj" # s "superpiano"),
("c", n "f'maj" # s "superpiano")
]
in
d1 \$ ur 3 "a b c" parts []

but I'd like that Tidal started playing at the beginning. I tried with "trigger" and "qtrigger" functions but doesn't seem to work. (d1 \$ trigger \$ ur 3 "a b c" parts []). Is there an alternative?

Additionally, is there a way to play it just once? (if you use once instead of d1 it plays just "a".

Hi @yago,

I moved this to the lesson on `ur` in particular.

Here's some way towards this:

``````
let parts = [
("a", n "c'maj" # s "superpiano"),
("b", n "a'maj" # s "superpiano"),
("c", n "f'maj" # s "superpiano")
]
playFor c pat = seqP [(0, c, pat)]
urOnce c pat parts fs = playFor c \$ ur c pat parts fs
in
d1 \$ qtrigger 1 \$ urOnce 3 "a b c" parts []
``````

You have to say which 'channel' you're triggering with `qtrigger`. I had to define a new function `urOnce` to only play the pattern through once. One problem is that if you've just missed the start of a cycle, qtrigger will miss off the start of the pattern.. Hmm.

You can also use `trigger` instead of `qtrigger` but that won't align with anything else that's playing.

2 Likes

Please bare the sheer absence of musicality of that example, hopefully it'll successfully illustrate what I aim for : I'd love to find a way to have the whole block starting with `superpiano`'s lowest C note, with the slowest / simplest rhythm (that is, `mel1`). Can't make it work each and every time.

``````do
let
pat1 = "t*4"
pat2 = "t([5 6],16,<0!! [0 2]>)"
mel = "<[<-7 0!3> ~] [1 3 5 7]>"
mel1 = struct pat1 \$ n (toScale [0,1,3,5,7,8,10] mel) # s "superpiano" # amp 0.333
mel2 = struct pat2 \$ n (toScale [0,1,3,5,7,8,10] mel) # s "superpiano" # amp 0.333
poomtchack = stack [struct "t(3,8)" \$ s "808bd" , struct "[ft]*2" \$ s "808sd"] #amp 0.75
techno = stack [struct "t*4" \$ s "808bd" , struct "[ft]!4" \$ s "808hh"] #amp 0.75
d1 \$
ur' 8 "a b"
[ ("a", poomtchack),
("b", techno)]
[]
d2 \$
ur' 8 "1 2"
[ ("1", mel1),
("2", mel2)]
[]
``````

Thanks !

This is amazing! I've always wondered if it was possible to use tidal in a more "offline" mode to make full tracks. Definitely going to explore this!

1 Like

Interesting function, but it's a bit hard to sequence multiple patterns at once isn't it?

I know you can do it using a comma, but things gets complicated, at least in my head. On first glance seqPLoop seems more easy for this.
I'm pretty new at digital music, but I assume people wants to build up tunes by layering patterns and turn them off/solo. So for making tracks it's an important function, which I'll explore further.

Hello,

When I run the code from this lesson I get the following error. I had a look around the forum and it looks like either a Tidal package error or a Cabal error? In Atom everything seems up to date so I'm guessing it's the later?

``````t>
β’ Variable not in scope: dt :: Double -> Pattern ControlMap
β’ Perhaps you meant one of these:
βd1β (line 43), βqtβ (imported from Sound.Tidal.Context),
βdetβ (imported from Sound.Tidal.Context)

Variable not in scope: dfb :: Double -> Pattern ControlMap``````

What's the specific code you're trying to run? It looks to me like a type `dt` - when in fact you meant `do` or `d1`

Hi cleary,

Thanks for getting back to me. I was trying to run @yaxu's code from above. I think `dt` is 'delay time' in this instance.

``````d1 \$ ur 16 "[bdsd, ~ claps, ~ [bass bass:crunch] ~ bass]"
[("bdsd", sound "bd [~ sd] bd sd" # squiz 2),
("claps", sound "clap:4*2 clap:4*3"
# delay 0.8 # dt "t" # dfb 0.4
# orbit 4 # speed 4
),
("bass", struct "t(3,8)" \$ sound "dbass" # shape 0.7 # speed "[1, ~ 2]")
]
[("crunch", (# crush 3))
]``````

Ah, yes if I recall he mentioned that it was a shortcut being added to newer versions of tidal (you may be running an older ver). You can also use `delayt` and `delayfb` I believe

Ah yes, for now you could make aliases by running e.g.:

``````let dt = delaytime
dfb = delayfeedback
``````
1 Like