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


(g8tr1522) #1

Hello all. I don’t frequent these forums very often, but I hope I can eventually contribute something big to the community.

So I spent the last month or so learning Ruby and Sonic Pi. And wowie zowie, is it easy to get a crazy awesome beat in SP. But SP is getting frustrating because it’s impossible to write a song with transitions. Renoise is baby’s-first-DAW, and when I’m doing anything in SP, I always get homesick, and wish I had a tracker interface and pattern editor. So after I read the READ-ME for the Renoise scripting API, and saw that Algorithmic composition is very possible, I knew I had to put my efforts into this.

But I don’t know where to start.

About my programming skills:

I’m not new to programming; I’m learning signal processing in MATLAB next semester. What I am very unfamiliar with, is file-handling, building and managing libraries, working with terminals. I’ve never used an API before. Even worse, I only really became fully comfortable with OOP when I just learned Sonic Pi; I finally had a practical reason to write big class structures.

I attempted to learn Lua, expecting it to be as easy as it was to pick up Ruby. Boy was I wrong. The whole idea of making your own OOP paradigms seems awesome, but I’m already having trouble with the stateless and stateful iterators.

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. I didn’t have to learn anything when I started. I just copied and pasted code, then changed some numbers, then added parameters, then swapped out fx units, etc. This made it easy to figure out what SP could and couldn’t do. Then after messing around like this, I buckled down and got serious, learning all the technical details.

My point is that I wish the Renoise docs were this easy. I don’t know where to start with this! I’m sure all of what I need is in Renoise.song.api.lua, but I don’t know what to do with that information. So maybe I do need some hand-holding. I need examples to illustrate the concepts to me.

To narrow things down, I’d be very satisfied if someone could explain this in particular:

  • how to put random notes in the pattern matrix, where the notes are chosen randomly from an array/table of notes I specify.
    -how to specify the time to ‘rest’ in-between each note.
    If anyone could spoonfeed that to me, I could probably figure out the rest myself. If you’re feeling generous, how do I do a similar thing with VST instrument parameters? And with Renoise’s built-in effects?

If this was as easy as Sonic Pi, I wouldn’t be asking you to write code for me, but I really don’t know where to begin.

TLDR : I want to do algorithmic composition in Renoise.I want easy, fully explained examples so I can have a jumping-off-point. I’m willing to put in hard work (i.e., learn Lua and study API docs), but I don’t know where to begin at all. So give me some examples pretty pleeeaaasseeeee. :slight_smile:

Thanks for the help so much! I really need it.


(fifagifs) #2

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?


(joule) #3

I’m very much in favor of making algorithmic tools to help rapid prototyping of arrangements! :slight_smile:

I really want to recommend you to consider using xStream as a platform for such experiments/models. At least check it out. xStream is like an “API” for generating pattern data (including a preset system) and there are already interesting models available that you can learn from! You can quite easily make your own models, or even your own class for it if you feel something fundamental is missing. I think this platform has a lot of potential and that it will get even better. To me, xStream is (or will be) for pattern generation what duplex is for midi controllers (the developer seems pretty committed), so consider using this instead of making your own stand-alone tool from scratch IMO :slight_smile:

I’m currently working on a chord class for xStream, being able to read, manipulate and then write chords (simple mechanics really). By this you’d be able to, for example, convert a chord track to an arp track (even complex arps that you wouldn’t normally try to track by hand). Or create a chord track by combining a simple chord track with a ‘rhythm track’. Check out https://github.com/snabeljoel/Chord-manipulation-model/tree/joule-development . This might be something you could make use of with algorithmic composition as well.

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.


(danoise) #4

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.


(g8tr1522) #5

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


(joule) #6

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


(danoise) #7

xinc%x rocks

Let me spreadshirt that!


(g8tr1522) #8

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.


(danoise) #9

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.


(joule) #10

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.


(g8tr1522) #11

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:)http://forum.renoise.com/index.php/topic/45618-new-tool-3031-xstream/


(g8tr1522) #12

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/


(joule) #13

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:


(g8tr1522) #14

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.


(g8tr1522) #15

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.


(joule) #16

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: http://forum.renoise.com/index.php/topic/47934-creating-a-class-beginner-question/ 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.


(danoise) #17

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.


(joule) #18

edit: moved, sorry.


(danoise) #19

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

http://forum.renoise.com/index.php/topic/45618-new-tool-3031-xstream/?p=348673


(g8tr1522) #20

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: http://forum.renoise.com/index.php/topic/47934-creating-a-class-beginner-question/ It might help you get in the ballpark.

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