phsclk

phsclk

Overview

phsclk is a utility that converts an incoming phasor signal into a clock signal that will tick N times in one cycle.

Using a phasor signal to generate a clock signal has the advantage of arbitrarily subdiving a beat. If the phasor is the master clock, parallel sequences can be subidvided in different ways while also remaining relatively in sync. There is no chance of accumulative drift.

This algorithm is minimally stateful, only requiring memory of the previous sample to work.

A tick is registered when the phasor crosses a certain threshold. Both the previous and current phasor signals are scaled by the subdivision amount, then floored. If they are different, a tick is registered.

Generated Files

phsclk.c and phsclk.h are the generated files.

<<phsclk.c>>=
#include <math.h>
#define SK_PHSCLK_PRIV
#include "phsclk.h"
<<funcs>>

<<phsclk.h>>=
#ifndef PHSCLK_H
#define PHSCLK_H

#ifndef SKFLT
#define SKFLT float
#endif

<<typedefs>>
<<funcdefs>>

#ifdef SK_PHSCLK_PRIV
<<structs>>
#endif

#endif

Structs

The state data is encapsulated in a struct called sk_phsclk.

<<typedefs>>=
typedef struct sk_phsclk sk_phsclk;

<<structs>>=
struct sk_phsclk {
    <<sk_phsclk>>
};

<<sk_phsclk>>=
SKFLT prev;

<<init>>=
pc->prev = -1;

Init

phsclk is initialized with sk_phsclk_init.

<<funcdefs>>=
void sk_phsclk_init(sk_phsclk *pc);

<<funcs>>=
void sk_phsclk_init(sk_phsclk *pc)
{
    <<init>>
}

Setting Number of Ticks

The number of ticks is set with the function sk_phsclk_nticks.

<<funcdefs>>=
void sk_phsclk_nticks(sk_phsclk *pc, SKFLT nticks);

<<funcs>>=
void sk_phsclk_nticks(sk_phsclk *pc, SKFLT nticks)
{
    pc->nticks = nticks;
}

<<sk_phsclk>>=
SKFLT nticks;

4 is a sensible starting value. Western music loves multiples of 4 and 8.

<<init>>=
sk_phsclk_nticks(pc, 4);

Computation

The function sk_phsclk_tick computes a single sample of audio from an input signal in.

<<funcdefs>>=
SKFLT sk_phsclk_tick(sk_phsclk *pc, SKFLT in);

The algorithm for phsclk is quite simple: scale and floor the previous and current input phasor signals, and if there is a difference, make a tick.

<<the_usual_way>>=
int i, pi;
SKFLT s, ps;
s = in * pc->nticks;
ps = pc->prev * pc->nticks;

i = floor(s);
pi = floor(ps);

if (i != pi) out = 1;

floor will almost always truncate the decimal, and will almost always ensure that the value is between 0 and nticks - 1. The exception to this is when in is exactly 1. This can somes cause extra ticks to happen, so a conditional is added to avoid this.

The one edge case for this is when nticks is 1, which will cause a tick only to happen at the start of the phase. To handle this, phsclk will look for phase resets instead, which happens when the previous value is greater than the current value.

This also will assume the phasor starts off at 0 at the beginning, so an initial tick also gets generated.

<<onetick_edgecase>>=
if (pc->prev > in || pc->prev == -1) out = 1;

<<funcs>>=
SKFLT sk_phsclk_tick(sk_phsclk *pc, SKFLT in)
{
    SKFLT out;
    out = 0;

    if (in < 1) {
        if (pc->nticks == 1) {
           <<onetick_edgecase>>
        } else {
            <<the_usual_way>>
        }
    }

    pc->prev = in;

    return out;
}