class:: SubsampleOffset
summary:: Offset from synth start within one sample.
related:: Classes/ControlRate, Classes/RadiansPerSample, Classes/SampleDur, Classes/SampleRate, Classes/OffsetOut
categories::  UGens>Info


Description::

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.


classmethods::

method::ir

Examples::

code::

// example: demonstrate cubic subsample interpolation


// 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)
}).add;
)

// 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: Done.freeSelf);
		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]).add;
)

(
	Routine {
		loop {
			s.sendBundle(0.2, [9, \Help_Subsample_Grain, -1, 1, 1, \freq, 1000]);
			rrand(0.001, 0.002).wait;
		}
	}.play;
)

::

