Catmull Rom Spline

Is there a quark or something I can use to make a Catmull-Rom spline interpolation between a number of points to store in a Buffer?

I want to index into a wavetable but warp the rate that the phase is reading if that makes sense so it’s more like this instead of a straight line:

The points are (0,0), (0.1, 0.25), (0.5, 0.5), (0.9, 0.75), (1, 1).

That part’s fine, but I want a smooth curve instead of discrete linear segments. I thought of using a Catmull Rom Spline interpolation on the phase index and plugging that into my transfer function with collect to get an array for a Wavetable. Then I could put it in a Buffer to use with Osc to index into the ugen reading my wavetable buffer.

I think this would be a lot easier if I could understand how exactly the curve argument works in Env, but the documentation is pretty vague and I’m not sure that’ll get me where I’m trying to go.

On the other hand, a Catmull Rom interpolation is definitely doable, but I really don’t care to work on that at the moment. I’d rather spend the time making music first and worry about the signal processing later.

Using a ‘sin’ curve with Env gives a smoother curve. Maybe this works for you?:

Env([0, 0.25, 0.5, 0.75, 1], [0.1, 0.4, 0.4, 0.1], 'sin').plot;

Best,
Paul

I’m trying to get something more like this:

Maybe one of these?

Env([0, 0.5, 1], [0.5, 0.5], [-6, 6]).plot;
Env([0, 0.5, 1], [0.5, 0.5], [-5, 5]).plot;

That is phase shaping / phase increment distortion. You find some more information in this thread i have written: On the path of the halfAHeart window - phase shaping vs. phase increment distortion

Thats an easingOutIn function also called a seat.

You can check out my collection of unit shapers here:

You can get this one from the collection (try out different easing cores), with height 0.5 you get the desired shape (all the params are normalized between 0 and 1 and you can modulate them at Audio rate)

(
var easeIn = { |x|
	x * x * x;
};

var easeOutIn = { |x, height = 0.5|
	Select.ar(x > 0.5, [
		height - (height * easeIn.(1 - (x * 2))),
		height + ((1 - height) * easeIn.((x - 0.5) * 2))
	]);
};

var cubicSeatReversedToLinear = { |x, shape, height = 0.5|
	var mix = shape * 2;
	var easeOut = 1 - easeOutIn.(1 - x, height);
	easeOut * (1 - mix) + (x * mix);
};

var linearToCubicSeat = { |x, shape, height = 0.5|
	var mix = (shape - 0.5) * 2;
	var easeIn = easeOutIn.(x, height);
	x * (1 - mix) + (easeIn * mix);
};

var cubicSeatToLinearMorph = { |x, shape, height = 0.5|
	Select.ar(shape > 0.5, [
		cubicSeatReversedToLinear.(x, shape, height),
		linearToCubicSeat.(x, shape, height)
	]);
};

{
	var phase = Phasor.ar(DC.ar(0), 50 * SampleDur.ir);

	var sigA = cubicSeatToLinearMorph.(phase, \shapeA.kr(0), \height.kr(0.875));
	var sigB = cubicSeatToLinearMorph.(phase, \shapeB.kr(0.5), \height.kr(0.875));
	var sigC = cubicSeatToLinearMorph.(phase, \shapeC.kr(1), \height.kr(0.875));

	[sigA, sigB, sigC];
}.plot(0.02).superpose_(true).plotColor_([Color.red, Color.blue, Color.magenta]);
)

You could also check out the cubic bezier through two given points here:

1 Like

if you use the kink transfer function to warp your linear phase, you even get one more control param:

(
var kink = { |phase, skew|
	var warpedPhase = Select.ar(BinaryOpUGen('>', phase, skew), [
		0.5 * (phase / skew),
		0.5 * (1 + ((phase - skew) / (1 - skew)))
	]);
	Select.ar(BinaryOpUGen('==', skew, 0), [warpedPhase,  0.5 * (1 + phase)]);
};

var easeIn = { |x|
	x * x * x * x * x;
};

var easeOutIn = { |x, height = 0.5|
	Select.ar(x > 0.5, [
		height - (height * easeIn.(1 - (x * 2))),
		height + ((1 - height) * easeIn.((x - 0.5) * 2))
	]);
};

var quinticSeatReversedToLinear = { |x, shape, height = 0.5|
	var mix = shape * 2;
	var easeOut = 1 - easeOutIn.(1 - x, height);
	easeOut * (1 - mix) + (x * mix);
};

var linearToQuinticSeat = { |x, shape, height = 0.5|
	var mix = (shape - 0.5) * 2;
	var easeIn = easeOutIn.(x, height);
	x * (1 - mix) + (easeIn * mix);
};

var quinticSeatToLinearMorph = { |x, shape, height = 0.5|
	Select.ar(shape > 0.5, [
		quinticSeatReversedToLinear.(x, shape, height),
		linearToQuinticSeat.(x, shape, height)
	]);
};

{
	var phase = Phasor.ar(DC.ar(0), 50 * SampleDur.ir);
	var warpedPhase = kink.(phase, \skew.kr(0.5));
	quinticSeatToLinearMorph.(warpedPhase, \shape.kr(0), \height.kr(0.5));
}.plot(0.02);
)

Thanks my friend, this is perfect! For some reason I just couldn’t remember the term “phase distortion” but yeah that’s absolutely it.

1 Like