SuperCollider CLASSES

SubsampleOffset

Offset from synth start within one sample.

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.

Class Methods

*ir

From superclass: InfoUGenBase

Inherited class methods

Instance Methods

Inherited instance methods

Examples

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

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