Realtime recording?

Hey, guys, thanks for the help so far!

I’m sure this is possible. I want to record to disk and stream it out as it is generated. I also want to set up this recorder from a single start up script. I have a script that will now wait for the sever to boot, create a Synth node, define a SynthDef, then when the server has that SynthDef play the Synth.

I’ve been reading the asynch messaging sections of the docs, which implies to me that it’s possible to do the same with a Recorder as well as a Synth. But I can’t actually figure out how :slight_smile:

Any ideas? Thank you!

Hi! What source do you want to record? If it’s simply your main out, then s.record will do just what you want: you are already streaming it out, and at the same time Recorder will write it to disk.

If it’s not your main out you want to record, Recorder can take in any other bus:

  • play something on a bus
~bus = Bus.audio(s, 2);
{ SinOsc.ar(LFNoise.kr(10).exprange(20,20000) }.play(outbus: ~bus);
  • have a Recorder record that bus
r = Recorder(s);
r.prepareForRecord("/path/to/rec/file.aiff", ~bus.numChannels);
r.recordBus(~bus);
  • have a monitor routing that bus to your main out
m = Monitor();
m.play(~bus, ~bus.numChannels, 0)
  • Then, when you’re done:
r.stopRecording;
m.stop;

Hey hey,

I don’t think s.record will work, because I need to have everything executed at once. For example, here’s my dummy current code. I added s.record in the beginning but nothing was saved, which I believe is because when recording started there was no audio. Is that possible?

s.waitForBoot({
var message;
x = Synth.basicNew(\grains, s);
message = x.newMsg(s, \addToTail);
SynthDef(\grains, { |out, freq=440, pan=0|
Out.ar(out, GrainSin.ar(2, Impulse.kr(10), 0.1, freq, pan, -1));
}).send(s, message);
});

Did you add s.record before s.waitForBoot? That would be the first explanation for not saving any file. Otherwise, Recorder doesn’t ignore silence, so a silent file would be saved.

However, s.record has a delay, which you can avoid by calling s.prepareForRecord first. From Server.record helpfile:

If you have not called prepareForRecord first (see above) then it will be invoked for you (but that adds a slight delay before recording starts for real).

So, to put it all together, you also have to know that s.prepareForRecord creates a SynthDef and allocates a buffer for Recorder. To make sure all this is done in due time before starting recording and playing, I would use s.bind and s.sync:

s.waitForBoot {
	s.bind{
		SynthDef(\grains) { |out, freq=440, pan=0|
			Out.ar(out, GrainSin.ar(2, Impulse.kr(10), 0.1, freq, pan, -1));
		}.send;
		s.prepareForRecord();
		s.sync; // wait for all defs to be ready, and rec buffers allocated
		s.record();
		Synth(\grains);
	}
};

Note: I took the freedom to not use your messaging style, as it’s not really needed in this example, and I think it’s better to rely on language abstractions when you can. Anyway, it also works with your syntax:

s.waitForBoot({
	s.bind{
		var message;
		s.prepareForRecord();
		s.sync;
		s.record();
		x = Synth.basicNew(\grains, s);
		message = x.newMsg(s, \addToTail);
		SynthDef(\grains, { |out, freq=440, pan=0|
			Out.ar(out, GrainSin.ar(2, Impulse.kr(10), 0.1, freq, pan, -1));
		}).send(s, message);
	}
});

Quick question Elgiano: is to the s.sync still needed since we’re using s.bind?

Yes, otherwise it doesn’t find the SynthDefs. I honestly don’t understand all the inner mechanisms involved.

If I understand correctly, s.bind doesn’t wait by itself, it just makes a bundle. Adding s.sync puts in some /sync messages, which make sure that subsequent messages are executed after the previous complete (i.e. those synths are created after the synthdefs are ready).