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

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

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 :slight_smile:

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.

Two things I'm curious about:

  • 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 :slight_smile:

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".

Thanks for your help!

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! :slight_smile:

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?

Thanks in advance!

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

thanks!