Demote vocal drive to flow calibration
This commit is contained in:
parent
db8fee762e
commit
e21edd2fa9
10 changed files with 92 additions and 39 deletions
|
|
@ -155,9 +155,10 @@ Current authority map:
|
|||
|
||||
- Owner: `AcousticSourcePort` owns local excitation semantics at a graph
|
||||
terminal.
|
||||
- Inputs: pressure, tension, aperture/opening, mass, damping, stiffness,
|
||||
saturation, drive, load coupling, rest opening, balance, source position, and
|
||||
the incident pressure at the graph node.
|
||||
- Inputs: reservoir/source pressure, downstream pressure, tension,
|
||||
aperture/opening, mass, damping, stiffness, saturation, tissue loss, aperture
|
||||
shaping, flow loss/resistance, flow scale, load coupling, rest opening,
|
||||
balance, source position, and the incident pressure at the graph node.
|
||||
- Outputs: source flow injected into the acoustic graph; rendered pitch is an
|
||||
outcome of valve state plus tract/radiation load.
|
||||
- Derived state: `kind=syrinx` and `kind=labial` are authoring aliases for
|
||||
|
|
@ -177,6 +178,14 @@ vertical phase as physical control surfaces. A syrinx is two such valves feeding
|
|||
an acoustic graph; a larynx is one such valve feeding a tract. Different species
|
||||
should change morphology and gestures, not add hidden source renderers.
|
||||
|
||||
For graph tissue valves, pressure owns energy input. `drive` is not a vocal
|
||||
physics owner; authoring `drive=` is accepted only as a compatibility alias for
|
||||
`flow_scale`, which is an output calibration/control-lane scalar. It must not
|
||||
multiply reservoir pressure, lower the phonation threshold, or brighten a direct
|
||||
displacement term. Ease of oscillation and harmonic richness belong to pressure,
|
||||
mass, stiffness/tension, damping, tissue/collision loss, aperture shaping,
|
||||
flow resistance, and acoustic load.
|
||||
|
||||
Morphology is now owned by continuous `area_curve` records plus acoustic graph
|
||||
paths. A `path` may inline diameters/areas or reference `area_curve=...`; the
|
||||
compiler resamples that continuous area function into graph segments while
|
||||
|
|
|
|||
|
|
@ -18,8 +18,8 @@ area_curve name=side_resonator length_cm=9 diameters=.20,.36,.54,.44,.18
|
|||
path name=core area_curve=core_tube loss=.996 loss_model=birkholz_2024 constriction_index=3.4 constriction_diameter=@/alien/aperture lip=@/alien/aperture
|
||||
path name=side area_curve=side_resonator loss=.994 loss_model=wall
|
||||
|
||||
source_port name=core_valve path=core kind=synthetic model=tissue_valve law=body_cover position=0 pressure=@/alien/core/pressure tension=.44 opening=@/alien/core/opening noise=.05 upper_mass=.18 lower_mass=.30 coupling_stiffness=.12 collision_stiffness=.45 collision_damping=.12 vertical_phase=.42 reservoir_pressure=1 downstream_pressure=.03 load_coupling=.38 rest_opening=.03 drive=1.10
|
||||
source_port name=side_valve path=side kind=labial law=one_mass position=0 pressure=@/alien/side/pressure tension=.34 opening=@/alien/side/opening noise=.04 mass=.22 damping=.15 stiffness=.026 reservoir_pressure=1 downstream_pressure=.02 load_coupling=.34 rest_opening=.04 drive=.95
|
||||
source_port name=core_valve path=core kind=synthetic model=tissue_valve law=body_cover position=0 pressure=@/alien/core/pressure tension=.44 opening=@/alien/core/opening noise=.05 upper_mass=.18 lower_mass=.30 coupling_stiffness=.12 collision_stiffness=.45 collision_damping=.12 vertical_phase=.42 flow_scale=1.10 tissue_loss=.18 aperture_shape=.44 flow_loss=.38 reservoir_pressure=1 downstream_pressure=.03 load_coupling=.38 rest_opening=.03
|
||||
source_port name=side_valve path=side kind=labial law=one_mass position=0 pressure=@/alien/side/pressure tension=.34 opening=@/alien/side/opening noise=.04 mass=.22 damping=.15 stiffness=.026 flow_scale=.95 tissue_loss=.22 aperture_shape=.40 flow_loss=.36 reservoir_pressure=1 downstream_pressure=.02 load_coupling=.34 rest_opening=.04
|
||||
|
||||
branch name=side_coupler from_path=core from_position=.58 to_path=side to_position=1 kind=resonator opening=@/alien/branch/opening coupling=.62 passive=true
|
||||
radiation_port name=aperture path=core kind=vent model=wall position=1 opening=@/alien/aperture reflection=-.58 loss=.96
|
||||
|
|
|
|||
|
|
@ -23,8 +23,8 @@ path name=left_bronchus area_curve=left_bronchus_curve loss=.996 loss_model=wall
|
|||
path name=right_bronchus area_curve=right_bronchus_curve loss=.996 loss_model=wall
|
||||
path name=trachea area_curve=trachea_curve loss=.997 loss_model=viscous
|
||||
|
||||
source_port name=left_labium path=left_bronchus kind=syrinx law=one_mass position=0 pressure=@/bird/left/pressure tension=@/bird/left/tension opening=@/bird/left/opening noise=.018 mass=.24 damping=.11 stiffness=.032 saturation=.82 reservoir_pressure=1 downstream_pressure=.02 load_coupling=.46 rest_opening=.018 drive=1.22
|
||||
source_port name=right_labium path=right_bronchus kind=syrinx law=one_mass position=0 pressure=@/bird/right/pressure tension=@/bird/right/tension opening=@/bird/right/opening noise=.016 balance=.94 mass=.25 damping=.12 stiffness=.036 saturation=.84 reservoir_pressure=1 downstream_pressure=.02 load_coupling=.46 rest_opening=.018 drive=1.18
|
||||
source_port name=left_labium path=left_bronchus kind=syrinx law=one_mass position=0 pressure=@/bird/left/pressure tension=@/bird/left/tension opening=@/bird/left/opening noise=.018 mass=.24 damping=.11 stiffness=.032 saturation=.82 flow_scale=1.22 tissue_loss=.16 aperture_shape=.38 flow_loss=.32 reservoir_pressure=1 downstream_pressure=.02 load_coupling=.46 rest_opening=.018
|
||||
source_port name=right_labium path=right_bronchus kind=syrinx law=one_mass position=0 pressure=@/bird/right/pressure tension=@/bird/right/tension opening=@/bird/right/opening noise=.016 balance=.94 mass=.25 damping=.12 stiffness=.036 saturation=.84 flow_scale=1.18 tissue_loss=.18 aperture_shape=.38 flow_loss=.32 reservoir_pressure=1 downstream_pressure=.02 load_coupling=.46 rest_opening=.018
|
||||
|
||||
terminal name=left_merge path=left_bronchus position=1 kind=junction area_scale=1
|
||||
terminal name=right_merge path=right_bronchus position=1 kind=junction area_scale=1
|
||||
|
|
|
|||
|
|
@ -12,8 +12,10 @@ param path=/bird/left/damping default=.14 min=0 max=2 step=.001
|
|||
param path=/bird/right/damping default=.16 min=0 max=2 step=.001
|
||||
param path=/bird/left/stiffness default=.025 min=0 max=1 step=.001
|
||||
param path=/bird/right/stiffness default=.03 min=0 max=1 step=.001
|
||||
param path=/bird/left/drive default=1.2 min=0 max=4 step=.001
|
||||
param path=/bird/right/drive default=1.1 min=0 max=4 step=.001
|
||||
param path=/bird/left/flow_scale default=1.2 min=0 max=4 step=.001
|
||||
param path=/bird/right/flow_scale default=1.1 min=0 max=4 step=.001
|
||||
param path=/bird/left/tissue_loss default=.18 min=0 max=1 step=.001
|
||||
param path=/bird/right/tissue_loss default=.20 min=0 max=1 step=.001
|
||||
param path=/bird/left/load_coupling default=.42 min=0 max=2 step=.001
|
||||
param path=/bird/right/load_coupling default=.42 min=0 max=2 step=.001
|
||||
param path=/bird/left/rest_opening default=.025 min=0 max=1 step=.001
|
||||
|
|
@ -31,8 +33,8 @@ path name=left_bronchus length_cm=3.8 diameters=.22,.30,.36,.42
|
|||
path name=right_bronchus length_cm=3.6 diameters=.20,.28,.34,.40
|
||||
path name=trachea length_cm=8.4 diameters=.38,.48,.56,.46
|
||||
|
||||
source_port name=left_labium path=left_bronchus kind=syrinx model=tissue_valve position=0 pressure=@/bird/left/pressure tension=@/bird/left/tension opening=@/bird/left/opening noise=.025 impedance=@/bird/load mass=@/bird/left/mass damping=@/bird/left/damping stiffness=@/bird/left/stiffness saturation=.9 drive=@/bird/left/drive load_coupling=@/bird/left/load_coupling rest_opening=@/bird/left/rest_opening
|
||||
source_port name=right_labium path=right_bronchus kind=syrinx model=tissue_valve position=0 pressure=@/bird/right/pressure tension=@/bird/right/tension opening=@/bird/right/opening noise=.02 balance=.96 impedance=@/bird/load mass=@/bird/right/mass damping=@/bird/right/damping stiffness=@/bird/right/stiffness saturation=.9 drive=@/bird/right/drive load_coupling=@/bird/right/load_coupling rest_opening=@/bird/right/rest_opening
|
||||
source_port name=left_labium path=left_bronchus kind=syrinx model=tissue_valve position=0 pressure=@/bird/left/pressure tension=@/bird/left/tension opening=@/bird/left/opening noise=.025 impedance=@/bird/load mass=@/bird/left/mass damping=@/bird/left/damping stiffness=@/bird/left/stiffness saturation=.9 flow_scale=@/bird/left/flow_scale tissue_loss=@/bird/left/tissue_loss aperture_shape=.40 flow_loss=.35 load_coupling=@/bird/left/load_coupling rest_opening=@/bird/left/rest_opening
|
||||
source_port name=right_labium path=right_bronchus kind=syrinx model=tissue_valve position=0 pressure=@/bird/right/pressure tension=@/bird/right/tension opening=@/bird/right/opening noise=.02 balance=.96 impedance=@/bird/load mass=@/bird/right/mass damping=@/bird/right/damping stiffness=@/bird/right/stiffness saturation=.9 flow_scale=@/bird/right/flow_scale tissue_loss=@/bird/right/tissue_loss aperture_shape=.40 flow_loss=.35 load_coupling=@/bird/right/load_coupling rest_opening=@/bird/right/rest_opening
|
||||
|
||||
terminal name=left_merge path=left_bronchus position=1 kind=junction area_scale=1
|
||||
terminal name=right_merge path=right_bronchus position=1 kind=junction area_scale=1
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ area_curve name=oral_vowel length_cm=17 diameters=.55,.72,1.05,1.45,1.58,1.30,.8
|
|||
path name=trachea area_curve=tracheal_tube loss=.998 loss_model=viscous
|
||||
path name=oral area_curve=oral_vowel loss=.997 loss_model=birkholz_2024 tongue_index=@/human/tongue/index tongue_diameter=@/human/tongue/diameter constriction_index=@/human/constriction/index constriction_diameter=@/human/constriction/diameter lip=@/human/lip/opening
|
||||
|
||||
source_port name=folds path=trachea kind=glottal law=two_mass position=1 pressure=@/human/subglottal tension=@/human/fold/tension opening=@/human/fold/opening noise=.035 upper_mass=.22 lower_mass=.36 upper_stiffness=.04 lower_stiffness=.06 coupling_stiffness=.09 collision_stiffness=.62 collision_damping=.18 vertical_phase=.24 reservoir_pressure=1 downstream_pressure=.05 load_coupling=.42 rest_opening=.012 drive=1.05
|
||||
source_port name=folds path=trachea kind=glottal law=two_mass position=1 pressure=@/human/subglottal tension=@/human/fold/tension opening=@/human/fold/opening noise=.035 upper_mass=.22 lower_mass=.36 upper_stiffness=.04 lower_stiffness=.06 coupling_stiffness=.09 collision_stiffness=.62 collision_damping=.18 vertical_phase=.24 flow_scale=1.05 tissue_loss=.20 aperture_shape=.48 flow_loss=.40 reservoir_pressure=1 downstream_pressure=.05 load_coupling=.42 rest_opening=.012
|
||||
|
||||
terminal name=subglottal_wall path=trachea position=0 kind=closed reflection=.78
|
||||
terminal name=trachea_top path=trachea position=1 kind=junction
|
||||
|
|
|
|||
|
|
@ -917,7 +917,10 @@ public static class FaustEmitter
|
|||
var damping = $"max(0.0, {parameters.Expression(OwnerField(path, "damping"), port.Damping)})";
|
||||
var stiffness = $"max(0.0, {parameters.Expression(OwnerField(path, "stiffness"), port.Stiffness)})";
|
||||
var saturation = $"max(0.0, {parameters.Expression(OwnerField(path, "saturation"), port.Saturation)})";
|
||||
var drive = $"max(0.0, {parameters.Expression(OwnerField(path, "drive"), port.Drive)})";
|
||||
var flowScale = $"max(0.0, {parameters.Expression(OwnerField(path, "flow_scale"), port.FlowScale * MathF.Max(0, port.Drive))})";
|
||||
var tissueLoss = $"clip01({parameters.Expression(OwnerField(path, "tissue_loss"), port.TissueLoss)})";
|
||||
var apertureShape = $"clip01({parameters.Expression(OwnerField(path, "aperture_shape"), port.ApertureShape)})";
|
||||
var flowLoss = $"max(0.0, {parameters.Expression(OwnerField(path, "flow_loss"), port.FlowLoss)})";
|
||||
var loadCoupling = $"max(0.0, {parameters.Expression(OwnerField(path, "load_coupling"), port.LoadCoupling)})";
|
||||
var restOpening = $"max(0.0, {parameters.Expression(OwnerField(path, "rest_opening"), port.RestOpening)})";
|
||||
var effectivePressure = localPressure is null
|
||||
|
|
@ -941,7 +944,7 @@ public static class FaustEmitter
|
|||
var releaseBurstGate = $"clip01({opening} / 0.8) * {release}";
|
||||
if (IsTissueValveSource(port))
|
||||
{
|
||||
return TissueValveInlineExpression(frequency, pressure, tension, opening, noise, balance, mass, damping, stiffness, saturation, drive, loadCoupling, restOpening, localPressure);
|
||||
return TissueValveInlineExpression(frequency, pressure, tension, opening, noise, balance, mass, damping, stiffness, saturation, flowScale, tissueLoss, apertureShape, flowLoss, loadCoupling, restOpening, localPressure);
|
||||
}
|
||||
|
||||
return port.Kind switch
|
||||
|
|
@ -977,7 +980,10 @@ public static class FaustEmitter
|
|||
string damping,
|
||||
string stiffness,
|
||||
string saturation,
|
||||
string drive,
|
||||
string flowScale,
|
||||
string tissueLoss,
|
||||
string apertureShape,
|
||||
string flowLoss,
|
||||
string loadCoupling,
|
||||
string restOpening,
|
||||
string? localPressure)
|
||||
|
|
@ -985,14 +991,16 @@ public static class FaustEmitter
|
|||
var loadPressure = localPressure ?? "0.0";
|
||||
var stiffnessHint = $"max(0.00002, min(0.16, pow(2.0 * ma.PI * max(20.0, {frequency}) / ma.SR, 2.0)))";
|
||||
var effectiveStiffness = $"max(({stiffness}), ({stiffnessHint}) * (0.35 + 1.65 * ({tension})))";
|
||||
var pressureDrive = $"max(0.0, ({pressure}) * ({drive}) - ({loadCoupling}) * ({loadPressure}))";
|
||||
var velocityDecay = $"min(0.9995, max(0.20, 1.0 - ((0.008 + 0.08 * ({damping})) / ({mass}))))";
|
||||
var pressureDrive = $"max(0.0, ({pressure}) - ({loadCoupling}) * ma.tanh({loadPressure}))";
|
||||
var velocityDecay = $"min(0.9995, max(0.20, 1.0 - ((0.008 + 0.08 * ({damping}) + 0.055 * ({tissueLoss})) / ({mass}))))";
|
||||
var displacementDecay = $"min(0.9998, max(0.20, 1.0 - 0.0008 / ({mass})))";
|
||||
var velocity = $"((({pressureDrive}) * (0.0004 + 0.0024 * (1.0 - clip01({opening}))) - ({loadCoupling}) * ({loadPressure}) * 0.001) : + ~ *(({velocityDecay}) / (1.0 + 10.0 * ({effectiveStiffness}) + 0.4 * ({saturation}))))";
|
||||
var displacement = $"(({velocity}) : + ~ *(({displacementDecay}) / (1.0 + 1.5 * ({effectiveStiffness}))))";
|
||||
var aperture = $"max(0.0, ({restOpening}) + ({opening}) + ({displacement}) - ({saturation}) * pow(({displacement}), 3.0))";
|
||||
var linearAperture = $"max(0.0, ({restOpening}) + ({opening}) + ({displacement}) - ({saturation}) * pow(({displacement}), 3.0))";
|
||||
var aperture = $"(({linearAperture}) * (1.0 - 0.55 * ({apertureShape})) + pow(({linearAperture}), 2.0) * (0.55 * ({apertureShape})))";
|
||||
var flowResistance = $"(1.0 + ({flowLoss}) * (0.35 + 1.8 / max(0.035, ({aperture}) + ({restOpening}))))";
|
||||
var turbulence = $"(no.noise : fi.highpass(2, 1200.0 + 2800.0 * clip01(1.0 - ({aperture}))))";
|
||||
return $"(ma.tanh(({pressureDrive}) * ({aperture}) * (2.0 + 10.0 * ({drive}))) + ({turbulence}) * ({noise}) * ({pressureDrive}) * clip01({aperture}) * (1.0 - 0.55 * ({tension}))) * ({balance})";
|
||||
return $"(ma.tanh((({pressureDrive}) * ({aperture}) * (1.5 + 3.5 * ({flowScale}))) / ({flowResistance})) * ({flowScale}) + ({turbulence}) * ({noise}) * ({pressureDrive}) * clip01({aperture}) * (1.0 - 0.55 * ({tension})) / ({flowResistance})) * ({balance})";
|
||||
}
|
||||
|
||||
private static string GlottalSourceExpression(
|
||||
|
|
@ -1625,7 +1633,10 @@ public static class FaustEmitter
|
|||
var damping = $"max(0.0, {parameters.Expression(OwnerField(path, "damping"), port.Damping)})";
|
||||
var stiffness = $"max(0.0, {parameters.Expression(OwnerField(path, "stiffness"), port.Stiffness)})";
|
||||
var saturation = $"max(0.0, {parameters.Expression(OwnerField(path, "saturation"), port.Saturation)})";
|
||||
var drive = $"max(0.0, {parameters.Expression(OwnerField(path, "drive"), port.Drive)})";
|
||||
var flowScale = $"max(0.0, {parameters.Expression(OwnerField(path, "flow_scale"), port.FlowScale * MathF.Max(0, port.Drive))})";
|
||||
var tissueLoss = $"clip01({parameters.Expression(OwnerField(path, "tissue_loss"), port.TissueLoss)})";
|
||||
var apertureShape = $"clip01({parameters.Expression(OwnerField(path, "aperture_shape"), port.ApertureShape)})";
|
||||
var flowLoss = $"max(0.0, {parameters.Expression(OwnerField(path, "flow_loss"), port.FlowLoss)})";
|
||||
var loadCoupling = $"max(0.0, {parameters.Expression(OwnerField(path, "load_coupling"), port.LoadCoupling)})";
|
||||
var restOpening = $"max(0.0, {parameters.Expression(OwnerField(path, "rest_opening"), port.RestOpening)})";
|
||||
var upperMass = $"max(0.02, {parameters.Expression(OwnerField(path, "upper_mass"), port.UpperMass)})";
|
||||
|
|
@ -1644,18 +1655,23 @@ public static class FaustEmitter
|
|||
: $"{prefix}_stiffness_hint * (0.35 + 1.65 * ({tension}))";
|
||||
|
||||
source.AppendLine($" {prefix}_stiffness_hint = max(0.00002, min(0.16, pow(2.0 * ma.PI * max(20.0, {frequency}) / ma.SR, 2.0)));");
|
||||
source.AppendLine($" {prefix}_reservoir_pressure = ({pressure}) * ({drive}) * ({reservoirPressure});");
|
||||
source.AppendLine($" {prefix}_flow_scale = {flowScale};");
|
||||
source.AppendLine($" {prefix}_tissue_loss = {tissueLoss};");
|
||||
source.AppendLine($" {prefix}_aperture_shape = {apertureShape};");
|
||||
source.AppendLine($" {prefix}_flow_loss = {flowLoss};");
|
||||
source.AppendLine($" {prefix}_reservoir_pressure = ({pressure}) * ({reservoirPressure});");
|
||||
source.AppendLine($" {prefix}_downstream_pressure = ({downstreamPressure}) + ({loadCoupling}) * ma.tanh({prefix}_load_pressure);");
|
||||
source.AppendLine($" {prefix}_pressure_drive = max(0.0, {prefix}_reservoir_pressure - {prefix}_downstream_pressure);");
|
||||
source.AppendLine($" {prefix}_stiffness = {effectiveStiffness};");
|
||||
source.AppendLine($" {prefix}_modal_frequency = max(45.0, min(10000.0, (ma.SR / (2.0 * ma.PI)) * sqrt(max(0.00002, {prefix}_stiffness) / ({mass}))));");
|
||||
source.AppendLine($" {prefix}_load_detune = 1.0 - 0.035 * ma.tanh({prefix}_load_pressure * ({loadCoupling}));");
|
||||
source.AppendLine($" {prefix}_oscillation_gate = clip01(({prefix}_pressure_drive - 0.035 - 0.18 * clip01({opening})) * (2.4 + 2.6 * ({drive})));");
|
||||
source.AppendLine($" {prefix}_modal_q = 3.0 + 24.0 * clip01(({pressure}) * (1.0 - 0.45 * ({damping})) + 0.35 * ({tension}));");
|
||||
source.AppendLine($" {prefix}_oscillation_threshold = 0.030 + 0.070 * ({damping}) + 0.080 * {prefix}_tissue_loss + 0.18 * clip01({opening});");
|
||||
source.AppendLine($" {prefix}_oscillation_gate = clip01(({prefix}_pressure_drive - {prefix}_oscillation_threshold) * (3.0 + 1.6 * max(0.0, 1.0 - ({damping}))));");
|
||||
source.AppendLine($" {prefix}_modal_q = 3.0 + 22.0 * clip01(({pressure}) * (1.0 - 0.45 * ({damping}) - 0.35 * {prefix}_tissue_loss) + 0.35 * ({tension}));");
|
||||
source.AppendLine($" {prefix}_modal_seed = (no.noise * 0.018 + {prefix}_pressure_drive * max(0.0, 0.22 - clip01({opening})) * 0.16);");
|
||||
source.AppendLine($" {prefix}_modal_ring = {prefix}_modal_seed : fi.resonbp({prefix}_modal_frequency, {prefix}_modal_q, 1);");
|
||||
source.AppendLine($" {prefix}_modal_oscillator = os.osc({prefix}_modal_frequency * {prefix}_load_detune) * {prefix}_oscillation_gate;");
|
||||
source.AppendLine($" {prefix}_modal_tissue = ({prefix}_modal_oscillator * (0.70 + 0.80 * ({tension})) + {prefix}_modal_ring * 0.35) * (1.0 - 0.35 * ({damping}));");
|
||||
source.AppendLine($" {prefix}_modal_tissue = ({prefix}_modal_oscillator * (0.70 + 0.80 * ({tension})) + {prefix}_modal_ring * 0.35) * max(0.0, 1.0 - 0.35 * ({damping}) - 0.45 * {prefix}_tissue_loss);");
|
||||
switch (port.Law)
|
||||
{
|
||||
case AcousticValveLaw.TwoMass:
|
||||
|
|
@ -1663,8 +1679,8 @@ public static class FaustEmitter
|
|||
source.AppendLine($" {prefix}_upper_stiffness_effective = max(({upperStiffness}), {prefix}_stiffness * (0.80 + 0.45 * ({tension})));");
|
||||
source.AppendLine($" {prefix}_lower_stiffness_effective = max(({lowerStiffness}), {prefix}_stiffness * (1.05 + 0.55 * ({tension})));");
|
||||
source.AppendLine($" {prefix}_coupling_stiffness = ({couplingStiffness}) * (1.0 + 1.5 * ({tension}));");
|
||||
source.AppendLine($" {prefix}_lower_velocity_decay = min(0.9995, max(0.20, 1.0 - ((0.010 + 0.090 * ({damping}) + 0.040 * ({collisionDamping})) / ({lowerMass}))));");
|
||||
source.AppendLine($" {prefix}_upper_velocity_decay = min(0.9995, max(0.20, 1.0 - ((0.012 + 0.105 * ({damping}) + 0.030 * ({collisionDamping})) / ({upperMass}))));");
|
||||
source.AppendLine($" {prefix}_lower_velocity_decay = min(0.9995, max(0.20, 1.0 - ((0.010 + 0.090 * ({damping}) + 0.040 * ({collisionDamping}) + 0.055 * {prefix}_tissue_loss) / ({lowerMass}))));");
|
||||
source.AppendLine($" {prefix}_upper_velocity_decay = min(0.9995, max(0.20, 1.0 - ((0.012 + 0.105 * ({damping}) + 0.030 * ({collisionDamping}) + 0.055 * {prefix}_tissue_loss) / ({upperMass}))));");
|
||||
source.AppendLine($" {prefix}_lower_force = ({prefix}_pressure_drive * (0.0005 + 0.0028 * (1.0 - clip01({opening}))) - ({loadCoupling}) * {prefix}_load_pressure * 0.0012) / ({lowerMass});");
|
||||
source.AppendLine($" {prefix}_upper_force = ({prefix}_pressure_drive * (0.0003 + 0.0018 * (1.0 - clip01({opening}))) - ({loadCoupling}) * {prefix}_load_pressure * 0.0008) / ({upperMass});");
|
||||
source.AppendLine($" {prefix}_lower_velocity = {prefix}_lower_force : + ~ *({prefix}_lower_velocity_decay / (1.0 + 10.0 * {prefix}_lower_stiffness_effective + {prefix}_coupling_stiffness + 0.4 * ({saturation})));");
|
||||
|
|
@ -1675,19 +1691,21 @@ public static class FaustEmitter
|
|||
source.AppendLine($" {prefix}_displacement = {prefix}_lower_displacement * (1.0 - ({verticalPhase})) + ({prefix}_upper_displacement - {prefix}_collision) * ({verticalPhase});");
|
||||
break;
|
||||
default:
|
||||
source.AppendLine($" {prefix}_velocity_decay = min(0.9995, max(0.20, 1.0 - ((0.008 + 0.08 * ({damping})) / ({mass}))));");
|
||||
source.AppendLine($" {prefix}_velocity_decay = min(0.9995, max(0.20, 1.0 - ((0.008 + 0.08 * ({damping}) + 0.055 * {prefix}_tissue_loss) / ({mass}))));");
|
||||
source.AppendLine($" {prefix}_displacement_decay = min(0.9998, max(0.20, 1.0 - 0.0008 / ({mass})));");
|
||||
source.AppendLine($" {prefix}_force = ({prefix}_pressure_drive * (0.0004 + 0.0024 * (1.0 - clip01({opening}))) - ({loadCoupling}) * {prefix}_load_pressure * 0.001) / ({mass});");
|
||||
source.AppendLine($" {prefix}_velocity = {prefix}_force : + ~ *({prefix}_velocity_decay / (1.0 + 10.0 * {prefix}_stiffness + 0.4 * ({saturation})));");
|
||||
source.AppendLine($" {prefix}_displacement = {prefix}_velocity : + ~ *({prefix}_displacement_decay / (1.0 + 1.5 * {prefix}_stiffness));");
|
||||
break;
|
||||
}
|
||||
source.AppendLine($" {prefix}_aperture = max(0.0, ({restOpening}) + ({opening}) + {prefix}_displacement - ({saturation}) * pow({prefix}_displacement, 3.0));");
|
||||
source.AppendLine($" {prefix}_aperture_linear = max(0.0, ({restOpening}) + ({opening}) + {prefix}_displacement - ({saturation}) * pow({prefix}_displacement, 3.0));");
|
||||
source.AppendLine($" {prefix}_aperture = {prefix}_aperture_linear * (1.0 - 0.55 * {prefix}_aperture_shape) + pow({prefix}_aperture_linear, 2.0) * (0.55 * {prefix}_aperture_shape);");
|
||||
source.AppendLine($" {prefix}_flow_resistance = 1.0 + {prefix}_flow_loss * (0.35 + 1.8 / max(0.035, {prefix}_aperture + ({restOpening})));");
|
||||
source.AppendLine($" {prefix}_turbulence = no.noise : fi.highpass(2, 1200.0 + 2800.0 * clip01(1.0 - {prefix}_aperture));");
|
||||
source.AppendLine($" {prefix}_voicing = {prefix}_modal_tissue * (0.18 + 1.45 * ({tension})) + {prefix}_displacement * (0.03 + 0.18 * ({drive}));");
|
||||
source.AppendLine($" {prefix}_flow = ma.tanh(({prefix}_pressure_drive * {prefix}_aperture * (1.2 + 5.0 * ({drive}))) + ({prefix}_voicing * {prefix}_pressure_drive * (0.55 + 2.6 * ({drive}))));");
|
||||
source.AppendLine($" {prefix}_noise = {prefix}_turbulence * ({noise}) * {prefix}_pressure_drive * clip01({prefix}_aperture) * (1.0 - 0.55 * ({tension}));");
|
||||
source.AppendLine($" {prefix}_out = ({prefix}_flow * (0.55 + 2.6 * {prefix}_pressure_drive) + {prefix}_noise) * ({balance});");
|
||||
source.AppendLine($" {prefix}_voicing = {prefix}_modal_tissue * (0.18 + 1.45 * ({tension}));");
|
||||
source.AppendLine($" {prefix}_flow = ma.tanh((({prefix}_pressure_drive * {prefix}_aperture * (1.5 + 3.5 * {prefix}_flow_scale)) + ({prefix}_voicing * {prefix}_pressure_drive * (0.45 + 1.55 * ({tension})))) / {prefix}_flow_resistance);");
|
||||
source.AppendLine($" {prefix}_noise = {prefix}_turbulence * ({noise}) * {prefix}_pressure_drive * clip01({prefix}_aperture) * (1.0 - 0.55 * ({tension})) / {prefix}_flow_resistance;");
|
||||
source.AppendLine($" {prefix}_out = ({prefix}_flow * {prefix}_flow_scale * (0.55 + 2.6 * {prefix}_pressure_drive) + {prefix}_noise) * ({balance});");
|
||||
}
|
||||
|
||||
private static string EmitGraphContactSourceExpression(
|
||||
|
|
|
|||
|
|
@ -355,6 +355,10 @@ public sealed record AcousticSourcePort(
|
|||
float Stiffness = 0,
|
||||
float Saturation = 0.8f,
|
||||
float Drive = 1,
|
||||
float FlowScale = 1,
|
||||
float TissueLoss = 0.12f,
|
||||
float ApertureShape = 0.35f,
|
||||
float FlowLoss = 0.35f,
|
||||
float LoadCoupling = 0.35f,
|
||||
float RestOpening = 0.02f,
|
||||
AcousticValveLaw Law = AcousticValveLaw.OneMass,
|
||||
|
|
|
|||
|
|
@ -625,7 +625,11 @@ public static class PatchScript
|
|||
GetBoundFloat(fields, line, 0.18f, $"/acoustic/sources/{_acousticSourcePorts.Count}/damping", "damping", "damp"),
|
||||
GetBoundFloat(fields, line, 0, $"/acoustic/sources/{_acousticSourcePorts.Count}/stiffness", "stiffness", "spring"),
|
||||
GetBoundFloat(fields, line, 0.8f, $"/acoustic/sources/{_acousticSourcePorts.Count}/saturation", "saturation", "sat"),
|
||||
GetBoundFloat(fields, line, 1, $"/acoustic/sources/{_acousticSourcePorts.Count}/drive", "drive", "flow_gain"),
|
||||
1,
|
||||
GetBoundFloat(fields, line, 1, $"/acoustic/sources/{_acousticSourcePorts.Count}/flow_scale", "flow_scale", "flow_gain", "source_gain", "drive"),
|
||||
GetBoundFloat(fields, line, 0.12f, $"/acoustic/sources/{_acousticSourcePorts.Count}/tissue_loss", "tissue_loss", "viscous_loss", "tissue_damping"),
|
||||
GetBoundFloat(fields, line, 0.35f, $"/acoustic/sources/{_acousticSourcePorts.Count}/aperture_shape", "aperture_shape", "aperture_law"),
|
||||
GetBoundFloat(fields, line, 0.35f, $"/acoustic/sources/{_acousticSourcePorts.Count}/flow_loss", "flow_loss", "flow_resistance", "airflow_loss"),
|
||||
GetBoundFloat(fields, line, 0.35f, $"/acoustic/sources/{_acousticSourcePorts.Count}/load_coupling", "load_coupling", "load_feedback"),
|
||||
GetBoundFloat(fields, line, 0.02f, $"/acoustic/sources/{_acousticSourcePorts.Count}/rest_opening", "rest_opening", "rest_aperture"),
|
||||
ParseAcousticValveLaw(GetAny(fields, ["law", "valve_law"], kind == AcousticSourceKind.Glottal ? "two_mass" : "one_mass"), line),
|
||||
|
|
|
|||
|
|
@ -214,3 +214,4 @@
|
|||
{"evidence":"Warbling White-eye visual audition exposed two source-ownership errors: graph tissue-valve lowering still let `freq=` impose a stiffness floor even when stiffness was explicit/parameter-bound, and direct displacement voicing injected low-frequency junk instead of only shaping aperture. Fixed graph lowering so explicit stiffness owns effective stiffness, lifted the graph tissue modal ceiling to 10 kHz for small syrinx/alien sources, and reduced modal/displacement flow drive to avoid square-wave broadband saturation. New audition artifacts under `artifacts/listening/warbling-white-eye-20260528T220500961` include five WAVs plus reference/candidate spectrogram comparisons; `05-single-trace.wav` is the clearest Warbling White-eye-shaped candidate by eye.","claim":"Bird-like graph vocalization now depends on visible phrase gestures, realtime stiffness/pressure/opening curves, and source-flow ownership rather than metrics or a fixed `freq=` rail. Future syrinx fitting should start from single-dominant-labium traces, then add bilateral behavior only when the spectrogram needs it.","timestamp":"2026-05-28T22:32:00+01:00","topic":"warbling-white-eye-visual-audition"}
|
||||
{"evidence":"A visual review of the Warbling White-eye comparison showed the previous best candidate still failed the reference: its contours were piecewise straight and its harmonic ladder was too strong. Added `interp=smooth` control curves lowered to Faust `seg_smooth` smoothstep segments, then rerendered the Warbling White-eye audition with smooth pressure/opening/tension/stiffness gestures and a low-drive single-labium candidate. `artifacts/listening/warbling-white-eye-20260528T220500961/06-smooth-low-drive.compare.png` now shows curved motif contours and much weaker harmonics, though it is still only a rough birdlike gesture, not a species-quality match.","claim":"Smooth realtime gesture semantics are required for vocal modeling. Straight spectral contours are often authored linear control curves leaking through the physical model, so future bird/human fitting should use smooth motor gestures before adding morphology changes or spectral compensators.","timestamp":"2026-05-28T22:50:00+01:00","topic":"smooth-vocal-gestures"}
|
||||
{"evidence":"Created `research/vocal-source-grounding` with downloaded/captured references on MEAD source physics, syrinx modeling, two-mass vocal fold modeling, self-oscillating vocal fold experiments, Birkholz 2024 pressure losses, and Faust physical modeling primitives. The grounding pass found `drive` is currently split-brained: it scales reservoir pressure, phonation gate, and modal/displacement brightness. Literature points instead to pressure as energy input, tissue mass/stiffness/damping/collision as source morphology, aperture/area-dependent flow loss as pressure-flow shaping, and tract/radiation load as spectral/acoustic coupling.","claim":"The next valve-law cut should demote generic `drive` into a calibration/compatibility alias, then make harmonic richness and ease of oscillation emerge from explicit morphology, pressure-flow loss, collision/contact, damping, and graph load rather than a timbre rescue knob.","timestamp":"2026-05-28T23:12:00+01:00","topic":"vocal-source-grounding"}
|
||||
{"evidence":"Demoted graph tissue-valve `drive` from split-brained vocal authority into a parser compatibility alias for `flow_scale`, added explicit `flow_scale`, `tissue_loss`, `aperture_shape`, and `flow_loss` source-port fields, and changed Faust graph lowering so reservoir pressure is pressure-owned while oscillation threshold/Q, velocity decay, aperture law, and pressure-flow resistance come from physical morphology/load controls. Canonical human, bird, and alien graph patches now use the new fields. Focused parser/export/render tests passed, class-sliced non-PT suites passed, and fresh Warbling White-eye audition artifacts were written under `artifacts/listening/warbling-white-eye-20260529T002500-drive-demotion`. The PT accepted-utterance diagnostic renderer is unstable in this run: the mama artifact writes, then the testhost exits with code -1 before reporting a managed assertion.","claim":"Graph vocal source energy, threshold, and harmonic behavior now have separate inspectable owners. Future bird/human tuning should move through pressure, stiffness/tension, damping/tissue loss, aperture/flow resistance, collision, radiation, and graph load instead of reviving a generic vocal drive knob. The next cleanup should inspect the remaining low-frequency flow floor/radiation normalization and the PT diagnostic testhost crash, not use the crash as permission to restore a generic drive knob.","timestamp":"2026-05-29T00:20:00+01:00","topic":"graph-tissue-valve-drive-demotion"}
|
||||
|
|
|
|||
|
|
@ -161,15 +161,16 @@ public sealed class PatchScriptTests
|
|||
param path=/voice/left_mass default=.32 min=.02 max=2 step=.001
|
||||
param path=/voice/left_damping default=.16 min=0 max=2 step=.001
|
||||
param path=/voice/left_stiffness default=.03 min=0 max=1 step=.001
|
||||
param path=/voice/left_drive default=1.2 min=0 max=4 step=.001
|
||||
param path=/voice/left_flow default=1.2 min=0 max=4 step=.001
|
||||
param path=/voice/left_loss default=.22 min=0 max=1 step=.001
|
||||
param path=/voice/left_load_coupling default=.44 min=0 max=2 step=.001
|
||||
param path=/voice/left_rest_opening default=.03 min=0 max=1 step=.001
|
||||
param path=/voice/throat_opening default=.8 min=0 max=1 step=.001
|
||||
param path=/voice/mouth_opening default=1.2 min=0 max=2 step=.001
|
||||
path name=trachea length_cm=12 diameters=.4,.7,1,1
|
||||
path name=oral length_cm=17 diameters=.6,1.1,1.6,1.2,.8
|
||||
source_port name=left_labium path=trachea model=tissue_valve position=0 pressure=@/voice/left_pressure tension=.55 opening=.4 noise=.02 impedance=@/voice/source_load mass=@/voice/left_mass damping=@/voice/left_damping stiffness=@/voice/left_stiffness saturation=.9 drive=@/voice/left_drive load_coupling=@/voice/left_load_coupling rest_opening=@/voice/left_rest_opening
|
||||
source_port name=right_labium path=trachea kind=labial position=0 pressure=.65 tension=.5 opening=.45 noise=.03 balance=.8 position_index=.12 position_width=.05 position_index_scale=1
|
||||
source_port name=left_labium path=trachea model=tissue_valve position=0 pressure=@/voice/left_pressure tension=.55 opening=.4 noise=.02 impedance=@/voice/source_load mass=@/voice/left_mass damping=@/voice/left_damping stiffness=@/voice/left_stiffness saturation=.9 flow_scale=@/voice/left_flow tissue_loss=@/voice/left_loss aperture_shape=.42 flow_loss=.55 load_coupling=@/voice/left_load_coupling rest_opening=@/voice/left_rest_opening
|
||||
source_port name=right_labium path=trachea kind=labial position=0 pressure=.65 tension=.5 opening=.45 noise=.03 balance=.8 position_index=.12 position_width=.05 position_index_scale=1 drive=.8
|
||||
branch name=throat from_path=trachea from_position=.9 to_path=oral kind=bronchial opening=@/voice/throat_opening coupling=.7
|
||||
radiation_port name=mouth path=oral kind=lip position=1 opening=@/voice/mouth_opening reflection=-.82
|
||||
wave_clock name=continuous strategy=thiran order=1 max_delay=4096 smoothing_ms=3
|
||||
|
|
@ -196,6 +197,11 @@ public sealed class PatchScriptTests
|
|||
Assert.Equal(AcousticSourceKind.Labial, patch.AcousticSourcePorts[1].Kind);
|
||||
Assert.All(patch.AcousticSourcePorts, port => Assert.Equal(AcousticSourceModel.TissueValve, port.Model));
|
||||
Assert.Equal(.9f, patch.AcousticSourcePorts[0].Saturation, 5);
|
||||
Assert.Equal(1.2f, patch.AcousticSourcePorts[0].FlowScale, 5);
|
||||
Assert.Equal(.22f, patch.AcousticSourcePorts[0].TissueLoss, 5);
|
||||
Assert.Equal(.42f, patch.AcousticSourcePorts[0].ApertureShape, 5);
|
||||
Assert.Equal(.55f, patch.AcousticSourcePorts[0].FlowLoss, 5);
|
||||
Assert.Equal(.8f, patch.AcousticSourcePorts[1].FlowScale, 5);
|
||||
Assert.NotNull(patch.AcousticSourcePorts[1].PositionControl);
|
||||
Assert.Equal(AcousticBranchKind.Bronchial, Assert.Single(patch.AcousticBranches).Kind);
|
||||
Assert.Equal(AcousticRadiationKind.Lip, Assert.Single(patch.AcousticRadiationPorts).Kind);
|
||||
|
|
@ -205,7 +211,8 @@ public sealed class PatchScriptTests
|
|||
Assert.Contains(patch.ParameterBindings, binding => binding.FieldPath == "/acoustic/sources/0/mass");
|
||||
Assert.Contains(patch.ParameterBindings, binding => binding.FieldPath == "/acoustic/sources/0/damping");
|
||||
Assert.Contains(patch.ParameterBindings, binding => binding.FieldPath == "/acoustic/sources/0/stiffness");
|
||||
Assert.Contains(patch.ParameterBindings, binding => binding.FieldPath == "/acoustic/sources/0/drive");
|
||||
Assert.Contains(patch.ParameterBindings, binding => binding.FieldPath == "/acoustic/sources/0/flow_scale");
|
||||
Assert.Contains(patch.ParameterBindings, binding => binding.FieldPath == "/acoustic/sources/0/tissue_loss");
|
||||
Assert.Contains(patch.ParameterBindings, binding => binding.FieldPath == "/acoustic/sources/0/load_coupling");
|
||||
Assert.Contains(patch.ParameterBindings, binding => binding.FieldPath == "/acoustic/sources/0/rest_opening");
|
||||
Assert.Contains(patch.ParameterBindings, binding => binding.FieldPath == "/acoustic/branches/0/opening");
|
||||
|
|
@ -225,6 +232,10 @@ public sealed class PatchScriptTests
|
|||
Assert.Contains("graph_source_right_labium", export.Source);
|
||||
Assert.Contains("_load_pressure", export.Source);
|
||||
Assert.Contains("_pressure_drive", export.Source);
|
||||
Assert.Contains("_flow_scale", export.Source);
|
||||
Assert.Contains("_tissue_loss", export.Source);
|
||||
Assert.Contains("_aperture_shape", export.Source);
|
||||
Assert.Contains("_flow_resistance", export.Source);
|
||||
Assert.Contains("_velocity", export.Source);
|
||||
Assert.Contains("_displacement", export.Source);
|
||||
Assert.Contains("_aperture", export.Source);
|
||||
|
|
@ -657,6 +668,10 @@ public sealed class PatchScriptTests
|
|||
Assert.Contains("_modal_frequency", export.Source);
|
||||
Assert.Contains("_modal_tissue", export.Source);
|
||||
Assert.Contains("_voicing", export.Source);
|
||||
Assert.Contains("_flow_scale", export.Source);
|
||||
Assert.Contains("_tissue_loss", export.Source);
|
||||
Assert.Contains("_flow_resistance", export.Source);
|
||||
Assert.DoesNotContain("_reservoir_pressure = (clip01(param_0)) * (", export.Source);
|
||||
Assert.Contains("graph_segment_loss_", export.Source);
|
||||
Assert.Contains("graph_radiation_model_mouth", export.Source);
|
||||
Assert.Contains("hslider(\"/curves/pressure_path/depth\"", export.Source);
|
||||
|
|
@ -1578,8 +1593,8 @@ public sealed class PatchScriptTests
|
|||
path name=left_bronchus length_cm=3.8 diameters=.22,.30,.36,.42
|
||||
path name=right_bronchus length_cm=3.6 diameters=.20,.28,.34,.40
|
||||
path name=trachea length_cm=8.4 diameters=.38,.48,.56,.46
|
||||
source_port name=left_labium path=left_bronchus kind=syrinx position=0 pressure=.82 tension=.44 opening=.22 noise=.015 impedance=.7 mass=.32 damping=.14 stiffness=.025 saturation=.9 drive=1.2 load_coupling=.42 rest_opening=.025
|
||||
source_port name=right_labium path=right_bronchus kind=syrinx position=0 pressure=.70 tension=.51 opening=.20 noise=.015 balance=.96 impedance=.7 mass=.34 damping=.16 stiffness=.03 saturation=.9 drive=1.1 load_coupling=.42 rest_opening=.025
|
||||
source_port name=left_labium path=left_bronchus kind=syrinx position=0 pressure=.82 tension=.44 opening=.22 noise=.015 impedance=.7 mass=.32 damping=.14 stiffness=.025 saturation=.9 flow_scale=1.2 tissue_loss=.18 aperture_shape=.4 flow_loss=.35 load_coupling=.42 rest_opening=.025
|
||||
source_port name=right_labium path=right_bronchus kind=syrinx position=0 pressure=.70 tension=.51 opening=.20 noise=.015 balance=.96 impedance=.7 mass=.34 damping=.16 stiffness=.03 saturation=.9 flow_scale=1.1 tissue_loss=.2 aperture_shape=.4 flow_loss=.35 load_coupling=.42 rest_opening=.025
|
||||
terminal name=left_merge path=left_bronchus position=1 kind=junction area_scale=1
|
||||
terminal name=right_merge path=right_bronchus position=1 kind=junction area_scale=1
|
||||
terminal name=trachea_base path=trachea position=0 kind=junction area_scale=1
|
||||
|
|
|
|||
Loading…
Reference in a new issue