How do I do the stuff you can do in Sonic Pi? (gimmie homework please)

What joule said - take a look at xStream. It’s definitely the closest thing Renoise has to Sonic Pi and it’s getting more powerful with each new release.

SP was so easy to jump into. The documentation gives easily understandable explanations for using the SP features. It touches on educating the reader on basic electronic music composition. But it goes so far that it also explains very simple programming paradigms like setting variables! I won’t need that much hand-holding of course, but it was very easy to learn SP because the docs were geared towards teaching children. But more importantly, there are examples EVERYWHERE.

Yup, examples are definitely the most ‘real’ way of learning to do stuff. Think of the Renoise API docs as a reference - you need that too.

But first step - no matter what - if you are serious about scripting in Renoise, enable the scripting console (explained here: https://github.com/renoise/xrnx))

Then you will be able to run little snippets of code and examine the outcome.

Yeah, I did see xStream. Seemed like it was what I wanted too, but same thing; I didn’t know where to begin. Also, I went to the “favorites” dialog, and when I tried to resize it, I got an error message, so I was afraid it might be busted. I’ll take a look at it again though. I guess I’ll read the docs for any methods that come up, and try to get some sense of it that way.

Do you guys know any sources that give an xStream tutorial?

xStream currently doesn’t support multiple tracks or ability to stack or run multiple models at once, but this doesn’t scare me off considering its potential. At the very least, it’s a great place to start for simple and convenient prototyping!

https://www.renoise.com/tools/xstream

PS. The TRK button will render the model into the track. I pretty much disregard the “live” mode.

I’m not worried about “live mode” either. At least for now. But I wasn’t sure what it meant when it said it didn’t support multiple tracks? That just means you can only operate on one track at a time, right? Like, you can’t write a single script that processes two different tracks?

Bump to check back as I’d love to achieve algocomp but have absolutely no coding experience. A fun way to get some interesting sequence results is to use fairly short phrases with odd length or odd lpb relative to the global LPB. It’s not remotely algorithmic but fun nonetheless. Being able to assign phrase lpb and length to instrument macros would get us closer, but not on the level of Sonic Pi. Btw, Sam Aaron is a genius! Do you mind me asking if you use Renoise to process loops made with Sonic Pi? Or do you use them separately?

Sam Aaron_is_a genius. Have you seen this research paper of his? Some crazy CS stuff in there.
https://www.doc.ic.ac.uk/~dorchard/publ/farm14-sonicpi.pdf

I thought about using the pattern matrix to stitch together loops I prerecorded. But I’d definitely rather have the full programming aspect. Then I could manually edit and fine tune a random sequence to my liking. (Which Sonic Pi doesn’t do well at all.)

I’m not worried about “live mode” either. At least for now. But I wasn’t sure what it meant when it said it didn’t support multiple tracks? That just means you can only operate on one track at a time, right? Like, you can’t write a single script that processes two different tracks?

Actually you can do that quite easily, but xStream isn’t primarily “meant” to be used like that (yet, I think).

You do have access to the whole renoise.song() object. If you want to output to (or input from) a different track, the key is to use xpos.line and xpos.sequence instead of xline (which is current track only).

local current_pattern = rns.sequencer.pattern_sequence[xpos.sequence]
local current_line = xpos.line
local output_track_x = whatever_track_index

rns:pattern(current_pattern):track(output_track_x):line(current_line) -- do whatever with this!

Nice things with using xStream imo is 1) live sandbox coding, 2) everything “in sync” and flexible, xinc%x rocks 3) interesting models already available, 4) a great tool probably having a bright future, so might as well start using it for these kind of tasks. 5) preset system already implemented, 6) midi triggering features already implemented for the hipsters, 7) system for setting up a GUI for variables is already implemented

xinc%x rocks

Let me spreadshirt that!

Still don’t know where to begin, even with xStream. The examples are too dense for me to decipher. Even worse, it’s not opening some of the examples. I tried opening Euclidian rhythms.lua, and I got:Error: a model already exists with this name.When I try to delete some models (not all), I get: No such file or directory.

