Recording SC: using the same sample multiple times

Hello :slight_smile:

I have an audio sample that I am using in a SynthDef, and I am declaring multiple instances of this SynthDef.

I wish to record the audio from playing multiple instances of this SynthDef.

In real time rendering, the audio is fine. When I have only one instance, playing and recording works fine.

When I have more than one instance, recording stops working as expected while playing still works.

I’ve tried multiple variations, both with s.record and with Recorder. Sometimes there is no audio at all in the recorded file, although the file take diskspace - sometimes there is only some channels but not all of them… and sometimes I forget to turn qjackctl off before hitting play :wink:

There is something I do not understand - or else I would be able to debug this ! - and I cannot find on the Internet or in tutorials.

Would you have a hint on how I could go about to debug this ? Resources to share on recording with SC ?

I am running SC 3.11.2 on Ubuntu 22.04.

Welcome! Can you share the code with steps to reproduce what you are experiencing? Ideally reduced to the simplest version possible while still reproducing the problem. It’s much easier for someone else to help you that way :slight_smile:

1 Like

Oh and when you paste code here make sure you put three back ticks
```
on the lines before and after the code blocks so the formatting doesn’t get messed up

1 Like

Yes of course !

I wanted to include two different ways of recording, one that does work and one that doesn’t - but alas, it must be because it is early for me but I cannot find the way that works again :sweat_smile: I will keep trying - in the meantime, here is the example I am working with, with a generic sample.wav that you can replace with whichever you have:

s.boot;

(
b=Buffer.read(s,thisProcess.nowExecutingPath.dirname++"/sample.wav");
)

(
SynthDef("help-LoopBuf",{
    arg out=0, bufnum=b.bufnum, rate=1, glide=0, gate=1, loopRel=0, startPos=0, startLoop, endLoop, ipol=2;
    var env, signal;
    rate = Lag.kr(rate, glide);
    env = EnvGen.ar(Env.adsr(0.1,0.2,1,2), gate, doneAction: 2);
    signal = LoopBuf.ar(2,bufnum, BufRateScale.kr(bufnum) * rate, gate+loopRel, startPos, startLoop, endLoop, ipol);
    Out.ar(out, (signal * env).dup);
}).send(s);
)

s.prepareForRecord;
s.record;

// start playback
s.sendMsg("/s_new", "help-LoopBuf", 140, 1, 0, \bufnum, b.bufnum, \startPos, 10000,\startLoop, 80000, \endLoop, 5000000);
s.sendMsg("/n_set", 140, \rate, -0.6);    // backwards

// start playback
s.sendMsg("/s_new", "help-LoopBuf", 200, 1, 0, \bufnum, b.bufnum, \startPos, 10000,\startLoop, 80000, \endLoop, 5000000);

s.sendMsg("/n_set", 200, \rate, -0.6);    // backwards

s.stopRecording;

s.quit;

Oh - ok this is a subtle one. If you evaluate
s.plotTree
you will see a window showing you the order of synth nodes on the server. By default the only node is the default group number 1. Evaluate one of your “/s_new” messages and you will see the new synth node you have made appear after the default group. When you evaluate s.record, you will see the recording synth also appear after the default group. Which one is first in the order of execution depends on which one you evaluated first, this is why you are getting unpredictable behavior.

It’s better practice to put all your synthesis inside the default group, then the record synth will always come last. If you change the fifth item in your OSC array from 0 to 1, you will see the synth appear inside of the default group, because you are setting the target to group #1.

But, I also recommend using the Synth abstraction rather than sending OSC messages directly to the server, unless you have a good reason for doing so. Makes confusion like this easier to avoid. A clearer way of writing this, IMO, is:

s.record;

x = Synth("help-LoopBuf", [\bufnum, b.bufnum, \startPos, 10000, \startLoop, 80000, \endLoop, 5000000]);
x.set(\rate, -0.6);
x.free; // stop the synth

y = Synth("help-LoopBuf", [\bufnum, b.bufnum, \startPos, 10000, \startLoop, 80000, \endLoop, 5000000]);
y.set(\rate, -0.6);
y.free;

s.stopRecording;

This way the recording synth will always come last and you don’t have to worry about targets or groups until you really need to.

1 Like

Thank you! I finally found the time to check this solution - it works :sparkles: