Just trying to get my head around Rack module development by looking at the source for the Fundamental modules.
My question is about the
if (running) statement. I get the that the inner if part is if there is an external clock. What I don’t understand is the maths involved to get the phase to tick the index of the sequence with the internal clock. (Plus I’m not exactly sure what is the purpose of the
CLOCK_INPUT?) I think I understand that
sampleTime is just the inverse of
sampleRate. What does
clockTime * args.sampleTime give in units?
I’m pretty sure I’m missing something simple, just can’t see it right now.
Thanks in advance.
I see sampletime as time, in milliseconds I think, since the last update. Is 1 / samplerate.
The sequencer does not count the time since the last update. It emulates a ramp oscillator, with the phase variable. When phase > 1 the sequencer ticks.
Clocktime * args.sampletime sets the frequency of the oscillator. It makes phase reach 1 faster.
Thanks. That helps a little with the understanding of sampletime and the phase variable.
OK, but I don’t understand the computation for clocktime. I’ve got a good maths and some science background and I’m trying to understand clocktime’s formula.
In the 1V/oct standard, the relationship between frequency and voltage is f = f_0 \cdot 2^V. The knob value can be added to the voltage because it also scales exponentially. See https://vcvrack.com/manual/VoltageStandards#pitch-and-frequencies for more details.
The next line is a phase accumulator. If we’re stepping in time by \Delta t, the phase should advance by \Delta t \cdot f. This is so that one period happens in 1/f seconds, or 1/(\Delta t \cdot f) steps.
Thank you. Let’s see if I can make some coherent statement based on what you’ve told me…
So clocktime is Hz (or cycles per second) that is required to give us the desired BPM. We then multiple Hz by seconds (sampletime) to give us how many cycles have passed since the last process. I think it’s assumed this is < 1 cycle per process call so the cycles (or cycle position) is stored in phase so that we can tell at which process call we need to tick the sequence for the BPM. I think that makes sense now.
Only one question. I’d imagine that phase is never exactly 1.0f so wouldn’t it be more precise to set phase to
-= 1 instead of 0f? Or is that moot because it’s so close we probably can’t hear the difference? (I’m assuming it’s the latter, because Seq3 sounds on beat to me.)
The fundamental oscillator does phase -= 1.
I think for a sequencer is ok to set it to zero.
Yes, it looks like
clockTime should definitely be
clockFreq. That code was written 4 years ago, which is ancient in VCV time.
At reasonable BPM, it doesn’t make any noticeable difference. For example at 160 bpm each period will be 16537 steps at 44.1kHz instead of the true 16537.5 steps. But at ridiculously high ones, sure, the timing could be improved.
Building a comprehensive sequencer as an exercise, any reason why I SHOULDN’T use a clock divider to process it? It uses ~3.7% without, down to ~.6% divided by 8 and all seems well.
I note that other sequencer sources I’ve looked at don’t and was wondering if there’s a good reason for that?
Stats for nerds: When I say comprehensive, currently 263 params, 58 inputs & 144 outputs!
Higher divisions, the greater the performance, but less of precision. If it doesn’t need to be at audio rate; the more efficient the better! Voltage works on lower frequencies, a higher division might work better?
2 to 8 might work better for audio rate but the dynamic range can suffer going past 4, you’ll hear it anyway because Nyquist, hearing for most adults starts to cut off at 10kHz… also where mp3’s start to compress, so why no noticeable change is heard.