ViolinProcessor
A parametric physical model of a bowed string instrument.
| Declared in | src/libs/libbahn/bahn/tracker/processor/ViolinProcessor.hpp |
| Inherits | StringInstrumentProcessor |
| Group | bahn |
Detailed description
The same shared engine as the piano and the guitar, with one difference that changes everything about how it plays: the string is a BowedString, so it is driven by a continuous stick-slip friction loop rather than handed energy once and left to ring.
What that means for the controls
A hammer and a pick take a velocity. A bow takes three continuous quantities — speed, force and position — and they are per-row lane parameters rather than node parameters, because a bow stroke belongs to a note in the way that an instrument's body size does not.
BowForce is a multiple of the force that plays at the current speed and position, not an absolute. The force that sustains the motion tracks bow speed and inversely tracks the distance from the bridge, which is Schelleng's relation, so an absolute control would be unplayable without the player tracking speed by hand (specs/physical-instruments §PIV-5c).
The bow lifts on zero speed
A tracker sends no key release unless the row carries NOTE_OFF. For a piano that trap costs a damper; for a sustaining instrument it costs everything, because a bowed note never decays on its own. BowSpeed at zero therefore lifts the bow and the string decays, and an explicit NOTE_OFF still stops it.
Vibrato is free here and hard elsewhere
Vibrato is a continuous pitch modulation of a sounding note. In a waveguide that means resampling a delay line, which is the exact operation that clicks or changes gain. In the rotation form it is a change of angle, and a rotation cannot touch the length of the vector it turns. Two parameters and no new mechanism.
Member function documentation
baseDecayFor
[override virtual protected] ProcessorSample ViolinProcessor::baseDecayFor(int note) const
What the string does once the bow leaves it.
Returns the T60 in seconds for the MIDI note note, before Scale moves it.
Long, because a violin string under tension with no damper on it rings audibly after the stroke — that ring is most of what an open string contributes to an ensemble. While the bow is DOWN this decay barely matters, because the bow is putting energy in faster than the string loses it.
baseInharmonicity
[override virtual protected] ProcessorSample ViolinProcessor::baseInharmonicity(int note) const
A violin string is thin and under high tension, so its stiffness sits in the same band as a guitar's rather than a piano's — measured guitar values run from about 1e-6 to 1e-3, and a piano's treble is two orders above that.
Returns the inharmonicity coefficient for the MIDI note note, before Scale divides it. A note outside the compass takes the value of the nearest end.
Derived from the same stiffness relation as the guitar's curve rather than measured on a violin, which the research log says plainly (§PIR-8).
bodyTable
[override virtual protected] std::vector<ModalBody<double>::ModeSpec> ViolinProcessor::bodyTable() const
The violin corpus.
Five identifiable low modes, of which three radiate strongly, plus a broad formant near 2.3 kHz called the bridge hill. The frequencies are measured values from Woodhouse's own textbook: A0 the Helmholtz air mode at 272 Hz, CBR at 407 Hz, B1− at 462 Hz, B1+ at 551 Hz, and the hill peaking around 2.3 kHz (§PIR-5).
Ordered by radiated level and not by frequency, because truncating the table is the quality budget and the budget must drop what matters least. CBR sits fourth despite its low frequency because it barely radiates, and the bridge hill sits fifth despite being the highest of the five because it carries most of the instrument's brightness.
Modes 6 through 10 are a deliberately generic upper body and carry no source, which the user documentation states rather than implies (§PIU-3).
damperT60
[override virtual protected] ProcessorSample ViolinProcessor::damperT60(const StringInstrumentProcessor<BowedString<double>>::Voice &v, ProcessorSample freeT60) const
The bow lifts on zero speed.
Returns the T60 in seconds that the voice v has now. freeT60 is the T60 of the note with nothing touching the string.
A tracker sends no key release unless the row carries NOTE_OFF, which is trap 4. For a piano that costs a damper; for a sustaining instrument it costs everything, because a bowed note never decays on its own. A string whose bow has lifted is in the base's released state and takes the shorter decay, which is a violinist taking the bow off the string rather than stopping it with a finger.
exciteVoice
[override virtual protected] void ViolinProcessor::exciteVoice(StringInstrumentProcessor<BowedString<double>>::Voice &v, ProcessorSample velocity)
Starting a stroke is not an excitation.
Puts the bow on the string of the voice v, with the values of the bow position, speed and force controls. velocity is not used.
A hammer and a pick hand the string energy once. A bow is simply put down on it, and the friction loop does the rest — so this sets the three bow quantities and nothing else. The note begins because the loop begins, which is why a bowed attack has a speaking time rather than a transient.
pitchOffsetCents
[override virtual protected] ProcessorSample ViolinProcessor::pitchOffsetCents(const StringInstrumentProcessor<BowedString<double>>::Voice &v) const
Vibrato, as a live pitch offset in cents.
Returns the vibrato offset in cents. Every voice gets the same offset, so the value does not depend on v.
Shared by every sounding string, because a violinist's hand vibrates one finger at a time but the effect is read as a property of the phrase. The depth is in cents and the rate in cycles per second, and both reach the rotation form directly — a change of angle, which cannot touch the length of the vector it turns.
stringBodyMix
[override virtual protected] std::pair<ProcessorSample, ProcessorSample> ViolinProcessor::stringBodyMix() const
The body is most of a violin.
The string alone moves almost no air. Everything a listener hears has been through the bridge and the corpus, which is why the mix leans further toward the body than the guitar's does.