Queue audio actuator controls into Fensalir
This commit is contained in:
parent
03337cb62d
commit
5ea539bc7d
6 changed files with 55 additions and 7 deletions
|
|
@ -145,7 +145,8 @@ a named invariant that the native runtime cannot protect yet.
|
|||
service and can emit live sync telemetry with
|
||||
`MIMIR_SYNC_TELEMETRY_SECONDS`. UI and telemetry read cached reports/states;
|
||||
they do not run synchronization analysis. The same cadence now publishes the
|
||||
latest actuator command frame for telemetry/readout; Faust/native DSP still
|
||||
latest actuator command frame for telemetry/readout and queues it into
|
||||
`AquariumAudioDocument` as an audio control frame; Faust/native DSP still
|
||||
owns actual sample movement.
|
||||
- `MimirRuntime` no longer submits the legacy direct `AquariumSplineFrame`
|
||||
spectrum dashboard. Live spectrum visualization authority is the
|
||||
|
|
|
|||
|
|
@ -306,7 +306,8 @@ runtime command owner above that Faust surface: it converts smoothed sync states
|
|||
into nonnegative holdback commands, keeps source-to-`sourceN` slots stable,
|
||||
reports overflow beyond the six-source profile, and exposes the reference
|
||||
holdback separately. `MimirRuntime` updates that command frame on the sync
|
||||
analysis cadence and telemetry can print the current DSP targets. This is
|
||||
analysis cadence, queues it into `AquariumAudioDocument` as an engine audio
|
||||
control frame, and telemetry can print the current DSP targets. This is
|
||||
control-plane publication only; Faust/native DSP still has to be wired as the
|
||||
hot sample mover.
|
||||
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ using System.Numerics;
|
|||
using System.Security.Cryptography;
|
||||
using System.Text.Json;
|
||||
using Aquarium.Engine;
|
||||
using Aquarium.Engine.Audio;
|
||||
using Aquarium.Engine.Input;
|
||||
using Aquarium.Engine.Render;
|
||||
using GameCult.Caching;
|
||||
|
|
@ -1847,10 +1848,26 @@ static int RunAudioActuatorBankSmoke()
|
|||
var early = frame.Commands.First(command => string.Equals(command.SourceId, "mic-1-early", StringComparison.Ordinal));
|
||||
var late = frame.Commands.First(command => string.Equals(command.SourceId, "mic-0-late", StringComparison.Ordinal));
|
||||
var mid = frame.Commands.First(command => string.Equals(command.SourceId, "mic-2-mid", StringComparison.Ordinal));
|
||||
var audio = new AquariumAudioDocument();
|
||||
audio.EnqueueControlFrame(new AquariumAudioControlFrame(
|
||||
MimirAlignmentActuatorProfile.SixSourceFaust.Id,
|
||||
frame.ReferenceSourceId,
|
||||
frame.ReferenceHoldbackSamples,
|
||||
frame.Commands
|
||||
.Select(command => new AquariumAudioControlCommand(
|
||||
command.SourceId,
|
||||
command.TargetDelaySamples,
|
||||
command.ResampleRatio,
|
||||
command.Confidence,
|
||||
command.FaustControls))
|
||||
.ToArray(),
|
||||
frame.TruncatedSourceCount,
|
||||
Sequence: 1));
|
||||
var drained = audio.DrainControlFrames();
|
||||
|
||||
Console.WriteLine(
|
||||
$"audio-actuator-bank-smoke reference={frame.ReferenceSourceId} referenceHoldback={frame.ReferenceHoldbackSamples:0.000} commands={frame.Commands.Count} truncated={frame.TruncatedSourceCount} " +
|
||||
$"lateDelay={late.TargetDelaySamples:0.000} midDelay={mid.TargetDelaySamples:0.000} earlyDelay={early.TargetDelaySamples:0.000} ratio={early.ResampleRatio:0.000000000}");
|
||||
$"lateDelay={late.TargetDelaySamples:0.000} midDelay={mid.TargetDelaySamples:0.000} earlyDelay={early.TargetDelaySamples:0.000} ratio={early.ResampleRatio:0.000000000} audioFrames={drained.Count}");
|
||||
|
||||
return string.Equals(frame.ReferenceSourceId, "loopback-scarlett-speakers", StringComparison.Ordinal) &&
|
||||
Math.Abs(frame.ReferenceHoldbackSamples - 120.0) < 0.001 &&
|
||||
|
|
@ -1858,7 +1875,9 @@ static int RunAudioActuatorBankSmoke()
|
|||
frame.TruncatedSourceCount == 1 &&
|
||||
late.TargetDelaySamples <= mid.TargetDelaySamples &&
|
||||
mid.TargetDelaySamples < early.TargetDelaySamples &&
|
||||
early.FaustControls.ContainsKey("source1/delay_samples")
|
||||
early.FaustControls.ContainsKey("source1/delay_samples") &&
|
||||
drained.Count == 1 &&
|
||||
drained[0].Commands.Count == frame.Commands.Count
|
||||
? 0
|
||||
: 1;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -73,6 +73,7 @@ public sealed class MimirRuntime : IAquariumRuntime, IAquariumRuntimeServicesRec
|
|||
private IReadOnlyList<MimirAudioSynchronizationReport> lastAudioSynchronizationReports = [];
|
||||
private IReadOnlyList<MimirAudioSpectrumSnapshot> lastAudioSpectra = [];
|
||||
private long spectrumHistorySequence;
|
||||
private long audioActuatorFrameSequence;
|
||||
private readonly Queue<MimirSpectrumHistoryFrame> spectrumHistory = new();
|
||||
private AquariumRuntimeServices runtimeServices = AquariumRuntimeServices.Empty;
|
||||
private MimirActuatorFrame lastAudioActuatorFrame = MimirActuatorFrame.Empty;
|
||||
|
|
@ -903,9 +904,33 @@ public sealed class MimirRuntime : IAquariumRuntime, IAquariumRuntimeServicesRec
|
|||
lastAudioActuatorFrame = audioActuatorBank.Update(
|
||||
synchronization.AudioSynchronizationStates,
|
||||
audioSyncUpdateIntervalSeconds);
|
||||
PublishAudioActuatorFrame(lastAudioActuatorFrame);
|
||||
nextAudioSyncSeconds = runtimeSeconds + audioSyncUpdateIntervalSeconds;
|
||||
}
|
||||
|
||||
private void PublishAudioActuatorFrame(MimirActuatorFrame frame)
|
||||
{
|
||||
if (frame.Commands.Count == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
audio.EnqueueControlFrame(new AquariumAudioControlFrame(
|
||||
MimirAlignmentActuatorProfile.SixSourceFaust.Id,
|
||||
frame.ReferenceSourceId,
|
||||
frame.ReferenceHoldbackSamples,
|
||||
frame.Commands
|
||||
.Select(command => new AquariumAudioControlCommand(
|
||||
command.SourceId,
|
||||
command.TargetDelaySamples,
|
||||
command.ResampleRatio,
|
||||
command.Confidence,
|
||||
command.FaustControls))
|
||||
.ToArray(),
|
||||
frame.TruncatedSourceCount,
|
||||
++audioActuatorFrameSequence));
|
||||
}
|
||||
|
||||
private void UpdateAudioSpectra()
|
||||
{
|
||||
if (runtimeSeconds < nextSpectrumSeconds)
|
||||
|
|
|
|||
|
|
@ -184,3 +184,4 @@
|
|||
{"ts": "2026-05-27T17:19:41+01:00", "type": "verification", "status": "ok", "note": "The MF GPU direct texture path now carries D3D11/D3D12 synchronization instead of relying on flush timing. native/camera_capture/mimir_mf_gpu_capture.dll creates a shared D3D11 fence, signals it after copying the decoded GPU surface into the shared BGRA texture, and MimirMediaFoundationGpuVideoCaptureDriver carries the fence handle/value through MimirVideoFrameDescriptor into Fensalir field resource declarations. Kiyo Pro 1920x1080 MJPG->RGB32 and H264->RGB32 smokes passed with zero live CPU payload bytes, nonzero shared texture handles, nonzero producer fence handles, and valid Fensalir camera resources."}
|
||||
{"ts": "2026-05-27T17:53:38+01:00", "type": "decision", "status": "ok", "note": "Synchronized camera Texture2D resources are not a mandate to invent production visual fusion now. Camera image claims remain debug-view-only until the renderer and audio work are fixed; future camera fusion/feature-extraction lowerings need a separate selected policy decision."}
|
||||
{"ts": "2026-05-27T18:03:11+01:00", "type": "decision", "status": "ok", "note": "Runtime audio sync states now derive explicit actuator command frames through MimirAlignmentActuatorBank: measured delay remains analyzer truth, the bank converts offsets into nonnegative Faust holdback controls with stable source slots, reference holdback, and overflow reporting. This is control-plane publication only; Faust/native DSP still owns live sample movement."}
|
||||
{"ts": "2026-05-27T18:06:41+01:00", "type": "decision", "status": "ok", "note": "MimirRuntime now queues the latest MimirAlignmentActuatorBank frame into AquariumAudioDocument as an engine audio control frame. This creates the Mimir-to-Fensalir control contract for Faust/native DSP targets, but remains control-plane only until a streaming DSP sample mover consumes it."}
|
||||
|
|
|
|||
|
|
@ -182,9 +182,10 @@ accepted_design:
|
|||
actuator surface for six channels of bounded fractional delay/gain.
|
||||
`MimirAlignmentActuatorBank` now converts runtime sync states into explicit
|
||||
nonnegative Faust holdback commands with stable source slots, a separate
|
||||
reference holdback, and overflow reporting; this publishes DSP control
|
||||
targets but does not move live samples until the Faust/native hot path is
|
||||
wired. The synthetic
|
||||
reference holdback, and overflow reporting, then queues those commands into
|
||||
`AquariumAudioDocument` as engine audio control frames; this publishes DSP
|
||||
control targets but does not move live samples until the Faust/native hot
|
||||
path is wired. The synthetic
|
||||
codebook proof is `dotnet run --project
|
||||
.\src\Mimir.BufferSmoke\Mimir.BufferSmoke.csproj -- --bioacoustic-self-test`.
|
||||
`Mimir.BufferSmoke --render-chirp-bin-f32` plus
|
||||
|
|
|
|||
Loading…
Reference in a new issue