How do you record stems from JITLib?

Hi there,

I’m quite new to ProxySpace, but I figured out that if I’m playing with, say, 4 nodeproxies (~john, ~paul, ~george, ~ringo), I can record them all separately using something like this:

p = ProxySpace.push(s);

~john.play; ~paul.play; ~george.play; ~ringo.play;

p.activeProxies.do(_.postln)

(
// set up recorders for each proxy
r = p.activeProxies.size.collect{ |i|
	// get proxy names
	var proxyName = p.activeProxies[i];
	// set up recorder
	p.record(
		proxyName,
		("~Desktop/" ++ proxyName.asString ++ ".wav").standardizePath,
		headerFormat: "wav",
		sampleFormat: "float"
	)
};
)

// start recording
r.do(_.unpause)

// make music with ProxySpace, blah, blah, blah...

// stop recording
r.do(_.close)

This records the four soundfiles, but as far as I can tell, it’s the pre-monitor signals, not what I hear. Obviously, not what I want.

Is it possible to record the post-monitor output from each separate proxy (~john, ~paul, ~george, ~ringo), that is, what the proxy sends to the speakers? Separate soundfiles, including the silences when I’ve ‘.stopped’, paused, or haven’t ‘.played’ the proxy yet? Assuming the proxies exist, I’d want to record them all starting from exactly the same point in time.

There’s a lot I still don’t understand about JITLib. I haven’t really used NodeProxy ‘roles’ or ‘chains’ yet, and I’ve got no idea how these might be included in recordings or not. The docs show a few recording options, but I’m not sure which ones are good for what purpose.

Previously, I’ve made a lot of (non-JITLib) multi-track music in SC, using multiple MIDI-modulated patterns, recording “channels” as stems using the MixerChannel Quark. Then import into a DAW for production. This works well for me. Similarly, I’d like to record the separate stems from a JITLib jam (of exactly what I’m hearing).

Does anyone here record ‘stems’ from JITLib? How do you do it?

As ever, thanks for any insight or tips. :smiley:

Jim

This records the four soundfiles, but as far as I can tell, it’s the pre-monitor signals, not what I hear. Obviously, not what I want.

Elaborate if you could, exactly the nature of what seems to be ‘pre-monitor signals.’

And maybe a short demo with just ~paul & ~ringo… or, in any form, a minimal yet clearly laid out and further elaboration would be useful, at this point.

1 Like

Hi @Rainer,

Thanks for the reply. No problem. I’ll try to write up a clearer example later, with a better explanation. I’m trying to do what is a very common thing in music production, but is maybe not so simple in JITLib. I probably haven’t explained it well though… :upside_down_face:

Thanks again.

The problem is that RecNodeProxies record the proxy’s source even when you’re not monitoring it!

Its actually kind of an annoying problem…

I think you’re going to need to set up a bunch of busses between your proxies and outputs - you could use .playN to route your proxies to both HW outs and your busses…

you could subclass NodeProxy to give each proxy a dedicated recording bus and then override the play method to send to both automatically?

1 Like

thinking further each NodeProxy just needs one additional private bus to record which mirrors the output - then you add a “recordStem” method which creates a RecNodeProxy from that mirror bus if that makes sense

1 Like

Thanks @semiquaver, that’s really helpful.

I think you’re going to need to set up a bunch of busses between your proxies and outputs - you could use .playN to route your proxies to both HW outs and your busses…

That seems to be an option. I’ll read up on .playN.

What appealed to me about JITLib was how simple it is to start from nothing, without having to write ‘set-up’ code. Possibly with no inkling of where it might go. But maybe I could try to knock-up some re-usable template code, to avoid having to think ahead too much.

thinking further each NodeProxy just needs one additional private bus to record which mirrors the output - then you add a “recordStem” method which creates a RecNodeProxy from that mirror bus if that makes sense

