77#ifndef SBL_DSP_PM_THERMAL_FRICTION_HPP_
78#define SBL_DSP_PM_THERMAL_FRICTION_HPP_
126 force_su_ = su < 0.0f ? 0.0f : (su > 1.0f ? 1.0f : su);
127 if (limits_ ==
nullptr || slices_ == 0) {
131 const float pos = force_su_ *
static_cast<float>(slices_ - 1);
132 uint8_t i =
static_cast<uint8_t
>(pos);
133 if (i >= slices_ - 1 && slices_ > 1) i =
static_cast<uint8_t
>(slices_ - 2);
134 const float blend = slices_ > 1 ? pos -
static_cast<float>(i) : 0.0f;
135 cold_limit_ = cold_gain_ * (slices_ > 1 ? limits_[i] + blend * (limits_[i + 1] - limits_[i]) : limits_[0]);
147 void set_rosin(
float heat,
float tau_ms,
float convect,
float mu_ratio,
149 heat_ = heat > 0.0f ? heat : 0.0f;
150 cool_ = tau_ms > 0.0f ? 1.0f / (tau_ms * 0.001f) : 0.0f;
151 convect_ = convect > 0.0f ? convect : 0.0f;
152 mu_ratio_ = (mu_ratio > 0.0f && mu_ratio <= 1.0f) ? mu_ratio :
DEFAULT_MU_RATIO;
159 cool_fast_ = fast_ms > 0.0f ? 1.0f / (fast_ms * 0.001f) : 0.0f;
160 fast_share_ = fast_share < 0.0f ? 0.0f : (fast_share > 1.0f ? 1.0f : fast_share);
173 const float f = std::fabs(force);
174 const float v = v_slip < 0.0f ? 0.0f : v_slip;
175 const float heating = heat_ * f * v;
176 t_fast_ += dt_ * (fast_share_ * heating - (cool_fast_ + convect_ * v) * t_fast_);
177 t_slow_ += dt_ * ((1.0f - fast_share_) * heating - (cool_ + convect_ * v) * t_slow_);
188 if (limits_ ==
nullptr)
return 0.0f;
189 const float a = std::fabs(dv_free);
194 if (a <=
limit || !(a == a)) {
196 f = (a == a) ? dv_free : 0.0f;
219 const float t = t_fast_ + t_slow_;
220 return t > 1.0f ? 1.0f : t;
240 const float* limits_ =
nullptr;
242 float force_su_ = 1.0f;
243 float cold_limit_ = 0.0f;
254 float t_fast_ = 0.0f;
255 float t_slow_ = 0.0f;
259static_assert(is_friction_law_v<ThermalFriction>,
"ThermalFriction is a friction law (physical-modeling.md §4.5)");
Clamping (Cross-cutting — Math)
uint8_t add_node(Kind kind, const char *name, uint8_t group, float value=0.0f, float value2=0.0f)
void set_fast_cooling(float fast_ms, float fast_share)
The fast cooling component: its time constant and the share of the heat it takes.
static constexpr float DEFAULT_CONVECT
Convection: cold rosin flowing into the contact, per unit sliding speed per second.
static constexpr float DEFAULT_FAST_SHARE
static constexpr float DEFAULT_MU_RATIO
Rosin, as Woodhouse measured it: friction at full heat is this fraction of cold.
float temperature() const
Contact temperature as a fraction of the range over which the rosin softens.
static constexpr float DEFAULT_FAST_MS
The fast cooling component: time constant and the share of heat it takes.
void set_rosin(float heat, float tau_ms, float convect, float mu_ratio, float cold_gain=DEFAULT_COLD_GAIN)
The rosin: how it heats, cools and softens (configuration, not signals)
static constexpr float DEFAULT_TAU_MS
Conduction into the string and the bow: the slow component's time to cool by 1/e.
float mu_rel() const
Friction relative to cold, from the temperature: 1 cold down to mu_ratio hot.
void set_limits(const float *limits, uint8_t slices)
The cold static limit per force slice — the friction-curve bow's limits
void reset()
Cold and stuck.
void set_force_su(float su)
Bow force across the slices [0, 1]; the cold limit interpolates between them.
static constexpr float DEFAULT_HEAT
float process(float dv_free)
One sample: relative velocity in, injection force out.
float limit() const
The static limit right now, warmed: where the string would release.
void advance(float force, float v_slip)
Advance the contact one sample from a force and sliding speed found elsewhere.
static constexpr float DEFAULT_COLD_GAIN
bool sticking() const
True while the string travels with the bow.
diagram::Ports describe(diagram::Graph &g, uint8_t group, const char *name="bow (thermal)") const
One Junction node: the friction nonlinearity. Never called from audio code (AP-037).
What a load, an exciter, a termination and a friction law provide (Physical modeling — cross-cutting)
Fixed-point constants and audio sample types.
A model's wiring, as data (AP-037)
@ Junction
where waves scatter or a source meets the string
constexpr float clamp01(float x)
x held to [0, 1]; NaN → 0.
Physical modeling: laws, bows, junctions, loads, resonators, strings (docs/conventions/physical-model...
The ports a component exposes after describing itself, so an owner can wire them.
uint8_t in
where a wave enters (the junction, the load)
uint8_t out
where a wave leaves (the pickup, the reflection)