code wiki / (root) / nx_actor_role_audio_grader.nx

nx_actor_role_audio_grader.nx source

↩ module page · 183 lines · 6865 B

1// nx_actor_role_audio_grader.nx -- audio-scene-grading actor role. 2// 3// Per CARDINAL [[feedback-parallel-companion-multimodal-dnd-real-time]]: 4// the parallel companion runs DIFFERENT modalities concurrently -- 5// LLM token gen + audio grading + image grading all interleaved. This 6// adapter wraps [[nx_audio_scene_quality]] (other-agent primitive) as 7// a cooperative actor so the substrate can drive heterogeneous work, 8// not just LLM clones. 9// 10// Cooperative phases: 11// Phase 0 (INIT): no-op (reserved for future warmup) 12// Phase 1 (GRADE): calls nx_audio_scene_grade with caller bins/rms/n_sources 13// Phase 2 (EMIT): pushes AUDIO_FRAME message containing the verdict 14// overall_score (Q14) as the payload handle 15// Phase 3 (DONE): terminal 16// 17// Composes [[project-conductor-arc-phases-c-d-integrate-with-nishi-ai- 18// 2026-05-19]] -- audio grading runs through the same actor + message + 19// multiplexer substrate as LLM inference. 20 21import "nx_syscalls.nx" 22import "nx_tier.nx" 23import "nx_layer_verdict.nx" 24import "nx_audio_scene_quality.nx" 25import "nx_actor.nx" 26import "nx_message.nx" 27 28// ===== Sealed enum: NxAudioGraderPhase ============================ 29 30const NX_AG_PHASE_INIT: nx_int = 0 31const NX_AG_PHASE_GRADE: nx_int = 1 32const NX_AG_PHASE_EMIT: nx_int = 2 33const NX_AG_PHASE_DONE: nx_int = 3 34const NX_AG_PHASE_N: nx_int = 4 35 36// ===== Sealed enum: NxAudioGraderVerdict ========================== 37 38const NX_AG_V_STEPPED: nx_int = 0 39const NX_AG_V_COMPLETED: nx_int = 1 40const NX_AG_V_FAILED_GRADE: nx_int = 2 41const NX_AG_V_INVALID: nx_int = 3 42const NX_AG_V_NULL: nx_int = 4 43const NX_AG_V_N: nx_int = 5 44 45// ===== Struct: NxAudioGraderCtx =================================== 46// 47// Caller owns spectral_bins + rms_window storage; adapter owns verdict. 48 49struct NxAudioGraderCtx { 50 spectral_bins: *i64, 51 n_bins: nx_int, 52 rms_window: *i64, 53 n_frames: nx_int, 54 n_sources: nx_int, 55 verdict: *i64, // NX_LV_STRIDE i64s 56 overall_score_q14: nx_int, 57 current_phase: nx_int, 58 last_step_verdict: nx_int, 59} 60 61const NX_AG_CTX_BYTES: nx_int = 72 // 9 fields * 8 62 63// ===== Validators ================================================= 64 65func nx_ag_phase_is_valid(p: nx_int) -> nx_int { 66 if p < 0 { return 0 } 67 if p >= NX_AG_PHASE_N { return 0 } 68 return 1 69} 70 71func nx_ag_v_is_valid(v: nx_int) -> nx_int { 72 if v < 0 { return 0 } 73 if v >= NX_AG_V_N { return 0 } 74 return 1 75} 76 77// ===== Constructor ================================================ 78 79func nx_ag_actor_new(spectral_bins: *i64, 80 n_bins: nx_int, 81 rms_window: *i64, 82 n_frames: nx_int, 83 n_sources: nx_int) -> *NxAudioGraderCtx { 84 if (spectral_bins as i64) == 0 { return 0 as *NxAudioGraderCtx } 85 if (rms_window as i64) == 0 { return 0 as *NxAudioGraderCtx } 86 if n_bins <= 0 { return 0 as *NxAudioGraderCtx } 87 if n_frames <= 0 { return 0 as *NxAudioGraderCtx } 88 if n_sources < 0 { return 0 as *NxAudioGraderCtx } 89 let raw: *u8 = sys_mmap(NX_AG_CTX_BYTES) 90 let ctx: *NxAudioGraderCtx = raw as *NxAudioGraderCtx 91 ctx.spectral_bins = spectral_bins 92 ctx.n_bins = n_bins 93 ctx.rms_window = rms_window 94 ctx.n_frames = n_frames 95 ctx.n_sources = n_sources 96 ctx.verdict = sys_mmap(NX_LV_STRIDE * 8) as *i64 97 ctx.overall_score_q14 = 0 98 ctx.current_phase = NX_AG_PHASE_INIT 99 ctx.last_step_verdict = NX_AG_V_STEPPED 100 return ctx 101} 102 103// ===== Phase helpers ============================================== 104 105func _ag_step_grade(ctx: *NxAudioGraderCtx) -> nx_int { 106 nx_audio_scene_grade(ctx.spectral_bins, ctx.n_bins, 107 ctx.rms_window, ctx.n_frames, 108 ctx.n_sources, ctx.verdict) 109 // The verdict layout puts the overall pass/score at NX_LV_OFF_OVERALL; 110 // we use the AVG of the 5 axes as an honest summary since the layer 111 // verdict's overall is a refine-signal, not a pass score. 112 var sum: nx_int = 0 113 var i: nx_int = 0 114 while i < NX_AQ_AXIS_COUNT { 115 sum = sum + (ctx.verdict[NX_LV_OFF_AXIS_0 + i] as nx_int) 116 i = i + 1 117 } 118 ctx.overall_score_q14 = sum / NX_AQ_AXIS_COUNT 119 if ctx.overall_score_q14 < 0 { return NX_AG_V_FAILED_GRADE } 120 return NX_AG_V_STEPPED 121} 122 123func _ag_step_emit(ctx: *NxAudioGraderCtx, 124 bus: *NxMessageBus, 125 sender_actor_id: nx_int, 126 now_us: nx_size) -> nx_int { 127 if (bus as i64) == 0 { return NX_AG_V_STEPPED } 128 nx_ms_send_fanout(bus, sender_actor_id, NX_MS_KIND_AUDIO_FRAME, 129 ctx.overall_score_q14 as nx_size, 8, now_us) 130 return NX_AG_V_STEPPED 131} 132 133// ===== Public step ================================================ 134 135func nx_ag_actor_step(ctx: *NxAudioGraderCtx, 136 sched: *NxActorScheduler, 137 bus: *NxMessageBus, 138 actor_id: nx_int, 139 now_us: nx_size) -> nx_int { 140 if (ctx as i64) == 0 { return NX_AG_V_NULL } 141 if ctx.current_phase >= NX_AG_PHASE_DONE { return NX_AG_V_COMPLETED } 142 var v: nx_int = NX_AG_V_STEPPED 143 if ctx.current_phase == NX_AG_PHASE_INIT { v = NX_AG_V_STEPPED } 144 if ctx.current_phase == NX_AG_PHASE_GRADE { v = _ag_step_grade(ctx) } 145 if ctx.current_phase == NX_AG_PHASE_EMIT { v = _ag_step_emit(ctx, bus, actor_id, now_us) } 146 ctx.last_step_verdict = v 147 ctx.current_phase = ctx.current_phase + 1 148 if (sched as i64) != 0 { nx_ac_step(sched, actor_id, 1000, now_us) } 149 if ctx.current_phase >= NX_AG_PHASE_DONE { 150 if (sched as i64) != 0 { nx_ac_complete(sched, actor_id) } 151 return NX_AG_V_COMPLETED 152 } 153 if v != NX_AG_V_STEPPED { 154 if (sched as i64) != 0 { nx_ac_fail(sched, actor_id) } 155 return v 156 } 157 return NX_AG_V_STEPPED 158} 159 160// ===== Accessors ================================================== 161 162func nx_ag_actor_phase(ctx: *NxAudioGraderCtx) -> nx_int { 163 if (ctx as i64) == 0 { return NX_AG_PHASE_DONE } 164 return ctx.current_phase 165} 166 167func nx_ag_actor_score_q14(ctx: *NxAudioGraderCtx) -> nx_int { 168 if (ctx as i64) == 0 { return 0 } 169 return ctx.overall_score_q14 170} 171 172func nx_ag_actor_is_done(ctx: *NxAudioGraderCtx) -> nx_int { 173 if (ctx as i64) == 0 { return 0 } 174 if ctx.current_phase >= NX_AG_PHASE_DONE { return 1 } 175 return 0 176} 177 178func nx_ag_actor_axis_q14(ctx: *NxAudioGraderCtx, axis: nx_int) -> nx_int { 179 if (ctx as i64) == 0 { return 0 } 180 if axis < 0 { return 0 } 181 if axis >= NX_AQ_AXIS_COUNT { return 0 } 182 return ctx.verdict[NX_LV_OFF_AXIS_0 + axis] as nx_int 183}