HrCodeSequencer a sequencer that sequences code within the Hadron environment


Inherits from: Object : HadronPlugin


HrCodeSequencer is a "code sequencer" for the Hadron environment. It has a familiar track based sequencer GUI, but the items inside tracks contains sclang code which interacts with the plugins inside Hadron. The code can also interact with the parent sequencer, so you can also alter the state of the sequencer (the tempo, position of playback etc.) which yields to possibilities that are not possible with traditional sequencers (for example you can experiment with generative form, generative looping logic etc. in an intuitive manner). 


Each code blob knows its exact position on the beat grid, and when the sequencer is running over it, it knows exactly what the current beat division the playing sequencer is in. The functions for the code blobs that share the same beat columns (i.e. that are to be executed simultaneously) are executed in top to bottom order.


See also: Hadron HadronPlugins


Known issues:


[1] Unfortunately, HrCodeSequencer is not compatible with SwingOSC at this time. It heavily relies on the Document class for code mangling and that class is not available on other platforms other than Cocoa. In the future, I am really willing to make a SwingOSC compatible version, and I'll be glad to help anyone who intends to work on it. Other than the unsupported classes, all code is written in cross-platform compatibility in mind.


[2] Due to a currently unaddressed UserView bug in the Cocoa implementation of SC, when your sequencer view gets too big horizontally, draw operation on that view (ruler etc.) fails. This limits the maximum amount of time your sequencer can handle horizontally. There are ways around it if you need extra time (zooming out as much as possible and increasing the granularity of the sequencer, working in half time etc.) but this is annoying for sure.


Theory of operation:


First, the GUI:


Bpm: Number of beats per minute


Bpb: Number of beats per bar


Num. Bars: Number of visible bars. When you try change this value (or Bpb value) to a lower value, if the clipping of time will result in discarding already placed code items on the track view, your change will be refused until you move the items to an earlier time grid.


Ticks per beat: The granularity of the sequencer. Should basically be a power of two. This sets the number of calls the sequencer will make to the code items on track view per beat.


The 4 transport buttons: They are "rewind", "stop", "pause" and "play" respectively. The difference between pause and stop is explained below. The transport buttons are instances of HrButton which can do midi learn, so You can trigger them with midi controllers. See HrButton help to see how it is achieved.


Stop Func: When you press this button, a Document will pop up with a function inside it which is passed three arguments, namely hadronParent, seqParent, currentBeat. When you issue "stop" on the sequencer, this function will be executed (as opposed to pause). hadronParent is the instance of Hadron that is running, seqParent is the sequencer you are working in, and currentBeat is the last beat the sequencer was in when you issued stop. 


This function, and the operations executed inside the Document itself is using an Environment that is separate from the default Environment SuperCollider uses. You can access your code items from within the function and Document. And you can control the sequencer and running plugins by using the passed in arguments. To learn more about the Environment, check the relevant help section in this document.


