### period mono f

##### 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

frac32.positive frequency in axoloti format

bool32.pulse trig

##### Parameters

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

##### Attributes

Declaration
float count = 0;  // sample counter
float 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
int32_t x0 = 0;       // value of the signal at previous 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_f = 268435456.0f / output; // calculate the frequency and output it
outlet_trig = 0;
Audio Rate
count += 1.0f;               // 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

float intercept = ((float)inlet_in) / ((float)(in_old - inlet_in));
// calculating the exact zero crossing point -> we want higher precision!

// 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
{
outlet_trig = 1;
output = count +
intercept; // readout, accounting for the "snippet" between samples
count = -intercept; // resetting the counter, adding the snippet betweein
// samples
integral = 0;           // resetting the integrator
ramp = 0;               // resetting the ramp integrator
dx = inlet_in - in_old; // calculating a new derivative at 0x
}
if (count > attr_max) // the reading is taking too long. I'll start counting
// from here without passing the readout.
{
count = -intercept;     // 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;