period mono

Detects (or at least it tries) the period (number of samples) of the input, based on zero crossings and mean value.
Author: Sputnki
License: BSD
Github: sptnk/detect/period mono.axo

Inlets

frac32buffer.bipolar input signal. should be dc-free, if you're not sure, put a highpass in front of it

Outlets

int32 number of samples at s-rate sample rate

bool32.pulse trig

Parameters

frac32.u.map tolerance for the mean value part, best set to intermediate values

Attributes

spinner Maximum period allowed. Used to discard false readings

spinner Minimum period allowed. Used to discard false readings

Declaration
uint32_t count = 0;  // sample counter
uint32_t output = 0; // output reading. The period is stored here

int64_t integral = 0; // integral of the signal starting from 0-crossing
int32_t dx = 0;       // derivative at zero crossing
int64_t ramp = 0;     //"tolerance" ramp

bool sign_old = 0; // sign of previous sample
bool sign = 0;     // sign of current sample

int32_t in_old; // old input
Control Rate
outlet_smp = output; // output the reading
outlet_trig = 0;
Audio Rate
count++;                     // increase the counter by 1
sign = inlet_in > 0 ? 1 : 0; // calculate the sign of curent input
integral += inlet_in;        // integrate the input
ramp += ___SMMUL(
    dx, param_tol
            << 2); // integrate the ramp, using the derivative at zero crossing

// too early
bool trig = (count > attr_min) && ((ramp > 0) ? (integral < ramp ? 1 : 0)
                                              : (integral > ramp ? 0 : 1));
// this condition serves to filter out meaningless zero crossings:
// if count<attr_min it means it's too early to provide a reading (maybe there's
// some noise in the signal) the second condition serves to test if the mean
// value of the signal is sufficiently close to 0 let's be honest: we'll never be
// so lucky to get it exactly to 0, so we'll settle at a sufficiently small value
// how small? it depends on how steep was the signal at zero crossing and on how
// happy we are with approximate readings

if (sign != sign_old) // a zero crossing has occurred
{
  if (trig) // if the "condition zero" i've explained before is met, we have a
            // readout!
  {
    output = count;         // readout
    count = 0;              // resetting the counter
    integral = 0;           // resetting the integrator
    ramp = 0;               // resetting the ramp integrator
    dx = inlet_in - in_old; // calculating a new derivative at 0x
    outlet_trig = 1 << 27;
  }
  if (count > attr_max) // the reading is taking too long. I'll start counting
                        // from here without passing the readout.
  {
    count = 0;              // resetting the counter
    integral = 0;           // resetting the integrator
    ramp = 0;               // resetting the ramp integrator
    dx = inlet_in - in_old; // calculating a new derivative at 0x
  }
}

sign_old = sign;
in_old = inlet_in;

Privacy

© 2024 Zrna Research