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;

)