Again, is there a resource that slowly and thoroughly explains how to use the members in Renoise.Song.API.lua? Or just how to use the API in general? I need baby steps with this stuff.

I tried opening Euclidian rhythms.lua, and I got:Error: a model already exists with this name.When I try to delete some models (not all), I get: No such file or directory.

xStream will import all models from the /userdata/models folder when first initialized, so there is no need to open/import a model. This would also explain the error message you are getting, because the tool will not accept two models with the same name. Instead, just select the model you want to run from the popup menu in the topmost toolbar?

When it comes to documentation, video tutorials would be nice - there are only so many things you can reliably communicate in writing. Small, focused videos explaining some of the more basic stuff - like: how to open a model and create some content in the pattern.

Check out “demo-Periodic output”. That’s the “hello world” of xstream, I think. Or “demo-transpose”.

When it comes to the Renoise Lua API, you pretty much wanna get familiar with the pattern lines in this case, as this is what you’re gonna manipulate with xstream 90% of the time. Understanding pattern lines, for loops/if statements, simple arithmetics and basic lua syntax will allow you to achieve very much with xStream.

First babystep to make the Renoise Lua API less scary:

  1. Enable the lua console in Renoise – https://github.com/renoise/xrnx
  2. Familiarize yourself with the renoise.song() object in the lua terminal. Check the output from the following commands:
    2a) oprint(renoise.song())
    2b) rprint(renoise.song().patterns[1].tracks[1].lines)
    2c) oprint(renoise.song().patterns[1].tracks[1].lines[1]) – is the same as renoise.song():pattern(1):track(1):line(1)
    (rprint is for investigating tables)

xline in xStream is basically such a line object, slightly customized. In an xStream model: xline.note_columns[1].note_value = 40 – will insert a note value of 40 on every line.

The renoise song API can be found here: https://github.com/renoise/xrnx/blob/master/Documentation/Renoise.Song.API.lua . I’ve only checked it (ctrl-f) occasionally, and found that you’ll learn the most by experimenting in testpad.lua or the terminal.

I’ve been using the terminal as my general Lua console for now, lol.

I’ve been reading Renoise.Song.API.Lua, and yeah seems like a reference-only document.

Check out “demo-Periodic output”. That’s the “hello world” of xstream, I think. Or “demo-transpose”.

xline in xStream is basically such a line object, slightly customized. In an xStream model: xline.note_columns[1].note_value = 40 – will insert a note value of 40 on every line.

I’ll start with these. Thanks for pointing me there!

I’m looking at the xStream readme, and there are dialog boxes on there that are different from mine, and some that I haven’t even seen! Is that readme up to date??

and NEVERMIND. I FOUND THIS.https://github.com/renoise/xrnx/tree/master/Tools/com.renoise.xStream.xrnx/source/xLib/docs
This is all I needed guys. But one more thing, do I post my future xStream questions on the general forum? (here:)https://forum.renoise.com/t/new-tool-3-0-3-1-xstream/44430

I’m looking at the xStream readme, and there are dialog boxes on there that are different from mine, and some that I haven’t even seen! Is that readme up to date??

Okay, I noticed that there was an xStream update on the 16th, so that answers why the readme confused me.

Check out “demo-Periodic output”. That’s the “hello world” of xstream, I think. Or “demo-transpose”.