That is a really good idea and does make a lot of sense. Thanks. But to be honest, I’ve never done that sort of programming before. I’ve only used code for music-making, never having a reason to subclass or add a new method to anything. I’m not sure it’s something I could easily do without a lot of study. I’ll re-read the Class help files though, and see how difficult it might be. Er, sorry if that sounds a bit lame. I struggle with my own musical code, let alone Class source code and various syntaxes. :-\

I think that those are definitely solutions though. Thanks again for your help, @semiquaver :smiley:

Jim

FWIW I’m also a musician first who got reluctantly sucked into coding by supercollider so ‘hail fellow well met’, as they say.

I would definitely recommend goofing around with adding methods to classes (this is pretty straightforward) and then writing your own (less so!) - it really unlocks the power of Supercollider and lets you “write what you imagine” - your interface as well as your music!

You have to understand the idea of classes and instances and their respective methods and variables… And then there is the basic machinery of the whole ^super.new.init thing which takes a second to wrap your head around. Sclang is modelled on SmallTalk - there are some great books out there that help understand the why and how… But going through the trouble can help give you a mental image of the object/class system which is quite the expressive tool from where I sit!

1 Like

FWIW I’m also a musician first who got reluctantly sucked into coding by supercollider so ‘hail fellow well met’, as they say.

Same exactly.

I’ve only used code for music-making, never having a reason to subclass or add a new method to anything.

This works for any object:

~object.addUniqueMethod
(
    \record, // ~object.record

    {
        |object ...arguments| // first argument is *always* the original object
        
        Post << class ( object ) << $\n <<* arguments ; // <<* will printAll [ , , , ]
    }
);

Object.uniqueMethods.asSortedArray.pairsDo{ |x y| x.postln; y.postln } ;
 

Peace.

1 Like

@semiquaver

FWIW I’m also a musician first who got reluctantly sucked into coding by supercollider so ‘hail fellow well met’, as they say.

Like wise. :smiley:

I would definitely recommend goofing around with adding methods to classes (this is pretty straightforward) and then writing your own (less so!) - it really unlocks the power of Supercollider and lets you “write what you imagine” - your interface as well as your music!

You’re probably right. The power of SC is mind-blowing, really. In this case it would let me integrate JITLib into my normal production workflow. Appreciate the encouragement. I’ll try some gentle tinkering…

Thanks again.

This works for any object:

~object.addUniqueMethod
(
    \record, // ~object.record

    {
        |object ...arguments| // first argument is *always* the original object
        
        Post << class ( object ) << $\n <<* arguments ; // <<* will printAll [ , , , ]
    }
);

Object.uniqueMethods.asSortedArray.pairsDo{ |x y| x.postln; y.postln } ;
 

Wow. Never knew about that. Interesting. Thanks. Is that something to be used while working on a new method without re-compiling, or is it a permanent way to add new methods? I.e. NodeProxy.recordStem?

Many thanks for your help.

Object.uniqueMethods is reset every compile.

You can use startup.scd, or Archive.global to force import.

The object could be a class, it doesn’t have to.

Thanks @Rainer. Could be useful indeed.

Oh interesting. This is ostensibly like creating an event and coupling a key name and a function, right?

There’s a good chapter in the SC Book on object modeling that goes through several examples of making pseudo-classes and methods by using events. I didn’t know about this other parallel though. Cool.

When using an event to create a pseudo-method it’s recommended to be careful with namespace overlaps – a key that has the same name as an actual method - the object will not look up the key, but use the method instead. What about with this?

The method here can only be invoked for a specific instance of an object.

a=[400,500,600];
a.addUniqueMethod(\play,{|i| Pbind(\freq,Pseq(i,inf));
a.play

if you define a method for Array:

Array.addUniqueMethod(\play etc

if will be a class method and won’t work for arrays in general.

I could see it being used in some kind of meta programming where objects are being provided with .awake or .play methods programatically but I haven’t found a use for it myself!