SubsampleOffset offset from synth start within one sample
Inherits from: Object : AbstractFunction : UGen : InfoUGenBase
SubsampleOffset.ir
When a synth is created from a time stamped osc-bundle, it starts calculation at the next possible block (normally 64 samples). Using an OffsetOut ugen, one can delay the audio so that it matches sample accurately.
For some synthesis methods, one needs subsample accuracy. SubsampleOffset provides the information where, within the current sample, the synth was scheduled. It can be used to offset envelopes or resample the audio output.
see also: OffsetOut
// example: demonstrate cubic subsample interpolation
Server.default = s = Server.internal; // switch servers for scope
// impulse train that can be moved between samples
(
SynthDef(\Help_SubsampleOffset, { |out, addOffset|
var in, dt, sampDur, extraSamples, sampleOffset, resampledSignal;
in = Impulse.ar(2000, 0, 0.3); // some input.
sampDur = SampleDur.ir; // duration of one sample
extraSamples = 4; // DelayC needs at least 4 samples buffer
sampleOffset = 1 - SubsampleOffset.ir; // balance out subsample offset
sampleOffset = sampleOffset + MouseX.kr(0, addOffset); // add a mouse dependent offset
// cubic resampling:
resampledSignal = DelayC.ar(in,
maxdelaytime: sampDur * (1 + extraSamples),
delaytime: sampDur * (sampleOffset + extraSamples)
);
OffsetOut.ar(out, resampledSignal)
}).send(s);
)
// create 2 pulse trains 1 sample apart, move one relatively to the other.
// when cursor is at the left, the impulses are adjacent, on the right, they are
// exactly 1 sample apart.
(
var dt = s.sampleRate.reciprocal; // 1 sample delay
s.sendBundle(0.2, [9, \Help_SubsampleOffset, s.nextNodeID, 1, 1, \out, 40, \addOffset, 3]);
s.sendBundle(0.2 + dt, [9, \Help_SubsampleOffset, s.nextNodeID, 1, 1, \out, 40, \addOffset, 0]);
)
s.scope(1, 40, zoom: 0.2);
// example of a subsample accurate sine grain:
// (I don't hear a difference to normal sample accurate grains, but maybe
// someone could add an example that shows the effect)
(
SynthDef(\Help_Subsample_Grain,
{ arg out=0, freq=440, sustain=0.005, attack=0.001;
var env, offset, sig, sd;
sd = SampleDur.ir;
offset = (1 - SubsampleOffset.ir) * sd;
// free synth after delay:
Line.ar(1,0, attack + sustain + offset, doneAction:2); env = EnvGen.kr(Env.perc(attack, sustain, 0.2));
sig = SinOsc.ar(freq, 0, env);
sig = DelayC.ar(sig, sd * 4, offset);
OffsetOut.ar(out, sig);
}, [\ir, \ir, \ir, \ir]).send(s);
)
(
Routine {
loop {
s.sendBundle(0.2, [9, \Help_Subsample_Grain, -1, 1, 1, \freq, 1000]);
rrand(0.001, 0.002).wait;
}
}.play;
)