When you close the document window, the stop function the sequencer uses will be updated automatically. (You WON'T be presented with a save dialog, and you DON'T need to save the document. When you press the button again, you will see that the code you entered is still there. And when you save your project in Hadron, the codes will be saved inside your saved project file automatically, and will be revived when you load later on. 


If you want to update the stopFunc your sequencer instance uses without closing the document, press Function + c. See the keyboard shortcuts section in this help also.


To Cursor: This button scrolls the view to the current location of the cursor.


Zoom: Zooms in and out for easier editing. See the Known issues [2] in this document for a possible problem with this.


--


The Ruler and Cursor view: The red numbers in the ruler denote bar start points, and the little black numbers are the beat positions in bars. Below the ruler is a black view which holds the cursor. When the sequencer is playing, you will see a white cursor advance over time. You can drag on this view to change the position of the cursor (when the sequencer is not playing).


The Tracks view: It is the gray view with horizontal stripes which denote track rows. Each row is a track where you can place your code items. The operations on this view is carried out by a contextual menu which is accessed by right clicking on it. The options on the contextual menu are:


Add code blob: 

Brings up the new code item dialog. In that window, you need to give unique a name to your item

and the variable with the same name will be added to the Environment all code items share. You can

also set the RGB colors for your item, if you click on the colored rectangle, a new random color will be

picked for you.

When you press "Ok", the item will be placed on the track view. The details regarding the usage of them

is covered later on in this document.

Add row:

Adds a row to the track view, in case you need more.

Remove last row:

Removes the last row from the view. If the last row already has some code items on it, removal

command will be refused.

Cancel:

Just closes the contextual menu.


Working with Code Blobs:


The code items (or blobs) represent a series of actions to be executed when the sequence is playing them. To delete an already created code item, right click on it and press delete. To move them around, drag them with your mouse, and to resize them, point your mouse to the right edge of the blob and when you see a black rectangle at the edge popped up, drag the edge with your mouse. 


To access the code that is contained in a blob, double click on the item. You will see a new Document window popped up, with a pre-filled function which has the arguments hadronParent, seqParent, currentBeat, beatStart, beatEnd, callInterval passed in.


When you close the document window, the function for the code blob will be updated automatically. (You WON'T be presented with a save dialog, and you DON'T need to save the document. When you double click on the blob again, you will see that the code you entered is still there. And when you save your project in Hadron, the codes will be saved inside your saved project file automatically, and will be revived when you load later on. 


If you want to update the function your code blob uses without closing the document, press Function + c. See the keyboard shortcuts section in this help also.


The passed in arguments:


hadronParent is the Hadron application instance that is currently running. Not much to do with this if you don't know the internals of the Hadron system. Its nice to have direct access to it.


seqParent is the HrCodeSequencer instance this code item belongs to. You can alter the state of the sequencer by using this variable, and you can access to the other running plugins in the system by issuing queries to this variable. Available options:


seqParent.getBpm;

Returns the current bpm of the running sequencer.

seqParent.changeBpm(argBpm);

Sets the bpm of the running sequencer.

seqParent.jumpTo(argBeat);

Makes the sequencer jump to the specified beat.

seqParent.givePlug(plugID);

This method provides access to the running plugins in the system, and needs some explanation.

Each plugin running in the Hadron system has its own unique ID that discerns it from the other

running plugins. If you want to talk to a plugin, you need to get it's ID number first. To do that, you need

to press "Function + p" while the code or sequencer window is on focus, and this will post a list of

active plugins, their names and ID numbers to the post window. Each instance has its own ID.

When you run this method, and give that id number, the method will return the actual plugin instance

back. There is basically two default things you can do with the instance (when you write your own plugins,

you can also add your own stuff to control too):

Each HadronPlugin probably has a modGets and modSets variables which are kind of Dictionary,

which have modulatable parameter name -> function mappings inside them. You can query the

values by using the provided console, to see how to access it and how to use it, refer to the console

section of this help. So for example you have a plugin with id 45306, and its modGets and modSets are:

modGets = Dictionary[ (level -> a Function) ]

modSets = Dictionary[ (level -> a Function) ]

You can query the dictionaries from the console. To see more info about these variables, check the

HadronPlugin and Writing-Hadron-Plugins helps.

The functions in modGets Dictionary return the current value of the named control, and the modSets

Dictionary sets the value for that control (typically in 0-1 range) by using the passed in argument. So,

to get the value, we can use:

seqParent.givePlug(43506).modGets.at(\level).value;

And to set that value to 0.5, we can use:

seqParent.givePlug(43506).modSets.at(\level).value(0.5);

If those operations set and get the values directly from the gui widgets, you will need to put the

queries inside a { }.defer; block.

See the console help in this document to find out how you can find out what modulatable values

running plugins have.


currentBeat is the beat the sequencer is on when the code blob is called. It is between beatStart and beatEnd.

So to infinitely loop between the start and stop points of a blob, one could say something like:


{|hadronParent, seqParent, currentBeat, beatStart, beatEnd, timeBetweenCalls| 


if(currentBeat == (beatEnd - callInterval),

{

seqParent.jumpTo(beatStart);

});

}


beatStart is the start beat of the blob on the track view.


beatEnd is the ending beat of the blob on the track view.


callInterval is the time between calls to the code blob, and it is the reciprocal of the Ticks per beat control,

found on the sequencer GUI. For example, for a Ticks per beat of 16, this value will be 0.0625.

Using this value with beatStart and beatEnd will allow you to find out where precisely the sequencer

cursor is in relation to the blobs length.



Keyboard shortcuts:


When the sequencer is in focus:


Fn + space: Play/pause

Fn + left arrow: Cursor to one beat left

Fn + right arrow: cursor to one beat right

Fn + r: Rewind

Fn + s: Stop

Fn + w: Save the current Environment the codes are running in.

Fn + q: Switch to the last saved Environment. (see the section about Environment in this help)

Fn + d: Post the current Environment to the post window

Fn + p: Post the names and unique ID's of all running plugins to the post window.

Fn + c: Open the console. See the section about console in this help.


When a Document is in focus:


Fn + p: Post the names and unique ID's of all running plugins to the post window.

Fn + c: Interpret the function. (same thing that happens when you close the document)


Environment:


All code Documents and blobs share the same environment which is separate from the main environment of sclang. So the variables used with the ~ prefix are shared between all code blobs. And the names of all code blobs are tied to the actual instances of the blobs. That means, if you have a code blob named timelooper1, there will be a variable called ~timelooper1 which points to that particular code blob. You can query some of the properties of the blob from any code window / function, here are the member variables that might be useful in some cases:


blobStartBeat: the starting beat of the blob (ex. ~timelooper1.blobStarBeat; )

blobEndBeat: the ending beat of the blob

currentRow: the row that blob resides on, might be useful for generative form generation based on spatial placement or whatnot...

color: the color of the blob, might be useful for color coding blobs and employing a selective generative form generation method by colors.


The console:


The console is a simple window that lets you send messages directly to the sequencer instance. You can use the console to test out simple pieces of queries. All the calls you make will be forwarded to the sequencer instance. Some methods that might be of use here (they can also be used in your code blobs):


givePlug(plugID): Returns the plugin that has the plugID. You can query its modulatable parameters and change them to see how they react from the console. 

Ex: 


givePlug(1234).modGets;

givePlug(1234).modGets.at(\level);

givePlug(1234).modSets.at(\level).value(0.5);


resetEnvir: Resets the current environment.


parentApp: Parent Hadron instance. Might be useful if you know what you are doing, for getting debugging data etc.


And some already covered methods:

givePlug, getBpm, changeBpm, jumpTo...


---


To get more info about the internals of the HadronPlugin system, see its help.


Batuhan Bozkurt 2009

http://www.earslap.com