ok i think i got it!!!
this is an ordinary PM implementation, just with an added window and a flipped phase for better comparision:
// ordinary PM
(
{
var freq = 400;
var mod = SinOsc.ar(freq * \mRatio.kr(1));
var sig = SinOsc.ar(freq * \cRatio.kr(1), (mod * \index.kr(5)).wrap(0, 4pi));
sig.neg * (Sweep.ar(0, freq) < 1);
}.plot(0.005);
)
this BufRd
pulsar implementation leads to the same result:
(
~freqBuf = Buffer.loadCollection(s, Signal.sineFill(2048, [1,0], 0!2));
~sndBuf = Buffer.loadCollection(s, Signal.sineFill(4096, [1,0], 0!2));
)
// pulsar BufRd PM with two sinusoids:
(
{
var tFreq = \tFreq.kr(100);
var trig = Impulse.ar(tFreq);
var grainFreq = \freq.kr(400);
var phase = Sweep.ar(trig, grainFreq);
var phi = BufRd.ar(
numChannels: 1,
bufnum: ~freqBuf,
phase: phase * BufFrames.kr(~freqBuf),
loop: 0,
interpolation: 4
);
var sig = BufRd.ar(
numChannels: 1,
bufnum: ~sndBuf,
phase: 1 - (phase + ((phi * \index.kr(5)) / 2pi)) * BufFrames.kr(~sndBuf),
loop: 1,
interpolation: 4
);
sig * (phase < 1);
}.plot(0.005);
)
when instead using a welch window as the modulator and decreasing the modulation index from 5 to 2 you get the curved phase signal:
(
var welch = Env([0, 1, 0], [0.5, 0.5], \wel).discretize(4096);
~freqBuf = Buffer.sendCollection(s, welch, 1);
~sndBuf = Buffer.loadCollection(s, Signal.sineFill(4096, [1,0], 0!2));
)
// pulsar BufRd PM with welch window as a modulator
(
{
var tFreq = \tFreq.kr(100);
var trig = Impulse.ar(tFreq);
var grainFreq = \freq.kr(400);
var phase = Sweep.ar(trig, grainFreq);
var phi = BufRd.ar(
numChannels: 1,
bufnum: ~freqBuf,
phase: phase * BufFrames.kr(~freqBuf),
loop: 0,
interpolation: 4
);
var sig = BufRd.ar(
numChannels: 1,
bufnum: ~sndBuf,
phase: 1 - (phase + ((phi * \index.kr(2)) / 2pi)) * BufFrames.kr(~sndBuf),
loop: 1,
interpolation: 4
);
sig * (phase < 1);
}.plot(0.005);
)
EDIT: i think the use of the welch window shows really nicely how frequency and phase are relatives of each other. Im wondering if i could use a ramp instead of a welch window when changing the interface.
thinking in terms of frequencies is a bit more straighforward then thinking of integrated frequency changes.
But i think the ordinary SinOsc as a modulator would not work anymore when changing the interface.
EDIT: using a curved ramp as the phase modulator and multiplying phi
with the phase again does lead to something similiar, but then the SinOsc implementation doesnt work anymore, so ive introduced an index window:
(
var ramp = Env([1, 0], [1], [3.0]).discretize(4096);
~freqBuf = Buffer.sendCollection(s, ramp, 1);
~sndBuf = Buffer.loadCollection(s, Signal.sineFill(4096, [1,0], 0!2));
)
(
var statelessWindow = { |levels, times, curve, phase|
var x = 0;
var window = times.size.collect{ |i|
var x2 = x + times[i];
var result = (phase >= x) * (phase < x2) * phase.lincurve(x, x2, levels[i], levels[i+1], curve[i]);
x = x2;
result;
}.sum;
window * (phase < 1);
};
{
var tFreq = \tFreq.kr(100);
var trig = Impulse.ar(tFreq);
var grainFreq = \freq.kr(400);
var phase = Sweep.ar(trig, grainFreq);
var phi = BufRd.ar(
numChannels: 1,
bufnum: ~freqBuf,
phase: phase * BufFrames.kr(~freqBuf),
loop: 0,
interpolation: 4
);
var indexWindow = statelessWindow.(
levels: [0, 1],
times: [1],
curve: [-8.0],
phase: phase
);
var index = \index.kr(0) + indexWindow.linlin(0, 1, 0, \indexModAmount.kr(2));
var sig = BufRd.ar(
numChannels: 1,
bufnum: ~sndBuf,
phase: 1 - (phase + ((phi * index) / 2pi)) * BufFrames.kr(~sndBuf),
loop: 1,
interpolation: 4
);
sig * (phase < 1);
}.plot(0.005);
)
any suggestions?