I JUST deciphered “periodic-output”!!! I was able to properly mess around with it too! It felt GREAT. Now I just need to get this lua table business straightened out, as well as working with random stuff in lua.
looks up math.random and realizes it interfaces with the C stdlib
Well I guess I gotta figure out this C API as well… :(Which means I’ll probably be spending the rest of July reading most of_Programming in Lua_.

So thanks a bunch joule for getting me started! lol
Hopefully I can figure the rest out myself. But I will have questions regarding xStream; again,do I post my future xStream questions on the general forum? (here:) http://forum.renoise…l-3031-xstream/

math.random() is just a simple LUA function that generates a random number AFAIK, as seen here: http://lua-users.org/wiki/MathLibraryTutorial

I’m sure there are ways to generate randomness that are flexible and advanced like hell (?), but the simple way to use it would probably be something like:

if (math.random(1, 20) == 1) then
 print("I had a five percent chance of being printed")
end

I would guess that a more “musical” way to generate randomness (line hits) that I’d try would be to determine a specific amount of hits that should be distributed for every 16 lines (for example). And then perhaps add another layer allowing that number to fluctuate ± a specific amount of hits. Controlled randomness :slight_smile:

The MagPi articles for Sonic Pi go all over the place with randomness. Including ‘resetting’ the seed to repeat a psuedo-random sequence; e.g., a bass line with eight random notes, but it repeats the same random notes over, and over. Don’t like that random sequence?, change the seed!!
This is where SonicPi really arrests me. All sorts of unpredictable ‘glitch’ drum beats made by making the seed reset or advance randomly, but__with chosen probability.

Here’s the download for the article:https://www.raspberrypi.org/magpi/issues/essentials-sonic-pi-v1/
The stuff I was talking about is mostly in chapters 3 and 7.

But yeah, I’m sure i can start doing that quickly in xStream. But I’m so impressed by Lua that I feel motivated enough to read the whole documentation. Plus, I’ll want to write my own classes, and it seems like Lua does that very unconventionally.

Yeah, I’ve just gotten a bit into classes (being a forever noob at programming).

If you read the class/OOP part on the official lua page, you’ll find that a class is pretty much a template table with one of the elements being a constructor function. This constructor is used when creating copies/objects of this table/class. The constructor function and what setmetatable can do is pretty much what you need to understand to set up simple classes. But… one thing worth mentioning is that Renoise provides (via luabind?) an ‘enhanced’ way of dealing with classes that seems to be a bit more convenient.

Danoise has explained some of it to me in this thread recently: https://forum.renoise.com/t/creating-a-class-beginner-question/46235 It might help you get in the ballpark.

EDIT: Imo the xStream might benefit from an even more standardized and modular framework. I’ve been thinking about the possibility of a “Pulse/Oscillator” class for setting up various hit patterns, instead of coding intricate if statements with arithmetics in each and every model.

The MagPi articles for Sonic Pi go all over the place with randomness. Including ‘resetting’ the seed to repeat a psuedo-random sequence; e.g., a bass line with eight random notes, but it repeats the same random notes over, and over. Don’t like that random sequence?, change the seed!!

Yep, random is great. Just in case you’ve missed this detail, the lua math.random is also seeded. The way you start over (or provide a new sequence) is to call the math.randomseed() function. So, whenever you are calling random it actually would spit out the same sequence of numbers - question is, how & when to set the seed.

The way I would use this is to create an argument for your model (+ in the args panel) and provide the following

name:rnd_seed (or whatever…)
type : number(integer)
fire-start: enabled

Then, add a handler function for the argument by clicking the plus sign below the code editor → “Add event handler” and choose the argument you just created.
The code editor should initialize with a blank template. Now add the following into it:

math.randomseed(args.rnd_seed)

And there you are. Whenever you modify the randomseed, it should be reflected in the model.
And, because ‘fire-start’ is enabled the selected seed should be applied when it’s first loaded and when switching between presets.

_ PS: Now, thinking about it I see a reason to introduce a couple more xStream events - because, you would also want to reset the seed when output is first started. _So, if you can wait until the next release I will introduce a set of features to make pseudo/seeded random numbers fully usable :slight_smile:

EDIT: Imo the xStream might benefit from an even more standardized and modular framework. I’ve been thinking about the possibility of a “Pulse/Oscillator” class for setting up various hit patterns, instead of coding intricate if statements with arithmetics in each and every model.

I can see how a lean & mean syntax for a “pulse generator” might be appealing, but it’s (IMHO) more important to keep that part as flexible and open as possible. For example, if we take a cue from our talks about the Euclidean rhythms model, this is a promise of the (planned) stacked models feature - the almighty Euclidean pulse generator.

edit: moved, sorry.

Yeah, our little conversation got technical/theoritical enough to be moved the main xStream topic :slight_smile:

https://forum.renoise.com/t/new-tool-3-0-3-1-xstream/44430

If you read the class/OOP part on the official lua page, you’ll find that a class is pretty much a template table with one of the elements being a constructor function. This constructor is used when creating copies/objects of this table/class. The constructor function and what setmetatable can do is pretty much what you need to understand to set up simple classes. But… one thing worth mentioning is that Renoise provides (via luabind?) an ‘enhanced’ way of dealing with classes that seems to be a bit more convenient.

Danoise has explained some of it to me in this thread recently: https://forum.renoise.com/t/creating-a-class-beginner-question/46235 It might help you get in the ballpark.

Thanks Joule! I’m still really confused about the metatables, so this will help.

Wasn’t sure if I should post this in the xStream thread or not. Sorry if it needs to be.

I’m confused about the random seed in xStream. I.e., I can’t reproduce the same sequence of random numbers. Pls help me Danoise.

_ PS: Now, thinking about it I see a reason to introduce a couple more xStream events - because, you would also want to reset the seed when output is first started. _So, if you can wait until the next release I will introduce a set of features to make pseudo/seeded random numbers fully usable :slight_smile:

I’m assuming your PS will address these questions, but maybe I just did something wrong with that event handler? Anyways,

I create a new model, and simply give it one line:xline.note_columns[1].note_value = math.random(36,48) .I keep applying to the selected track, but I’ll get a new random sequence every time**.

If I give the model a second line,math.randomseed(0),and I apply to the track, every note is the same note***. I’m guessing this is because of the behavior of xLine*?

So I get rid of that second line. But now I was clever and thought about setting the random seed in the scripting console; maybe that can set Renoise’s global random seed? So I enter the commandmath.randomseed(0)directly into the terminal. A satisfyingly greenmath.randomseed(0)appears in the console. After I played around with that, I realized that I_could_ reproduce the same random sequence. But I have to entermath.randomseed(0)into the terminal every single time before I apply the model to the track. If I don’t, I get a new sequence every time I apply**. (I explain further below at the footnote**)

Is that event handler supposed to take care of that? I did exactly as you said, but I still get a new sequence every time I apply**.

I’m so confused :frowning:


*I wish I could confidently say I got that behavior because xLine re-applies the model at every line in the track; if I reset the seed at every line, of course I’ll get the same note over and over.
But that’s the thing, I have no exact idea how xLine operates. I tried to read the lua code, but I couldn’t make heads or tails of it. I wish your documentation would describe it better. I wish it said something like, “xLine has two methods, note_columns and effect_columns”, “See renoise.NoteColumn for details on editing note values”, “here’s an example on how to blah blah blah”. Instead, I’m faced with these cryptic function names with cryptic descriptions that mean nothing to me. I have no exact idea how xLine or xinc works. Only a confident guess [of their behavior] after experimenting around with them. (I don’t even know what xpos does).
This is why I’m having such a hard time. There’s no “xStream for Dummies” that I can pour over. All I have is the many examples, with no line-by-line comments, and the cryptic documentation with “functions” that aren’t even used in the examples. I hate being a whiner, but I seriously am so confused because of this.

**Well, I don’t exactly get a new sequence every time. I get areproduciblesequence of sequences. If I reset the seed in the terminal, and apply the model three times, I get three different sequences. But If I reset the seed, and apply the model three times, I’ll get the same sequences (but they’ll all be different). I made this picture (at bottom) for clarification, and in case you need to reproduce this behavior.
I get the same behavior if I use the event handler you described. If I set the “rnd_seed” argument value to 0, I can get the same sequence of sequences. But the only way I can reproduce the sequences is if I change the argument value to something else, apply the model to the track, and then I change the argument value back to 0 (and apply to track). So am I doing something wrong?

***I don’t really care about an answer for this one, but I thought I’d let you know. In this situation, I’d expect xStream to fill the column all with the same, but a different note if I change the seed value. If I set the seed to 0,1,2,3… (and apply after changing) I keep getting “C-4”. But if I type in an arbitrary number, I get something different. But if I increment this arbitrary number and apply again, it’s the same note value. No matter how much I increment the seed.

This is the picture which clarifies what I mean by “sequence of sequences”.

^ Right here, it should say “step 3”, not “step one”.

WHOOOOOOOOOOPSSSSSsssssssies

Well I just realized immediately after posting that last one why I get the “sequence of sequences”.

If you stream the model to the track, it repeats this “sequence of sequences”. More specifically:
I reset the seed to 0 in the console, and_stream_ my example model. ThenI’ll get the output in Step 4.Until the stream reaches the top again. Then I’ll get the output in Step 5. When it reaches the top again, I’ll get the output in step 6 (and so on).

But the problem still persists; I still have to entermath.randomseed(0)into the console if I want those same sequences to be streamed.

I create a new model, and simply give it one line:xline.note_columns[1].note_value = math.random(36,48) .I keep applying to the selected track, but I’ll get a new random sequence every time**.
If I give the model a second line,math.randomseed(0),and I apply to the track, every note is the same note***. I’m guessing this is because of the behavior of xLine*?

So I get rid of that second line. But now I was clever and thought about setting the random seed in the scripting console; maybe that can set Renoise’s global random seed? So I enter the commandmath.randomseed(0)directly into the terminal. A satisfyingly greenmath.randomseed(0)appears in the console. After I played around with that, I realized that I_could_ reproduce the same random sequence. But I have to entermath.randomseed(0)into the terminal every single time before I apply the model to the track. If I don’t, I get a new sequence every time I apply**. (I explain further below at the footnote**)
Is that event handler supposed to take care of that? I did exactly as you said, but I still get a new sequence every time I apply**.

Yes, you nailed it. The random seed has to be set at the right moment to work like expected. And the right time (in this case, anyway) would be when output is first started.
That would be the purpose of the event handler - it would simply be a “hook” which you hang your randomseed statement on.

So please don’t be confused. It’s certainly true that xStream documentation is rather scarce, but that just makes it so much easier to improve :slight_smile:

But that’s the thing, I have no exact idea how xLine operates. I tried to read the lua code, but I couldn’t make heads or tails of it. I wish your documentation would describe it better. I wish it said something like, “xLine has two methods, note_columns and effect_columns”, “See renoise.NoteColumn for details on editing note values”, “here’s an example on how to blah blah blah”. Instead, I’m faced with these cryptic function names with cryptic descriptions that mean nothing to me. I have no exact idea how xLine or xinc works. Only a confident guess [of their behavior] after experimenting around with them. (I don’t even know what xpos does).

xLine is a ‘virtual’ representation of the renoise.Patternline, accepting exactly the same input - note_string, instrument_value, etc. But, unlike renoise.PatternLine it doesn’t have to existing in an actual pattern somewhere. Having a virtual representation is required for a tool like xStream to work, because the final line on which output is written might change during playback (for example, if you enable pattern loop near the end of a pattern the tool will redirect it’s output to the top of the pattern instead of the next pattern). Also, it allows us to capture things in a buffer and optimize the output in various ways.

xpos is also a virtual representation of a fundamental Renoise API component - the renoise SongPos. It contains the current sequence index and line number.

(remember, you can always use print(), rprint() and oprint() to output various debug information to the console)

xinc is the ever-increasing counter that doesn’t care about patterns but simply keeps increasing for as long the tool is streaming.

So you should use xpos if you somehow wanted your model to rely on the pattern structure, or xinc if you don’t.

All I have is the many examples, with no line-by-line comments, and the cryptic documentation with “functions” that aren’t even used in the examples.

In one of the last released I renamed a bunch of models to “Demo-something” since they are less complex than the rest. Not with line-by-line comments, but that should certainly be doable. So, not saying that the documentation can’t be improved - it always can.

And when you refer to the cryptic documentation, I guess you found the xLib documentation, contained somewhere deep in the source of xStream? Well, that’s the framework powering all of my newer tools: xRules, PhraseMate, Noodletrap, etc. This is definitely not meant to be a entry point into xStream, rather it should be hidden from plain sight. I’m sorry - seeing now that the README does refer to the xLib documentation. instead, I’ll change it to use the description above + add a mention of how to make good use of xinc in the ‘Getting started’ section of the readme :ph34r: