Tidal icon indicating copy to clipboard operation
Tidal copied to clipboard

unexpected "skip" messages

Open kindohm opened this issue 3 years ago • 16 comments

Seeing undesirable skip messages, late messages, and sometimes audibly inaccurate sequencing. Given this pattern:

d1 
  $ (|* gain 1.2)
  $ foldEvery [6,8] rev
  $ foldEvery [7,11] (linger "3e")
  $ sometimesBy 0.1 (stutWith "<3 4 5>" "1e" (|* gain 0.95))
  $ sometimesBy 0.1 ((# s "{peri ifdrums feel}%12") . (# gain 0.9))
  $ sometimesBy 0.1 (|* speed 0.5)
  $ foldEvery [3,7] (|+ n "<2 3 4>")
  $ sometimesBy 0.1 (off "1s" id) $ (1 ~>)
  $ sometimesBy 0.1 (off "3s" id) $ (1 ~>)
  $ struct "1(<2 [1 2 2]/3 2 [1 2]/2 [2 1]/2 3>,{8 8 4 8 16}%2,<0 1 5>)" 
  $ s "{bd drum}%11" 
  # n "{10 5 2}%14" # cut 1
  # speed "{1 1 1 1 0.5}%9"
  # cps (120/120/2)

I see skip messages:

tidal> skip: 11
skip: 11
skip: 11
skip: 11
tidal> kip: 12
skip: 11
:{
  hush
:}
tidal> 

My SuperCollider output is filled with late messages, even though there are only a few events fired every second.

My pattern is not really dense at all (the rhythm in the struct function is kind of sparse). However, there are many layers of conditional logic.

If I start to remove various conditional effects, then the skip messages go away. I haven't been able to pinpoint if there is a specific function that results in the skips... but in general it seems to get worse with "sometimesBy" and "while". If I replace them with "every" or "foldEvery" conditions, then the problems go away.

I guess in my opinion this logic isn't very complex and shouldn't result in so many skips/late messages. I'm probably leaning into some difficult performance problems, but it would be great a Tidal user could create a pattern with many more layers of conditional logic.

If I continue to add more layers of conditional logic, the sequencing is audibly "wrong" to my ears and the timing starts to get really off.

kindohm avatar May 24 '21 22:05 kindohm

Replacing sometimesBy with every or foldEvery conditions seems to help a little bit.

Using while instead of sometimesBy seems to make it a little worse.

kindohm avatar May 24 '21 22:05 kindohm

Hey @kindohm which tidal version are you on?

yaxu avatar May 25 '21 09:05 yaxu

Hey @kindohm which tidal version are you on?

1.7.2

I'll update to 1.7.4 and will see if I observe the same stuff.

kindohm avatar May 25 '21 11:05 kindohm

@yaxu updated to 1.7.4 and I'm seeing the save behavior with skip and late messages.

kindohm avatar May 25 '21 12:05 kindohm

I'm using kind of a weird Tidal bootup sequence so I'm going to also try this on a vanilla Atom package to make sure my window/latency params aren't causing the issue.

kindohm avatar May 25 '21 12:05 kindohm

Observing the same stuff with a vanilla Atom install.

kindohm avatar May 25 '21 12:05 kindohm

I also tried that pattern and I get the same skip messages on tidal 1.7.4

ndr-brt avatar May 25 '21 12:05 ndr-brt

I tried to simplify the pattern to understand what's the problem... seems like the sometimesBy has a central role in this. This pattern skips also, and it's not dense at all

d1
    $ sometimesBy 0.1 (|+ n 1)
    $ sometimesBy 0.1 (|+ n 1)
    $ sometimesBy 0.1 (|+ n 1)
    $ sometimesBy 0.1 (|+ n 1)
    $ sometimesBy 0.1 (|+ n 1)
    $ sometimesBy 0.1 (|+ n 1)
    $ sometimesBy 0.1 (|+ n 1)
    $ sometimesBy 0.1 (|+ n 1)
    $ sometimesBy 0.1 (|+ n 1)
    $ sometimesBy 0.1 (|+ n 1)
    $ sometimesBy 0.1 (|+ n 1)
    $ sometimesBy 0.1 (|+ n 1)
    $ sometimesBy 0.1 (|+ n 1)
    $ sometimesBy 0.1 (|+ n 1)
    $ sometimesBy 0.1 (|+ n 1)
    $ sometimesBy 0.1 (|+ n 1)
    $ "bd"

ndr-brt avatar Jun 11 '21 07:06 ndr-brt

sometimesBy performance is also discussed here: https://github.com/tidalcycles/Tidal/issues/564

yaxu avatar Jun 11 '21 22:06 yaxu

  • further discussion here: https://github.com/tidalcycles/Tidal/issues/636

yaxu avatar Jun 11 '21 22:06 yaxu

In summary, it's tricky.. Each sometimesBy doubles up the patterns that have to be calculated, and as we know from the pandemic, doubling gets bad quickly.. @jwaldmann explains it here: https://github.com/tidalcycles/Tidal/issues/636#issuecomment-618404963

If you're chaining them with the same likelihood, note though that sometimesBy 0.1 x $ sometimesBy 0.1 y is the same as sometimesBy 0.1 (x . y). So the above from @ndr-brt is the same as sometimesBy 0.1 (|+ n 16)

yaxu avatar Jun 11 '21 22:06 yaxu

I thought this might be more efficient but it seems not..

import Prelude hiding ((<*),(*>))

sometimesBy r f pat = stack [a,b]
  where randpat = (\x y -> (x,y)) <$> pat <* (rotR 1000 rand)
        a = fst <$> filterValues (\(_,y) -> y <= r) randpat
        b = f $ fst <$> filterValues (\(_,y) -> y > r) randpat

yaxu avatar Jun 13 '21 10:06 yaxu

This is much more efficient (linear?):

sometimesBy r f pat = innerJoin $ (\x -> if x >= r then f pat else pat) <$> rand

However you end up joining inner discrete events with outer continuous ones, which means that you will find different answers at different sample rates.

yaxu avatar Jun 13 '21 14:06 yaxu

I tried by myself a solution similar to the first you shared, and I noticed that was not so efficient. The second one is better but I noticed two things:

  • the sign should be inverted (x < r)
  • the function is not applied as a whole, eg:
d1
  $ sometimesBy 0.3 (stutWith 3 "s" (|* sp 2))
  $ s "bd*4"

With this piece of code, not every event that should be played by stutWith will be played, while it does with the current sometimesBy implementation

ndr-brt avatar Jun 14 '21 07:06 ndr-brt

@ndr-brt yes I hear the problem and I think it comes from the fact that it's calculating 'inside' a continuous pattern. On the other hand it does some kind of awesome like this.

yaxu avatar Jun 14 '21 10:06 yaxu

Here's an interesting hack that samples from rand according to the input pattern:

sometimesBy r f pat = innerJoin $ (\x -> if x >= r then f pat else pat) <$> (const <$> rand *> mono pat)

It seems to work but wouldn't work well for polyphonic patterns, and doesn't seem very performant either.

yaxu avatar Jun 14 '21 10:06 yaxu