Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Pattern crashes the interpreter #2

Open
Bubobubobubobubo opened this issue May 13, 2024 · 9 comments
Open

Pattern crashes the interpreter #2

Bubobubobubobubo opened this issue May 13, 2024 · 9 comments

Comments

@Bubobubobubobubo
Copy link

I think that I have identified a few bugs with the parser. Nothing dramatic but some of them are crashing / halting the interpreter such as this one: "[casio:2 casio:3/3]/<2 3 4>". I'm opening this new issue to identify some examples that I've found. Will post more if I find more 😄

@j0py
Copy link
Owner

j0py commented May 13, 2024 via email

@Bubobubobubobubo
Copy link
Author

Bubobubobubobubo commented May 13, 2024

I have integrated Pmini in a convoluted way so my patterns can look like this:

(
~rhythm => [
  pat: "[kick:11(3,8)/2, hat:4(5,8)/2, fsnare:2(1,8)/4]",
  rate: [1, 0.5], release: 0.5,
];
~rhythm.fx1(0.1, {
  arg in;
  var sound = CombC.ar(in, 2, c.dur / 4, LFNoise0.kr(c.dur * 2).range(0.01, 1));
  sound = MiVerb.ar(sound, time: 0.1);
  sound
});
~rhythm.play;
)

Is that possible in Tidal Cycles?

Most things are possible yes. For instance, if I'm not wrong, you can also do kick:[2|3|4]. You can even pattern some of the values inside the euclidian operator. There a few impossible combinations but very few of them and there is usually a better way to express what the expression suggests.

I have other patterns crashing the interpreter but more strikingly, I can crash SC by playing a pattern without associating it with a default instrument. I don't think that this is possible in the regular Pbind examples you have in the README file. It means that if I write ~a => [pat: "0 1 2"], it is game over and SC crashes 😄. It doesn't produces any error message, it just.. crashes. I'm trying to debug it now!

EDIT: adding this one that does not behave like the regular Tidal: "[1 2|~ 3 4]/2". It looks like it chooses between 1 2 and ~ 3 4 even though it should be choosing between ~ and 2. You can get the right behavior with "[1 [2|~] 3 4]/2".

@j0py
Copy link
Owner

j0py commented May 14, 2024 via email

@j0py
Copy link
Owner

j0py commented May 15, 2024

Thank you for the other issue with the | character. I had the impression that I had the correct behavior for that but I guess not.
Will be fixed too.

The crashes of sclang are probably caused by the fact that my parser uses recursiveness. This appears to be not so handy if you want to build something robuust that does not crash on whatever input you give it. So I am now making a non recursive version, in which all loops will end in a predictable manner. It will also give info about syntax errors/misunderstandings.

@Bubobubobubobubo
Copy link
Author

Yes, I think that I sometimes fall in these recursive traps. I ended up integrating quite nicely with my current setup. If you want to take a look: https://github.com/Bubobubobubobubo/BuboQuark. I can get various interesting behaviors thanks to Pmini (sample-based patterns, pitched samples, CC Messages, etc). Let me know if I can help you making it better/more robust. I can help for testing stuff, etc.

@j0py
Copy link
Owner

j0py commented May 17, 2024

OKee i have started making the non-recursive parser. It can parse stuff like "[casio:2 casio:3/3]/<2 3 4> 12" without problems. I still have to then do something with the parsed data, that will come soon. I checked the video + description of Yaxu about the "|" character in mini notation (week 4 lesson 2, and to me it looks like that the surrounding square brackets must be there.
It says:

-- The second step in this sequence is a randomly pick from
-- four subsequences:
d1 $ n "0 [0|1*3|2*8|3 4 5] 2 3" # sound "cpu"
   # speed 1.5

the four sequences are "0", "1*3", "2*8" and "3 4 5".
omitting the brackets would give us these four sequences:
"0 0", "1*3", "2*8" and "3 4 5 2 3" :-)
What do you think?

@Bubobubobubobubo
Copy link
Author

I think that your assumptions are correct! I've been playing with it more and more since it is now integrated and found other inconsistencies such as the {}% and (x, y) euclidian operator. I will do my best to summarize and explain because I think that the issue is the same in both cases:

  • Tidal is building patterns in a functional way. Patterns take t, a position in time, and are queried at different positions in time. Each time, they return the events that take place at that position, be it the begin, the middle or the end of an event. The mini-notation is ultimately parsed as a set of nested/imbricated function calls.
  • Pmini unfolds a pattern when parsing it. casio(3,8) appears to add casio eight times to the pattern when parsed. It will speed up the pattern dramatically and so you need to divide to get back to normal speed. Tidal will only add something at that position in time if the query returns an event for the euclidian algorithm.
  • {}% is doing something similar (or so I think).

Mark Zadel has written a wonderful document about the Tidal pattern syntax. It is not very well known but it goes in depth into the whole thing. Maybe it can help with the parser refactoring.

@j0py
Copy link
Owner

j0py commented May 17, 2024

Indeed a wonderful document!
The part on mini-notation confirms most of my assumptions as to what a certain pattern should do.

About the euclidian patterns: i am not sure what you mean by unfolding the pattern.
The class that Pmini get's it's cycles from is JSMini, and class JSMini has a log method which will show what steps it generates for a cycle. Like so:

JSMini("1 2(3,8)").log

 "[" 1.0 
-- "1" 0.5 
-- "2" 0.5 
--** "(" 0.0 ,
--**-- "," 1.0 
--**---- "3" 1.0 
--**-- "," 1.0 
--**---- "8" 1.0 
cycle 0
[ 1, 0.5, 0.5, 1, nil ]
[ 1, 0.1875, 0.1875, 2, nil ]
[ 1, 0.1875, 0.1875, 2, nil ]
[ 1, 0.125, 0.125, 2, nil ]
-> a JSMini

First it logs the internal "tree" of nodes that will generate the steps, and then it will log the actual steps generated for the given cycle (default is cycle 0). Each step is an array with 5 value: trig, delta, dur, str and num.

The euclidian steps together occupy half the cycle, which is correct. And within that half cycle, the time is divided over 3 identical steps according to (3,8). Delta's are 0.5 * 3/8, 0.5 * 3/8 and 0.5 * 2/8. And so are the dur values.

Looking in the Mark Zadel doc (under "Use brackets to create a Euclidean rhythm:") step "a", which would normally last a whole cycle, is cut into 3 smaller steps, each lasting 1/7 of a cycle and spread out over the time of a cycle using the (3,7) notation.

The only difference i see with JSMini is that JSMini makes the duration of each euclydian step as long as possible (equal to the delta), while in Mark Zadel doc, each step gets a duration of 1/7th step.
Is this the difference that you encountered?

@Bubobubobubobubo
Copy link
Author

The only difference i see with JSMini is that JSMini makes the duration of each euclydian step as long as possible (equal to the delta), while in Mark Zadel doc, each step gets a duration of 1/7th step.
Is this the difference that you encountered?

I think so! Sorry for not looking into the whole thing at a deeper level! I suspect that this is also the case for {}%. It can be quite surprising for a user expecting to find the tidal notation as is. I should probably be more methodic and do a write-up of all the tiny differences I find here and there. They come naturally while playing but I don't have much time to play 🥲 .

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants