/** * Runtime audio routing control for CrossPad hardware over USB MIDI SysEx. * * Speaks CROSSPAD_CMD_AUDIO_ROUTE (0x1D) from crosspad-core's SysEx protocol * (handled by platform-idf main/audio_route_control.cpp): per-codec ADC input, * USB-mic capture source, DAC output route, volume, mute, and a state query. * * Transport (v10): the crosspad-hil daemon — `midi.sysex` for each set frame, * `midi.query_route` for the read-back. The daemon owns port discovery and the * reply parse, so this module no longer shells out to `amidi` and no longer * decodes raw bytes; that also makes it work on Windows and macOS, where the * old ALSA-only path could not run at all. Frame construction stays here * because it is the part worth unit-testing without a device. */ import { z } from "zod"; import type { McpServer, RegisteredTool } from "@modelcontextprotocol/sdk/server/mcp.js"; import { type DaemonRequester } from "../hil/select.js"; import type { ToolContext } from "../tool-context.js"; export type { DaemonRequester }; export type AdcInput = "diff" | "line1" | "line2"; export type DacOutput = "line1" | "line2" | "all"; export interface AudioRouteSetParams { codec?: 0 | 1; adc_input?: AdcInput; mic_src?: 0 | 1; dac_output?: DacOutput; volume?: number; mute?: boolean; } export interface AudioRouteState { mic_src: number; adc_input: [AdcInput, AdcInput]; dac_output: [DacOutput, DacOutput]; volume: [number, number]; mute: [boolean, boolean]; } export interface AudioRouteResult { success: boolean; sent?: string[]; state?: AudioRouteState; port?: string; error?: string; } export declare const TOOL_NAME = "crosspad_audio_route"; /** One SysEx frame as the daemon's `frame` argument wants it: "F0 7D 1D 01 00 02 F7". */ export declare function hexFrame(bytes: number[]): string; /** Build the SysEx frames for a set request (exported for tests). */ export declare function buildSetFrames(p: AudioRouteSetParams): { frames: number[][]; error?: string; }; /** midi.py parse_query_reply() dict → the v9 state shape this tool has always returned. */ export declare function stateFromQuery(q: Record): AudioRouteState; export declare function crosspadAudioRouteSet(daemon: DaemonRequester, device: string | undefined, params: AudioRouteSetParams, signal?: AbortSignal): Promise; export declare function crosspadAudioRouteQuery(daemon: DaemonRequester, device: string | undefined, signal?: AbortSignal): Promise; export declare const AudioRouteInput: z.ZodObject<{ action: z.ZodEnum<{ query: "query"; set: "set"; }>; device: z.ZodOptional; codec: z.ZodOptional, z.ZodLiteral<1>]>>; adc_input: z.ZodOptional>; mic_src: z.ZodOptional, z.ZodLiteral<1>]>>; dac_output: z.ZodOptional>; volume: z.ZodOptional; mute: z.ZodOptional; }, z.core.$strip>; export type AudioRouteArgs = z.infer; export declare const O_AudioRoute: { success: z.ZodBoolean; sent: z.ZodOptional>; state: z.ZodOptional>; dac_output: z.ZodArray>; volume: z.ZodArray; mute: z.ZodArray; }, z.core.$strip>>; port: z.ZodOptional; error: z.ZodOptional>; details: z.ZodOptional>; }, z.core.$loose>]>>; resultType: z.ZodOptional; confirmation: z.ZodOptional>; tool: z.ZodOptional; hint: z.ZodOptional; }; export declare function registerAudioRouteTool(server: McpServer, ctx: ToolContext): RegisteredTool;