StiffString
Ready-to-run robot software for hobby robotics.
template <typename T> class StiffString
| Inherits | Unit |
Declared in src/libs/libmediacore/mediacore/audio/units/StiffString.hpp.
Detailed description
A bank of inharmonic modes modelling one stiff, struck string.
Why not a waveguide, and why not ModalResonator
The two obvious choices both fail the requirement that the instrument can be rescaled WHILE IT IS SOUNDING.
A digital waveguide stores the wave in a delay line, so pitch is delay length. Retuning means resampling the line: either a click, or a pitch glide with a fractional-delay filter whose gain moves with the interpolation. Neither is acceptable mid-note.
ModalResonator stores each mode as a direct-form recursion, y[n] = a1*y[n-1] - a2*y[n-2] + g*x[n]. Its state pair (y1, y2) encodes the old frequency, so rewriting (a1, a2) mid-ring changes the amplitude the state implies, and the note steps in level.
How much it steps depends on the size of the change, and that matters. An early version of testPianoModel claimed the direct form was unusable for this and swept it gradually to prove the point — it came out smooth, at 2.95 against 3.02 at rest, and refuted the claim. A direct-form resonator's error scales with each individual frequency increment, so a slow sweep is fine in it. What it cannot absorb is a JUMP: an automation step, a preset recall, a control thrown across its range. There the implied amplitude changes at once and the output is discontinuous.
The rotation form below is exact at any angle, which means the scale control can be moved arbitrarily rather than only slowly. That is a narrower claim than the one this comment used to make, and it is the one the test measures.
The rotation form
Each mode here is a phasor (re, im) advanced by a rotation and then scaled:
re' = r * (re*cos(w) - im*sin(w))
im' = r * (re*sin(w) + im*cos(w))
A rotation is norm-preserving for ANY angle. Changing w between one sample and the next therefore changes the direction of travel and nothing else — the mode's amplitude is carried in the vector's length, which the rotation cannot touch. Retuning is artifact-free by construction rather than by smoothing, and the decay stays exactly where it was.
That property is the whole reason this class exists.
The physics it carries
Partial n of a stiff string is not at n*f0. Bending stiffness raises it:
f(n) = n * f0 * sqrt(1 + B*n*n)
B is the inharmonicity coefficient — around 1e-4 for a long bass string and one to two orders larger for a short thick treble string. It is what makes a piano sound like a piano rather than an organ, and it is why piano tuners stretch octaves.
Strike position enters as a comb: a partial with a node at the strike point cannot be excited at all.
weight(n) = |sin(n * pi * alpha)|
With alpha = 1/7, every 7th partial vanishes. Real hammers sit between 1/7 and 1/15 along the string, which is why the 7th is weak rather than absent in most instruments.