@audiofab-io/easy-spin-ui 0.3.4 → 0.3.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js
CHANGED
|
@@ -703,13 +703,19 @@ function F({ workletUrl: i, sampleRate: a = 32768 }) {
|
|
|
703
703
|
playing: !1,
|
|
704
704
|
bypassed: !1,
|
|
705
705
|
channelMode: "mono",
|
|
706
|
-
sampleRate: null
|
|
706
|
+
sampleRate: null,
|
|
707
|
+
blockTimeUs: null
|
|
707
708
|
}), m = e(async () => {
|
|
708
709
|
if (!o.current) return d.current ||= (async () => {
|
|
709
710
|
let e = new AudioContext({ sampleRate: a });
|
|
710
711
|
await e.audioWorklet.addModule(i);
|
|
711
712
|
let t = new AudioWorkletNode(e, "fv1-processor", { outputChannelCount: [2] });
|
|
712
|
-
t.
|
|
713
|
+
t.port.onmessage = ({ data: e }) => {
|
|
714
|
+
e?.type === "blockTime" && typeof e.us == "number" && p((t) => ({
|
|
715
|
+
...t,
|
|
716
|
+
blockTimeUs: e.us
|
|
717
|
+
}));
|
|
718
|
+
}, t.connect(e.destination), o.current = e, s.current = t, p((t) => ({
|
|
713
719
|
...t,
|
|
714
720
|
sampleRate: e.sampleRate
|
|
715
721
|
}));
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../src/components/Knob.tsx","../src/components/ProgramSelector.tsx","../src/components/ClipSelector.tsx","../src/components/PedalFace.tsx","../src/audio/binary.ts","../src/simulator/useSimulator.ts"],"sourcesContent":["import { useRef, useCallback } from 'react'\n\ninterface KnobProps {\n value: number // 0.0 – 1.0\n label: string\n onChange: (value: number) => void\n size?: number\n /** When true, render without a visible body — just a pointer indicator\n * (for overlaying on top of a pre-drawn dial graphic). */\n overlay?: boolean\n}\n\nconst SWEEP_DEG = 300\nconst MIN_DEG = -SWEEP_DEG / 2\n\nexport function Knob({ value, label, onChange, size = 56, overlay = false }: KnobProps) {\n const knobRef = useRef<SVGSVGElement>(null)\n const dragging = useRef(false)\n const startAngle = useRef(0)\n const startValue = useRef(0)\n\n const getAngleFromEvent = useCallback((e: PointerEvent) => {\n const el = knobRef.current\n if (!el) return 0\n const rect = el.getBoundingClientRect()\n const cx = rect.left + rect.width / 2\n const cy = rect.top + rect.height / 2\n return Math.atan2(e.clientY - cy, e.clientX - cx) * (180 / Math.PI)\n }, [])\n\n const onPointerDown = useCallback((e: React.PointerEvent) => {\n dragging.current = true\n startAngle.current = getAngleFromEvent(e.nativeEvent)\n startValue.current = value\n ;(e.target as Element).setPointerCapture(e.pointerId)\n }, [getAngleFromEvent, value])\n\n const onPointerMove = useCallback((e: React.PointerEvent) => {\n if (!dragging.current) return\n const angle = getAngleFromEvent(e.nativeEvent)\n const delta = angle - startAngle.current\n const norm = ((delta + 540) % 360) - 180\n const valueDelta = norm / SWEEP_DEG\n const newValue = Math.max(0, Math.min(1, startValue.current + valueDelta))\n onChange(newValue)\n }, [getAngleFromEvent, onChange])\n\n const onPointerUp = useCallback(() => {\n dragging.current = false\n }, [])\n\n const rotation = MIN_DEG + value * SWEEP_DEG\n\n const svg = (\n <svg\n ref={knobRef}\n width={overlay ? '100%' : size}\n height={overlay ? '100%' : size}\n viewBox=\"0 0 56 56\"\n className=\"cursor-grab active:cursor-grabbing select-none touch-none\"\n role=\"slider\"\n aria-valuenow={Math.round(value * 100)}\n aria-valuemin={0}\n aria-valuemax={100}\n aria-label={label}\n onPointerDown={onPointerDown}\n onPointerMove={onPointerMove}\n onPointerUp={onPointerUp}\n >\n <circle cx=\"28\" cy=\"28\" r=\"28\" fill=\"transparent\" />\n {overlay ? (\n <circle cx=\"28\" cy=\"28\" r=\"24\" fill=\"none\" stroke=\"#111\" strokeWidth=\"1.5\" />\n ) : (\n <>\n <circle cx=\"28\" cy=\"28\" r=\"26\" fill=\"none\" stroke=\"#888\" strokeWidth=\"1.5\" />\n <circle cx=\"28\" cy=\"28\" r=\"22\" fill=\"#f0f0f0\" stroke=\"#aaa\" strokeWidth=\"1\" />\n </>\n )}\n <g transform={`rotate(${rotation} 28 28)`}>\n <line\n x1=\"28\"\n y1=\"28\"\n x2=\"28\"\n y2={overlay ? 10 : 8}\n stroke={overlay ? '#111' : '#B8942C'}\n strokeWidth={overlay ? 2.5 : 2}\n strokeLinecap=\"round\"\n />\n </g>\n </svg>\n )\n\n if (overlay) {\n return svg\n }\n\n return (\n <div className=\"flex flex-col items-center gap-1\">\n {svg}\n <span className=\"text-[10px] text-text-secondary text-center leading-tight max-w-[80px] truncate\">\n {label}\n </span>\n </div>\n )\n}\n","import { useRef, useCallback } from 'react'\nimport { PROGRAM_SLOT_COUNT } from '@audiofab-io/fv1-core/pedal'\n\ninterface ProgramSelectorProps {\n selectedSlot: number\n onSelectSlot: (slot: number) => void\n slotLabels?: string[]\n /** When true, render as a rotary dial with a pointer indicator (no visible body). */\n overlay?: boolean\n}\n\nconst POS_COUNT = PROGRAM_SLOT_COUNT\nconst START_ANGLE_DEG = 180 // position 1 (lower-left)\nconst END_ANGLE_DEG = 30 + 360 // position 8 (lower-right, via the top)\nconst STEP_DEG = (END_ANGLE_DEG - START_ANGLE_DEG) / (POS_COUNT - 1)\n\nfunction angleForPosition(index0: number): number {\n return START_ANGLE_DEG + index0 * STEP_DEG\n}\n\nfunction nearestSlotFromPointerAngle(pointerDeg: number): number {\n const a = ((pointerDeg % 360) + 360) % 360\n let bestSlot = 0\n let bestDist = Infinity\n for (let i = 0; i < POS_COUNT; i++) {\n const slotAngle = ((angleForPosition(i) % 360) + 360) % 360\n let diff = Math.abs(a - slotAngle)\n if (diff > 180) diff = 360 - diff\n if (diff < bestDist) {\n bestDist = diff\n bestSlot = i\n }\n }\n return bestSlot\n}\n\n/**\n * Rotary program selector. In overlay mode it renders as a pot-style knob\n * (black circular outline + pointer) that points at the currently selected\n * slot. The knob can be dragged to change program — it snaps to the nearest\n * of the 8 discrete positions.\n */\nexport function ProgramSelector({\n selectedSlot,\n onSelectSlot,\n slotLabels,\n overlay = false,\n}: ProgramSelectorProps) {\n const knobRef = useRef<SVGSVGElement>(null)\n const dragging = useRef(false)\n\n const getAngleFromEvent = useCallback((e: PointerEvent) => {\n const el = knobRef.current\n if (!el) return 0\n const rect = el.getBoundingClientRect()\n const cx = rect.left + rect.width / 2\n const cy = rect.top + rect.height / 2\n const raw = Math.atan2(e.clientY - cy, e.clientX - cx) * (180 / Math.PI)\n return ((raw % 360) + 360) % 360\n }, [])\n\n const onPointerDown = useCallback((e: React.PointerEvent) => {\n dragging.current = true\n ;(e.target as Element).setPointerCapture(e.pointerId)\n const angle = getAngleFromEvent(e.nativeEvent)\n const nearest = nearestSlotFromPointerAngle(angle)\n if (nearest !== selectedSlot) onSelectSlot(nearest)\n }, [getAngleFromEvent, selectedSlot, onSelectSlot])\n\n const onPointerMove = useCallback((e: React.PointerEvent) => {\n if (!dragging.current) return\n const angle = getAngleFromEvent(e.nativeEvent)\n const nearest = nearestSlotFromPointerAngle(angle)\n if (nearest !== selectedSlot) onSelectSlot(nearest)\n }, [getAngleFromEvent, selectedSlot, onSelectSlot])\n\n const onPointerUp = useCallback(() => {\n dragging.current = false\n }, [])\n\n if (!overlay) {\n return (\n <div className=\"grid grid-cols-4 gap-1\">\n {Array.from({ length: POS_COUNT }, (_, i) => (\n <button\n key={i}\n onClick={() => onSelectSlot(i)}\n title={slotLabels?.[i] ?? `Slot ${i + 1}`}\n className={`w-7 h-7 rounded text-xs font-bold ${selectedSlot === i\n ? 'bg-gold text-surface'\n : 'bg-surface-hover text-text-secondary hover:bg-surface-card border border-border'\n }`}\n >\n {i + 1}\n </button>\n ))}\n </div>\n )\n }\n\n const rotation = angleForPosition(selectedSlot) - 270\n\n return (\n <svg\n ref={knobRef}\n width=\"100%\"\n height=\"100%\"\n viewBox=\"0 0 56 56\"\n className=\"cursor-grab active:cursor-grabbing select-none touch-none\"\n role=\"listbox\"\n aria-label=\"Program selector\"\n aria-activedescendant={`prog-slot-${selectedSlot}`}\n onPointerDown={onPointerDown}\n onPointerMove={onPointerMove}\n onPointerUp={onPointerUp}\n >\n <circle cx=\"28\" cy=\"28\" r=\"28\" fill=\"transparent\" />\n <circle cx=\"28\" cy=\"28\" r=\"24\" fill=\"none\" stroke=\"#111\" strokeWidth=\"1.5\" />\n <g transform={`rotate(${rotation} 28 28)`}>\n <line\n x1=\"28\"\n y1=\"28\"\n x2=\"28\"\n y2=\"10\"\n stroke=\"#111\"\n strokeWidth=\"2.5\"\n strokeLinecap=\"round\"\n />\n </g>\n </svg>\n )\n}\n","export interface ClipInfo {\n id: string\n name: string\n description?: string\n}\n\ninterface ClipSelectorProps {\n /** List of clips the consumer wants to expose. */\n clips: ClipInfo[]\n selectedClipId: string | null\n onSelect: (clipId: string) => void\n /** When true, the selector is visually disabled (e.g. while a list is loading). */\n disabled?: boolean\n}\n\n/**\n * Pure presentational dropdown for picking an audio clip. The shared package\n * has no opinion about where clips come from — consumers fetch / bundle their\n * own list and pass it in.\n */\nexport function ClipSelector({ clips, selectedClipId, onSelect, disabled = false }: ClipSelectorProps) {\n return (\n <select\n value={selectedClipId ?? ''}\n onChange={e => onSelect(e.target.value)}\n disabled={disabled}\n className=\"px-2 py-1 rounded bg-surface-hover border border-border text-xs text-text-primary focus:outline-none focus:border-gold-dim disabled:opacity-50\"\n >\n <option value=\"\" disabled>\n {disabled ? 'Loading…' : 'Select clip'}\n </option>\n {clips.map(clip => (\n <option key={clip.id} value={clip.id}>\n {clip.name}\n </option>\n ))}\n </select>\n )\n}\n","import { useState } from 'react'\nimport { Knob } from './Knob'\nimport { ProgramSelector } from './ProgramSelector'\nimport { ClipSelector, type ClipInfo } from './ClipSelector'\nimport { PROGRAM_SLOT_COUNT } from '@audiofab-io/fv1-core/pedal'\n\nexport type ChannelMode = 'mono' | 'stereo'\n\nexport interface PedalFaceProps {\n /** URL of the pedal outline graphic. Required — see assets/pedal.png in\n * this package, or bring your own. */\n pedalImageUrl: string\n\n /** Current values of the three pots, normalised 0..1. */\n pots: [number, number, number]\n onPotChange: (index: number, value: number) => void\n /** Per-pot display labels — typically the effect's `controls[].name`,\n * or `Pot 0/1/2` when the active program is unknown. */\n potLabels?: [string, string, string]\n\n /** Currently selected slot (0-based). */\n selectedSlot: number\n onSelectSlot: (slot: number) => void\n /** Display labels for each of the 8 slots. Empty / undefined means empty. */\n slotLabels?: string[]\n /** Drop handler for slot N. The data string is the platform-specific\n * payload (e.g. an effect id, a file URI). The consumer interprets it. */\n onAssignSlot?: (slotIndex: number, payload: string) => void\n onUnassignSlot?: (slotIndex: number) => void\n onUnassignAllSlots?: () => void\n /** Called when the user clicks the per-slot \"send to pedal\" icon. */\n onProgramSlot?: (slotIndex: number) => void\n /** Index of the slot currently being written to the pedal, or null. */\n programmingSlot?: number | null\n /** When set, empty slots show a \"+\" button that calls this callback —\n * used by hosts that have a notion of a \"currently tracked / active\"\n * program the user can drop into a slot. */\n onAssignTrackedToSlot?: (slotIndex: number) => void\n /** When set, Ctrl/Cmd+click and right-click on an assigned slot fires\n * this callback so hosts can \"open the source file\" — e.g. open the\n * underlying .spn / .spndiagram in an editor tab. */\n onOpenSlotSource?: (slotIndex: number) => void\n\n /** Audio clip selection — pass an empty array to hide the selector. */\n clips?: ClipInfo[]\n selectedClipId: string | null\n onSelectClip: (clipId: string) => void\n\n playing: boolean\n onPlay: () => void\n onPause: () => void\n bypassed: boolean\n onToggleBypass: () => void\n channelMode: ChannelMode\n onChannelModeChange: (mode: ChannelMode) => void\n\n /** Pedal connection state — the I/O button cluster only renders when\n * these are wired up. */\n pedalConnected?: boolean\n onConnectPedal?: () => void\n onReadPedal?: () => void\n onWritePedal?: () => void\n pedalReading?: boolean\n pedalWriting?: boolean\n}\n\n/**\n * Overlay positions as percentages of the pedal image (1573 × 2627).\n *\n * pot0 / pot1 / pot2 — potentiometer centres\n * programSelector — rotary program selector knob centre\n * led — status LED\n * footswitch — bypass footswitch centre\n */\nconst POS = {\n pot0: { left: '22.85%', top: '14%' },\n pot1: { left: '77.15%', top: '14%' },\n pot2: { left: '22.85%', top: '33.75%' },\n programSelector: { left: '76%', top: '33.75%' },\n led: { left: '50%', top: '42%' },\n footswitch: { left: '50%', top: '68.5%' },\n pot0Label: { left: '22.85%', top: '2.5%' },\n pot1Label: { left: '77.15%', top: '2.5%' },\n pot2Label: { left: '22.85%', top: '44%' },\n pedalIO: { left: '105%', top: '70%' },\n}\n\nconst KNOB_SIZE_PCT = 20\nconst FOOTSWITCH_SIZE_PCT = 14\nconst HEX_NUT_SIZE_PCT = 20\nconst LED_SIZE_PCT = 5\n\nexport function PedalFace({\n pedalImageUrl,\n pots,\n onPotChange,\n potLabels = ['Pot 0', 'Pot 1', 'Pot 2'],\n selectedSlot,\n onSelectSlot,\n slotLabels,\n onAssignSlot,\n onUnassignSlot,\n onUnassignAllSlots,\n onProgramSlot,\n programmingSlot = null,\n onAssignTrackedToSlot,\n onOpenSlotSource,\n clips,\n selectedClipId,\n onSelectClip,\n playing,\n onPlay,\n onPause,\n bypassed,\n onToggleBypass,\n channelMode,\n onChannelModeChange,\n pedalConnected = false,\n onConnectPedal,\n onReadPedal,\n onWritePedal,\n pedalReading = false,\n pedalWriting = false,\n}: PedalFaceProps) {\n const pedalBusy = pedalReading || pedalWriting\n const [dragOverSlot, setDragOverSlot] = useState<number | null>(null)\n\n const ledOn = !bypassed\n const anyAssigned = slotLabels?.some(l => l) ?? false\n const slotProgrammable = pedalConnected && !pedalBusy\n\n return (\n <div className=\"flex flex-col items-center gap-5 w-full max-w-[460px] mx-auto\">\n <div\n className=\"relative w-full max-w-[360px] pedal-outline\"\n style={{\n aspectRatio: '1573 / 2627',\n backgroundImage: `url(${pedalImageUrl})`,\n backgroundSize: 'contain',\n backgroundRepeat: 'no-repeat',\n backgroundPosition: 'center top',\n }}\n >\n <KnobOverlay\n posStyle={POS.pot0}\n sizePct={KNOB_SIZE_PCT}\n value={pots[0]}\n label={potLabels[0]}\n onChange={v => onPotChange(0, v)}\n />\n <KnobOverlay\n posStyle={POS.pot1}\n sizePct={KNOB_SIZE_PCT}\n value={pots[1]}\n label={potLabels[1]}\n onChange={v => onPotChange(1, v)}\n />\n <KnobOverlay\n posStyle={POS.pot2}\n sizePct={KNOB_SIZE_PCT}\n value={pots[2]}\n label={potLabels[2]}\n onChange={v => onPotChange(2, v)}\n />\n\n <PotLabel posStyle={POS.pot0Label} text={potLabels[0]} />\n <PotLabel posStyle={POS.pot1Label} text={potLabels[1]} />\n <PotLabel posStyle={POS.pot2Label} text={potLabels[2]} />\n\n {/* Program Selector knob */}\n <div\n className=\"absolute\"\n style={{\n left: POS.programSelector.left,\n top: POS.programSelector.top,\n width: `${KNOB_SIZE_PCT}%`,\n aspectRatio: '1 / 1',\n transform: 'translate(-50%, -50%)',\n }}\n >\n <ProgramSelector\n overlay\n selectedSlot={selectedSlot}\n onSelectSlot={onSelectSlot}\n slotLabels={slotLabels}\n />\n </div>\n\n {/* LED */}\n <div\n className=\"absolute rounded-full transition-all\"\n style={{\n left: POS.led.left,\n top: POS.led.top,\n width: `${LED_SIZE_PCT}%`,\n aspectRatio: '1 / 1',\n transform: 'translate(-50%, -50%)',\n background: ledOn\n ? 'radial-gradient(circle at 35% 30%, #ff8a8a 0%, #e11 55%, #800 100%)'\n : 'radial-gradient(circle at 35% 30%, #f2f2f2 0%, #bbb 60%, #777 100%)',\n boxShadow: ledOn\n ? '0 0 10px rgba(255, 60, 60, 0.75)'\n : 'inset 0 1px 2px rgba(0,0,0,0.25)',\n border: '1px solid #333',\n }}\n aria-label=\"Status LED\"\n />\n\n {/* Hex-shaped silver retaining nut frames the footswitch */}\n <svg\n viewBox=\"0 0 100 100\"\n className=\"absolute pointer-events-none\"\n style={{\n left: POS.footswitch.left,\n top: POS.footswitch.top,\n width: `${HEX_NUT_SIZE_PCT}%`,\n aspectRatio: '1 / 1',\n transform: 'translate(-50%, -50%)',\n filter: 'drop-shadow(0 2px 2px rgba(0,0,0,0.45))',\n }}\n >\n <defs>\n <radialGradient id=\"silverHexNut\" cx=\"40%\" cy=\"35%\" r=\"65%\">\n <stop offset=\"0%\" stopColor=\"#f8f8f8\" />\n <stop offset=\"45%\" stopColor=\"#c8c8c8\" />\n <stop offset=\"100%\" stopColor=\"#707070\" />\n </radialGradient>\n </defs>\n <polygon\n points=\"5,50 27.5,11 72.5,11 95,50 72.5,89 27.5,89\"\n fill=\"url(#silverHexNut)\"\n stroke=\"#333\"\n strokeWidth=\"2\"\n strokeLinejoin=\"round\"\n />\n </svg>\n\n {/* Pedal I/O cluster — only rendered when consumer wires it up */}\n {(onConnectPedal || onReadPedal || onWritePedal) && (\n <div\n className=\"absolute flex items-center gap-1\"\n style={{\n left: POS.pedalIO.left,\n top: POS.pedalIO.top,\n transform: 'translate(-50%, -50%)',\n }}\n >\n {!pedalConnected ? (\n onConnectPedal && (\n <button\n type=\"button\"\n onClick={onConnectPedal}\n className=\"px-2 py-1 rounded border border-border bg-surface-card text-[10px] font-semibold text-text-primary hover:border-gold-dim transition-colors whitespace-nowrap\"\n >\n Connect\n </button>\n )\n ) : (\n <>\n {onReadPedal && (\n <IconButton\n onClick={onReadPedal}\n disabled={pedalBusy}\n busy={pedalReading}\n label=\"Read programs from pedal\"\n >\n <ArrowUpFromBox />\n </IconButton>\n )}\n {onWritePedal && (\n <IconButton\n onClick={onWritePedal}\n disabled={pedalBusy}\n busy={pedalWriting}\n label=\"Write programs to pedal\"\n >\n <ArrowDownToBox />\n </IconButton>\n )}\n </>\n )}\n </div>\n )}\n\n {/* Footswitch — silver stompbox-style */}\n <button\n onClick={onToggleBypass}\n aria-label={bypassed ? 'Bypassed — click to engage' : 'Engaged — click to bypass'}\n className=\"absolute rounded-full cursor-pointer\"\n style={{\n left: POS.footswitch.left,\n top: POS.footswitch.top,\n width: `${FOOTSWITCH_SIZE_PCT}%`,\n aspectRatio: '1 / 1',\n transform: 'translate(-50%, -50%)',\n background: 'radial-gradient(circle at 35% 30%, #fafafa 0%, #cfcfcf 45%, #888 90%, #555 100%)',\n border: '1.5px solid #222',\n boxShadow: '0 2px 4px rgba(0,0,0,0.4), inset 0 1px 1px rgba(255,255,255,0.6), inset 0 -2px 3px rgba(0,0,0,0.25)',\n }}\n >\n <span\n className=\"absolute rounded-full pointer-events-none\"\n style={{\n left: '50%',\n top: '50%',\n width: '80%',\n aspectRatio: '1 / 1',\n transform: 'translate(-50%, -50%)',\n background: 'radial-gradient(circle at 40% 35%, #f0f0f0 0%, #b0b0b0 60%, #707070 100%)',\n border: '1px solid #444',\n boxShadow: 'inset 0 1px 1px rgba(255,255,255,0.5), inset 0 -1px 2px rgba(0,0,0,0.35)',\n }}\n />\n </button>\n </div>\n\n {/* Web/extension playback controls (not part of the physical pedal) */}\n <div className=\"flex items-center gap-3 flex-wrap justify-center\">\n <button\n onClick={playing ? onPause : onPlay}\n className=\"px-4 py-1.5 rounded border border-border bg-surface-card text-sm font-semibold text-text-primary hover:border-gold-dim transition-colors\"\n >\n {playing ? 'Pause' : 'Play'}\n </button>\n {clips && clips.length > 0 && (\n <ClipSelector\n clips={clips}\n selectedClipId={selectedClipId}\n onSelect={onSelectClip}\n />\n )}\n <div\n role=\"radiogroup\"\n aria-label=\"Output channel mode\"\n title=\"Mono matches the current Easy Spin hardware (DACL to both jacks). Stereo plays the FV-1's native left/right outputs.\"\n className=\"flex items-center rounded border border-border bg-surface-card text-sm overflow-hidden\"\n >\n {(['mono', 'stereo'] as const).map(mode => (\n <button\n key={mode}\n type=\"button\"\n role=\"radio\"\n aria-checked={channelMode === mode}\n onClick={() => onChannelModeChange(mode)}\n className={`px-3 py-1.5 font-semibold transition-colors ${\n channelMode === mode\n ? 'bg-gold text-surface'\n : 'text-text-secondary hover:text-text-primary'\n }`}\n >\n {mode === 'mono' ? 'Mono' : 'Stereo'}\n </button>\n ))}\n </div>\n </div>\n\n {/* Program slots — drop a payload onto a slot to assign it; click a\n slot to make it the active program. */}\n <div className=\"w-full space-y-2\">\n <div className=\"flex items-center justify-between\">\n <h3 className=\"text-xs font-semibold uppercase tracking-wider text-text-muted\">\n Programs on Pedal\n </h3>\n {anyAssigned && onUnassignAllSlots && (\n <button\n type=\"button\"\n onClick={onUnassignAllSlots}\n className=\"text-[11px] text-text-muted hover:text-red-400 transition-colors\"\n title=\"Clear all local slot assignments\"\n >\n Unassign all\n </button>\n )}\n </div>\n <div className=\"grid grid-cols-2 gap-2\">\n {Array.from({ length: PROGRAM_SLOT_COUNT }, (_, i) => {\n const isActive = selectedSlot === i\n const isDragOver = dragOverSlot === i\n const label = slotLabels?.[i]\n const isEmpty = !label\n return (\n <div\n key={i}\n role=\"button\"\n tabIndex={0}\n onClick={e => {\n // Ctrl/Cmd+click on an assigned slot opens the source file\n // (consumer-defined). Plain click selects the slot.\n if ((e.ctrlKey || e.metaKey) && !isEmpty && onOpenSlotSource) {\n e.preventDefault()\n onOpenSlotSource(i)\n return\n }\n onSelectSlot(i)\n }}\n onContextMenu={e => {\n if (!isEmpty && onOpenSlotSource) {\n e.preventDefault()\n onOpenSlotSource(i)\n }\n }}\n onKeyDown={e => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault()\n onSelectSlot(i)\n }\n }}\n onDragOver={e => {\n if (!onAssignSlot) return\n e.preventDefault()\n // Pick a dropEffect that's compatible with whatever the\n // drag source set as its allowed effects. Without this,\n // sources that don't allow 'copy' (e.g. VS Code's Explorer)\n // require Ctrl to drop, because the OS only upgrades to\n // 'copy' when a modifier key is held. Matching the source's\n // allowed effects lets the drop fire without modifiers.\n e.dataTransfer.dropEffect = pickDropEffect(e.dataTransfer.effectAllowed)\n if (dragOverSlot !== i) setDragOverSlot(i)\n }}\n onDragLeave={() => setDragOverSlot(null)}\n onDrop={e => {\n if (!onAssignSlot) return\n e.preventDefault()\n setDragOverSlot(null)\n // Try text/plain first (web-app effect-id pattern), then\n // text/uri-list (VS Code / OS file drags). uri-list payloads\n // are newline-separated; we take the first URI.\n let payload = e.dataTransfer.getData('text/plain')\n if (!payload) {\n const uriList = e.dataTransfer.getData('text/uri-list')\n if (uriList) {\n payload = uriList.split('\\n').map(s => s.trim()).find(s => s && !s.startsWith('#')) ?? ''\n }\n }\n if (payload) onAssignSlot(i, payload)\n }}\n className={[\n 'flex items-center gap-2 px-2 py-2 rounded border text-left transition-colors cursor-pointer',\n 'bg-surface-card text-sm outline-none focus-visible:ring-1 focus-visible:ring-gold-dim',\n isActive\n ? 'border-gold-dim ring-1 ring-gold-dim/60 text-text-primary'\n : 'border-border text-text-primary hover:border-gold-dim',\n isDragOver ? 'border-dashed border-gold-dim bg-gold-dim/10' : '',\n ].join(' ')}\n >\n <span\n className={[\n 'flex-none w-6 h-6 inline-flex items-center justify-center rounded-full text-xs font-bold',\n isActive ? 'bg-gold-dim text-black' : 'bg-black/30 text-text-primary',\n ].join(' ')}\n >\n {i + 1}\n </span>\n <span\n className={[\n 'flex-1 min-w-0 truncate',\n isEmpty ? 'italic text-text-muted' : 'font-medium',\n ].join(' ')}\n >\n {isEmpty ? 'Empty' : label}\n </span>\n {isEmpty && onAssignTrackedToSlot && (\n <button\n type=\"button\"\n onClick={e => {\n e.stopPropagation()\n onAssignTrackedToSlot(i)\n }}\n aria-label={`Assign currently tracked program to slot ${i + 1}`}\n title=\"Assign currently tracked program here\"\n className=\"flex-none p-1 rounded text-text-muted hover:text-gold-dim hover:bg-black/20 transition-colors\"\n >\n <PlusIcon />\n </button>\n )}\n {!isEmpty && onProgramSlot && slotProgrammable && (\n <button\n type=\"button\"\n onClick={e => {\n e.stopPropagation()\n onProgramSlot(i)\n }}\n disabled={programmingSlot !== null}\n aria-label={`Write slot ${i + 1} to pedal`}\n title=\"Write this slot to pedal\"\n className=\"flex-none p-1 rounded text-text-muted hover:text-gold-dim hover:bg-black/20 disabled:opacity-40 disabled:cursor-not-allowed transition-colors\"\n >\n {programmingSlot === i ? <Spinner small /> : <ArrowDownToBox small />}\n </button>\n )}\n {!isEmpty && onUnassignSlot && (\n <button\n type=\"button\"\n onClick={e => {\n e.stopPropagation()\n onUnassignSlot(i)\n }}\n aria-label={`Unassign slot ${i + 1}`}\n title=\"Unassign\"\n className=\"flex-none p-1 rounded text-text-muted hover:text-red-400 hover:bg-black/20 transition-colors\"\n >\n <TrashIcon />\n </button>\n )}\n </div>\n )\n })}\n </div>\n </div>\n </div>\n )\n}\n\ninterface KnobOverlayProps {\n posStyle: { left: string; top: string }\n sizePct: number\n value: number\n label: string\n onChange: (value: number) => void\n}\n\nfunction KnobOverlay({ posStyle, sizePct, value, label, onChange }: KnobOverlayProps) {\n return (\n <div\n className=\"absolute\"\n style={{\n left: posStyle.left,\n top: posStyle.top,\n width: `${sizePct}%`,\n aspectRatio: '1 / 1',\n transform: 'translate(-50%, -50%)',\n }}\n >\n <Knob overlay value={value} label={label} onChange={onChange} />\n </div>\n )\n}\n\ninterface PotLabelProps {\n posStyle: { left: string; top: string }\n text: string\n}\n\nfunction PotLabel({ posStyle, text }: PotLabelProps) {\n return (\n <div\n className=\"absolute text-center text-[11px] sm:text-xs font-semibold text-black whitespace-nowrap pointer-events-none\"\n style={{\n left: posStyle.left,\n top: posStyle.top,\n transform: 'translate(-50%, -50%)',\n }}\n >\n {text}\n </div>\n )\n}\n\ninterface IconButtonProps {\n onClick?: () => void\n disabled?: boolean\n busy?: boolean\n label: string\n children: React.ReactNode\n}\n\nfunction IconButton({ onClick, disabled, busy, label, children }: IconButtonProps) {\n return (\n <button\n type=\"button\"\n onClick={onClick}\n disabled={disabled}\n aria-label={label}\n title={label}\n className=\"p-1 rounded border border-border bg-surface-card text-text-primary hover:border-gold-dim hover:text-gold-dim disabled:opacity-40 disabled:cursor-not-allowed transition-colors\"\n >\n {busy ? <Spinner /> : children}\n </button>\n )\n}\n\nfunction Spinner({ small = false }: { small?: boolean }) {\n const cls = small ? 'w-3.5 h-3.5 animate-spin' : 'w-4 h-4 animate-spin'\n return (\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" className={cls}>\n <path d=\"M21 12a9 9 0 1 1-6.219-8.56\" />\n </svg>\n )\n}\n\nfunction ArrowUpFromBox() {\n return (\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" className=\"w-4 h-4\">\n <path d=\"M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4\" />\n <polyline points=\"17 8 12 3 7 8\" />\n <line x1=\"12\" y1=\"3\" x2=\"12\" y2=\"15\" />\n </svg>\n )\n}\n\nfunction ArrowDownToBox({ small = false }: { small?: boolean }) {\n const cls = small ? 'w-3.5 h-3.5' : 'w-4 h-4'\n return (\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" className={cls}>\n <path d=\"M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4\" />\n <polyline points=\"7 10 12 15 17 10\" />\n <line x1=\"12\" y1=\"15\" x2=\"12\" y2=\"3\" />\n </svg>\n )\n}\n\nfunction pickDropEffect(allowed: DataTransfer['effectAllowed']): 'copy' | 'move' | 'link' | 'none' {\n // Choose something the source explicitly allows so the drop fires without\n // requiring modifier keys. Prefer 'copy' for clarity (sliding cursor with +)\n // when it's allowed, otherwise fall back through the other modes.\n switch (allowed) {\n case 'copy':\n case 'copyLink':\n case 'copyMove':\n case 'all':\n case 'uninitialized':\n return 'copy'\n case 'move':\n case 'linkMove':\n return 'move'\n case 'link':\n return 'link'\n case 'none':\n default:\n return 'none'\n }\n}\n\nfunction PlusIcon() {\n return (\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" className=\"w-3.5 h-3.5\">\n <line x1=\"12\" y1=\"5\" x2=\"12\" y2=\"19\" />\n <line x1=\"5\" y1=\"12\" x2=\"19\" y2=\"12\" />\n </svg>\n )\n}\n\nfunction TrashIcon() {\n return (\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" className=\"w-3.5 h-3.5\">\n <path d=\"M3 6h18\" />\n <path d=\"M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2\" />\n <path d=\"M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6\" />\n <path d=\"M10 11v6M14 11v6\" />\n </svg>\n )\n}\n","/**\n * Converts a compiled FV-1 binary (Uint8Array, big-endian) to an array of\n * 32-bit machine code words suitable for FV1Simulator.loadProgram().\n *\n * An FV-1 program is 128 instructions × 4 bytes = 512 bytes.\n */\nexport function binaryToMachineCode(binary: Uint8Array): number[] {\n const words: number[] = []\n const view = new DataView(binary.buffer, binary.byteOffset, binary.byteLength)\n for (let i = 0; i < binary.length; i += 4) {\n words.push(view.getUint32(i, false)) // big-endian\n }\n return words\n}\n","import { useRef, useState, useCallback, useEffect } from 'react'\nimport { FV1Assembler } from '@audiofab-io/fv1-core'\nimport type { FV1AssemblerProblem } from '@audiofab-io/fv1-core'\nimport { binaryToMachineCode } from '../audio/binary'\n\nexport type ChannelMode = 'mono' | 'stereo'\n\nexport interface SimulatorState {\n /** True when audio is currently playing. */\n playing: boolean\n /** True when the bypass footswitch is engaged (signal passes through dry). */\n bypassed: boolean\n /** Output channel mode — see ChannelMode. */\n channelMode: ChannelMode\n /** Sample rate of the AudioContext (set after init). */\n sampleRate: number | null\n}\n\nexport interface UseSimulatorOptions {\n /**\n * URL of the bundled FV-1 audio worklet processor. Required.\n *\n * In Vite-based consumers, prefer:\n * import workletUrl from '@audiofab-io/easy-spin-ui/worklet?url'\n *\n * In VS Code webview consumers, derive the URL via\n * webview.asWebviewUri(...)\n * after copying `node_modules/@audiofab-io/easy-spin-ui/dist/worklet/fv1-processor.js`\n * into your webview's resource directory.\n */\n workletUrl: string\n /** AudioContext sample rate. Defaults to 32 768 Hz to match the FV-1. */\n sampleRate?: number\n}\n\nexport interface AssembleResult {\n success: boolean\n errors?: FV1AssemblerProblem[]\n}\n\n/**\n * Headless hook that drives an off-DOM AudioContext + FV-1 audio worklet.\n *\n * The hook is deliberately decoupled from any \"where do programs come from\"\n * concern — consumers fetch / compile / load binaries themselves and pass\n * them in via `loadProgram`. The same applies to audio clips.\n */\nexport function useSimulator({ workletUrl, sampleRate = 32768 }: UseSimulatorOptions) {\n const ctxRef = useRef<AudioContext | null>(null)\n const workletRef = useRef<AudioWorkletNode | null>(null)\n const sourceRef = useRef<AudioBufferSourceNode | null>(null)\n const clipBufferRef = useRef<AudioBuffer | null>(null)\n const initPromiseRef = useRef<Promise<void> | null>(null)\n\n const [state, setState] = useState<SimulatorState>({\n playing: false,\n bypassed: false,\n channelMode: 'mono',\n sampleRate: null,\n })\n\n const init = useCallback(async () => {\n if (ctxRef.current) return\n if (initPromiseRef.current) return initPromiseRef.current\n\n initPromiseRef.current = (async () => {\n const ctx = new AudioContext({ sampleRate })\n await ctx.audioWorklet.addModule(workletUrl)\n const worklet = new AudioWorkletNode(ctx, 'fv1-processor', {\n outputChannelCount: [2],\n })\n worklet.connect(ctx.destination)\n ctxRef.current = ctx\n workletRef.current = worklet\n setState(s => ({ ...s, sampleRate: ctx.sampleRate }))\n })()\n\n return initPromiseRef.current\n }, [workletUrl, sampleRate])\n\n /** Load a pre-compiled FV-1 binary (512 bytes, big-endian) into the simulator. */\n const loadProgram = useCallback(async (binary: Uint8Array) => {\n await init()\n const code = binaryToMachineCode(binary)\n workletRef.current!.port.postMessage({\n type: 'loadProgram',\n machineCode: code,\n })\n }, [init])\n\n /**\n * Convenience: assemble FV-1 source and load the result.\n *\n * Returns `{ success: false, errors }` on fatal assembler errors so callers\n * can surface them. Non-fatal warnings are ignored here.\n */\n const loadProgramFromSource = useCallback(async (spnSource: string): Promise<AssembleResult> => {\n await init()\n const assembler = new FV1Assembler()\n const result = assembler.assemble(spnSource)\n const fatal = result.problems.filter(p => p.isfatal)\n if (fatal.length > 0) {\n return { success: false, errors: fatal }\n }\n const binary = FV1Assembler.toUint8Array(result.machineCode)\n const code = binaryToMachineCode(binary)\n workletRef.current!.port.postMessage({\n type: 'loadProgram',\n machineCode: code,\n })\n return { success: true }\n }, [init])\n\n /**\n * Decode an audio clip from raw bytes and stage it as the simulator's input.\n * If audio is currently playing, the new clip starts immediately; otherwise\n * it's just held until `play()` is called.\n */\n const loadClipBuffer = useCallback(async (clipBytes: ArrayBuffer | Uint8Array) => {\n await init()\n const ctx = ctxRef.current!\n const wasPlaying = sourceRef.current !== null\n\n if (sourceRef.current) {\n try { sourceRef.current.stop() } catch { /* already stopped */ }\n sourceRef.current.disconnect()\n sourceRef.current = null\n }\n\n const ab = clipBytes instanceof ArrayBuffer\n ? clipBytes\n : (clipBytes.buffer.slice(clipBytes.byteOffset, clipBytes.byteOffset + clipBytes.byteLength) as ArrayBuffer)\n const buffer = await ctx.decodeAudioData(ab)\n clipBufferRef.current = buffer\n\n if (wasPlaying) {\n const source = ctx.createBufferSource()\n source.buffer = buffer\n source.loop = true\n source.connect(workletRef.current!)\n source.start()\n sourceRef.current = source\n await ctx.resume()\n }\n }, [init])\n\n const play = useCallback(async () => {\n await init()\n const ctx = ctxRef.current!\n const buffer = clipBufferRef.current\n if (!buffer) return\n\n // AudioBufferSourceNode is single-use — create a fresh one each time.\n if (sourceRef.current) {\n try { sourceRef.current.stop() } catch { /* already stopped */ }\n sourceRef.current.disconnect()\n }\n\n const source = ctx.createBufferSource()\n source.buffer = buffer\n source.loop = true\n source.connect(workletRef.current!)\n source.start()\n sourceRef.current = source\n await ctx.resume()\n\n setState(s => ({ ...s, playing: true }))\n }, [init])\n\n const pause = useCallback(() => {\n if (sourceRef.current) {\n try { sourceRef.current.stop() } catch { /* already stopped */ }\n sourceRef.current.disconnect()\n sourceRef.current = null\n }\n ctxRef.current?.suspend()\n setState(s => ({ ...s, playing: false }))\n }, [])\n\n const setPot = useCallback((index: number, value: number) => {\n workletRef.current?.port.postMessage({ type: 'setPot', index, value })\n }, [])\n\n const setBypass = useCallback((active: boolean) => {\n workletRef.current?.port.postMessage({ type: 'bypass', active })\n setState(s => ({ ...s, bypassed: active }))\n }, [])\n\n const setChannelMode = useCallback((mode: ChannelMode) => {\n workletRef.current?.port.postMessage({ type: 'setChannelMode', mode })\n setState(s => ({ ...s, channelMode: mode }))\n }, [])\n\n // Tear down the AudioContext on unmount to avoid leaking audio threads.\n useEffect(() => {\n return () => {\n if (sourceRef.current) {\n try { sourceRef.current.stop() } catch { /* already stopped */ }\n sourceRef.current.disconnect()\n }\n ctxRef.current?.close().catch(() => { /* already closed */ })\n }\n }, [])\n\n return {\n ...state,\n loadProgram,\n loadProgramFromSource,\n loadClipBuffer,\n play,\n pause,\n setPot,\n setBypass,\n setChannelMode,\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../src/components/Knob.tsx","../src/components/ProgramSelector.tsx","../src/components/ClipSelector.tsx","../src/components/PedalFace.tsx","../src/audio/binary.ts","../src/simulator/useSimulator.ts"],"sourcesContent":["import { useRef, useCallback } from 'react'\n\ninterface KnobProps {\n value: number // 0.0 – 1.0\n label: string\n onChange: (value: number) => void\n size?: number\n /** When true, render without a visible body — just a pointer indicator\n * (for overlaying on top of a pre-drawn dial graphic). */\n overlay?: boolean\n}\n\nconst SWEEP_DEG = 300\nconst MIN_DEG = -SWEEP_DEG / 2\n\nexport function Knob({ value, label, onChange, size = 56, overlay = false }: KnobProps) {\n const knobRef = useRef<SVGSVGElement>(null)\n const dragging = useRef(false)\n const startAngle = useRef(0)\n const startValue = useRef(0)\n\n const getAngleFromEvent = useCallback((e: PointerEvent) => {\n const el = knobRef.current\n if (!el) return 0\n const rect = el.getBoundingClientRect()\n const cx = rect.left + rect.width / 2\n const cy = rect.top + rect.height / 2\n return Math.atan2(e.clientY - cy, e.clientX - cx) * (180 / Math.PI)\n }, [])\n\n const onPointerDown = useCallback((e: React.PointerEvent) => {\n dragging.current = true\n startAngle.current = getAngleFromEvent(e.nativeEvent)\n startValue.current = value\n ;(e.target as Element).setPointerCapture(e.pointerId)\n }, [getAngleFromEvent, value])\n\n const onPointerMove = useCallback((e: React.PointerEvent) => {\n if (!dragging.current) return\n const angle = getAngleFromEvent(e.nativeEvent)\n const delta = angle - startAngle.current\n const norm = ((delta + 540) % 360) - 180\n const valueDelta = norm / SWEEP_DEG\n const newValue = Math.max(0, Math.min(1, startValue.current + valueDelta))\n onChange(newValue)\n }, [getAngleFromEvent, onChange])\n\n const onPointerUp = useCallback(() => {\n dragging.current = false\n }, [])\n\n const rotation = MIN_DEG + value * SWEEP_DEG\n\n const svg = (\n <svg\n ref={knobRef}\n width={overlay ? '100%' : size}\n height={overlay ? '100%' : size}\n viewBox=\"0 0 56 56\"\n className=\"cursor-grab active:cursor-grabbing select-none touch-none\"\n role=\"slider\"\n aria-valuenow={Math.round(value * 100)}\n aria-valuemin={0}\n aria-valuemax={100}\n aria-label={label}\n onPointerDown={onPointerDown}\n onPointerMove={onPointerMove}\n onPointerUp={onPointerUp}\n >\n <circle cx=\"28\" cy=\"28\" r=\"28\" fill=\"transparent\" />\n {overlay ? (\n <circle cx=\"28\" cy=\"28\" r=\"24\" fill=\"none\" stroke=\"#111\" strokeWidth=\"1.5\" />\n ) : (\n <>\n <circle cx=\"28\" cy=\"28\" r=\"26\" fill=\"none\" stroke=\"#888\" strokeWidth=\"1.5\" />\n <circle cx=\"28\" cy=\"28\" r=\"22\" fill=\"#f0f0f0\" stroke=\"#aaa\" strokeWidth=\"1\" />\n </>\n )}\n <g transform={`rotate(${rotation} 28 28)`}>\n <line\n x1=\"28\"\n y1=\"28\"\n x2=\"28\"\n y2={overlay ? 10 : 8}\n stroke={overlay ? '#111' : '#B8942C'}\n strokeWidth={overlay ? 2.5 : 2}\n strokeLinecap=\"round\"\n />\n </g>\n </svg>\n )\n\n if (overlay) {\n return svg\n }\n\n return (\n <div className=\"flex flex-col items-center gap-1\">\n {svg}\n <span className=\"text-[10px] text-text-secondary text-center leading-tight max-w-[80px] truncate\">\n {label}\n </span>\n </div>\n )\n}\n","import { useRef, useCallback } from 'react'\nimport { PROGRAM_SLOT_COUNT } from '@audiofab-io/fv1-core/pedal'\n\ninterface ProgramSelectorProps {\n selectedSlot: number\n onSelectSlot: (slot: number) => void\n slotLabels?: string[]\n /** When true, render as a rotary dial with a pointer indicator (no visible body). */\n overlay?: boolean\n}\n\nconst POS_COUNT = PROGRAM_SLOT_COUNT\nconst START_ANGLE_DEG = 180 // position 1 (lower-left)\nconst END_ANGLE_DEG = 30 + 360 // position 8 (lower-right, via the top)\nconst STEP_DEG = (END_ANGLE_DEG - START_ANGLE_DEG) / (POS_COUNT - 1)\n\nfunction angleForPosition(index0: number): number {\n return START_ANGLE_DEG + index0 * STEP_DEG\n}\n\nfunction nearestSlotFromPointerAngle(pointerDeg: number): number {\n const a = ((pointerDeg % 360) + 360) % 360\n let bestSlot = 0\n let bestDist = Infinity\n for (let i = 0; i < POS_COUNT; i++) {\n const slotAngle = ((angleForPosition(i) % 360) + 360) % 360\n let diff = Math.abs(a - slotAngle)\n if (diff > 180) diff = 360 - diff\n if (diff < bestDist) {\n bestDist = diff\n bestSlot = i\n }\n }\n return bestSlot\n}\n\n/**\n * Rotary program selector. In overlay mode it renders as a pot-style knob\n * (black circular outline + pointer) that points at the currently selected\n * slot. The knob can be dragged to change program — it snaps to the nearest\n * of the 8 discrete positions.\n */\nexport function ProgramSelector({\n selectedSlot,\n onSelectSlot,\n slotLabels,\n overlay = false,\n}: ProgramSelectorProps) {\n const knobRef = useRef<SVGSVGElement>(null)\n const dragging = useRef(false)\n\n const getAngleFromEvent = useCallback((e: PointerEvent) => {\n const el = knobRef.current\n if (!el) return 0\n const rect = el.getBoundingClientRect()\n const cx = rect.left + rect.width / 2\n const cy = rect.top + rect.height / 2\n const raw = Math.atan2(e.clientY - cy, e.clientX - cx) * (180 / Math.PI)\n return ((raw % 360) + 360) % 360\n }, [])\n\n const onPointerDown = useCallback((e: React.PointerEvent) => {\n dragging.current = true\n ;(e.target as Element).setPointerCapture(e.pointerId)\n const angle = getAngleFromEvent(e.nativeEvent)\n const nearest = nearestSlotFromPointerAngle(angle)\n if (nearest !== selectedSlot) onSelectSlot(nearest)\n }, [getAngleFromEvent, selectedSlot, onSelectSlot])\n\n const onPointerMove = useCallback((e: React.PointerEvent) => {\n if (!dragging.current) return\n const angle = getAngleFromEvent(e.nativeEvent)\n const nearest = nearestSlotFromPointerAngle(angle)\n if (nearest !== selectedSlot) onSelectSlot(nearest)\n }, [getAngleFromEvent, selectedSlot, onSelectSlot])\n\n const onPointerUp = useCallback(() => {\n dragging.current = false\n }, [])\n\n if (!overlay) {\n return (\n <div className=\"grid grid-cols-4 gap-1\">\n {Array.from({ length: POS_COUNT }, (_, i) => (\n <button\n key={i}\n onClick={() => onSelectSlot(i)}\n title={slotLabels?.[i] ?? `Slot ${i + 1}`}\n className={`w-7 h-7 rounded text-xs font-bold ${selectedSlot === i\n ? 'bg-gold text-surface'\n : 'bg-surface-hover text-text-secondary hover:bg-surface-card border border-border'\n }`}\n >\n {i + 1}\n </button>\n ))}\n </div>\n )\n }\n\n const rotation = angleForPosition(selectedSlot) - 270\n\n return (\n <svg\n ref={knobRef}\n width=\"100%\"\n height=\"100%\"\n viewBox=\"0 0 56 56\"\n className=\"cursor-grab active:cursor-grabbing select-none touch-none\"\n role=\"listbox\"\n aria-label=\"Program selector\"\n aria-activedescendant={`prog-slot-${selectedSlot}`}\n onPointerDown={onPointerDown}\n onPointerMove={onPointerMove}\n onPointerUp={onPointerUp}\n >\n <circle cx=\"28\" cy=\"28\" r=\"28\" fill=\"transparent\" />\n <circle cx=\"28\" cy=\"28\" r=\"24\" fill=\"none\" stroke=\"#111\" strokeWidth=\"1.5\" />\n <g transform={`rotate(${rotation} 28 28)`}>\n <line\n x1=\"28\"\n y1=\"28\"\n x2=\"28\"\n y2=\"10\"\n stroke=\"#111\"\n strokeWidth=\"2.5\"\n strokeLinecap=\"round\"\n />\n </g>\n </svg>\n )\n}\n","export interface ClipInfo {\n id: string\n name: string\n description?: string\n}\n\ninterface ClipSelectorProps {\n /** List of clips the consumer wants to expose. */\n clips: ClipInfo[]\n selectedClipId: string | null\n onSelect: (clipId: string) => void\n /** When true, the selector is visually disabled (e.g. while a list is loading). */\n disabled?: boolean\n}\n\n/**\n * Pure presentational dropdown for picking an audio clip. The shared package\n * has no opinion about where clips come from — consumers fetch / bundle their\n * own list and pass it in.\n */\nexport function ClipSelector({ clips, selectedClipId, onSelect, disabled = false }: ClipSelectorProps) {\n return (\n <select\n value={selectedClipId ?? ''}\n onChange={e => onSelect(e.target.value)}\n disabled={disabled}\n className=\"px-2 py-1 rounded bg-surface-hover border border-border text-xs text-text-primary focus:outline-none focus:border-gold-dim disabled:opacity-50\"\n >\n <option value=\"\" disabled>\n {disabled ? 'Loading…' : 'Select clip'}\n </option>\n {clips.map(clip => (\n <option key={clip.id} value={clip.id}>\n {clip.name}\n </option>\n ))}\n </select>\n )\n}\n","import { useState } from 'react'\nimport { Knob } from './Knob'\nimport { ProgramSelector } from './ProgramSelector'\nimport { ClipSelector, type ClipInfo } from './ClipSelector'\nimport { PROGRAM_SLOT_COUNT } from '@audiofab-io/fv1-core/pedal'\n\nexport type ChannelMode = 'mono' | 'stereo'\n\nexport interface PedalFaceProps {\n /** URL of the pedal outline graphic. Required — see assets/pedal.png in\n * this package, or bring your own. */\n pedalImageUrl: string\n\n /** Current values of the three pots, normalised 0..1. */\n pots: [number, number, number]\n onPotChange: (index: number, value: number) => void\n /** Per-pot display labels — typically the effect's `controls[].name`,\n * or `Pot 0/1/2` when the active program is unknown. */\n potLabels?: [string, string, string]\n\n /** Currently selected slot (0-based). */\n selectedSlot: number\n onSelectSlot: (slot: number) => void\n /** Display labels for each of the 8 slots. Empty / undefined means empty. */\n slotLabels?: string[]\n /** Drop handler for slot N. The data string is the platform-specific\n * payload (e.g. an effect id, a file URI). The consumer interprets it. */\n onAssignSlot?: (slotIndex: number, payload: string) => void\n onUnassignSlot?: (slotIndex: number) => void\n onUnassignAllSlots?: () => void\n /** Called when the user clicks the per-slot \"send to pedal\" icon. */\n onProgramSlot?: (slotIndex: number) => void\n /** Index of the slot currently being written to the pedal, or null. */\n programmingSlot?: number | null\n /** When set, empty slots show a \"+\" button that calls this callback —\n * used by hosts that have a notion of a \"currently tracked / active\"\n * program the user can drop into a slot. */\n onAssignTrackedToSlot?: (slotIndex: number) => void\n /** When set, Ctrl/Cmd+click and right-click on an assigned slot fires\n * this callback so hosts can \"open the source file\" — e.g. open the\n * underlying .spn / .spndiagram in an editor tab. */\n onOpenSlotSource?: (slotIndex: number) => void\n\n /** Audio clip selection — pass an empty array to hide the selector. */\n clips?: ClipInfo[]\n selectedClipId: string | null\n onSelectClip: (clipId: string) => void\n\n playing: boolean\n onPlay: () => void\n onPause: () => void\n bypassed: boolean\n onToggleBypass: () => void\n channelMode: ChannelMode\n onChannelModeChange: (mode: ChannelMode) => void\n\n /** Pedal connection state — the I/O button cluster only renders when\n * these are wired up. */\n pedalConnected?: boolean\n onConnectPedal?: () => void\n onReadPedal?: () => void\n onWritePedal?: () => void\n pedalReading?: boolean\n pedalWriting?: boolean\n}\n\n/**\n * Overlay positions as percentages of the pedal image (1573 × 2627).\n *\n * pot0 / pot1 / pot2 — potentiometer centres\n * programSelector — rotary program selector knob centre\n * led — status LED\n * footswitch — bypass footswitch centre\n */\nconst POS = {\n pot0: { left: '22.85%', top: '14%' },\n pot1: { left: '77.15%', top: '14%' },\n pot2: { left: '22.85%', top: '33.75%' },\n programSelector: { left: '76%', top: '33.75%' },\n led: { left: '50%', top: '42%' },\n footswitch: { left: '50%', top: '68.5%' },\n pot0Label: { left: '22.85%', top: '2.5%' },\n pot1Label: { left: '77.15%', top: '2.5%' },\n pot2Label: { left: '22.85%', top: '44%' },\n pedalIO: { left: '105%', top: '70%' },\n}\n\nconst KNOB_SIZE_PCT = 20\nconst FOOTSWITCH_SIZE_PCT = 14\nconst HEX_NUT_SIZE_PCT = 20\nconst LED_SIZE_PCT = 5\n\nexport function PedalFace({\n pedalImageUrl,\n pots,\n onPotChange,\n potLabels = ['Pot 0', 'Pot 1', 'Pot 2'],\n selectedSlot,\n onSelectSlot,\n slotLabels,\n onAssignSlot,\n onUnassignSlot,\n onUnassignAllSlots,\n onProgramSlot,\n programmingSlot = null,\n onAssignTrackedToSlot,\n onOpenSlotSource,\n clips,\n selectedClipId,\n onSelectClip,\n playing,\n onPlay,\n onPause,\n bypassed,\n onToggleBypass,\n channelMode,\n onChannelModeChange,\n pedalConnected = false,\n onConnectPedal,\n onReadPedal,\n onWritePedal,\n pedalReading = false,\n pedalWriting = false,\n}: PedalFaceProps) {\n const pedalBusy = pedalReading || pedalWriting\n const [dragOverSlot, setDragOverSlot] = useState<number | null>(null)\n\n const ledOn = !bypassed\n const anyAssigned = slotLabels?.some(l => l) ?? false\n const slotProgrammable = pedalConnected && !pedalBusy\n\n return (\n <div className=\"flex flex-col items-center gap-5 w-full max-w-[460px] mx-auto\">\n <div\n className=\"relative w-full max-w-[360px] pedal-outline\"\n style={{\n aspectRatio: '1573 / 2627',\n backgroundImage: `url(${pedalImageUrl})`,\n backgroundSize: 'contain',\n backgroundRepeat: 'no-repeat',\n backgroundPosition: 'center top',\n }}\n >\n <KnobOverlay\n posStyle={POS.pot0}\n sizePct={KNOB_SIZE_PCT}\n value={pots[0]}\n label={potLabels[0]}\n onChange={v => onPotChange(0, v)}\n />\n <KnobOverlay\n posStyle={POS.pot1}\n sizePct={KNOB_SIZE_PCT}\n value={pots[1]}\n label={potLabels[1]}\n onChange={v => onPotChange(1, v)}\n />\n <KnobOverlay\n posStyle={POS.pot2}\n sizePct={KNOB_SIZE_PCT}\n value={pots[2]}\n label={potLabels[2]}\n onChange={v => onPotChange(2, v)}\n />\n\n <PotLabel posStyle={POS.pot0Label} text={potLabels[0]} />\n <PotLabel posStyle={POS.pot1Label} text={potLabels[1]} />\n <PotLabel posStyle={POS.pot2Label} text={potLabels[2]} />\n\n {/* Program Selector knob */}\n <div\n className=\"absolute\"\n style={{\n left: POS.programSelector.left,\n top: POS.programSelector.top,\n width: `${KNOB_SIZE_PCT}%`,\n aspectRatio: '1 / 1',\n transform: 'translate(-50%, -50%)',\n }}\n >\n <ProgramSelector\n overlay\n selectedSlot={selectedSlot}\n onSelectSlot={onSelectSlot}\n slotLabels={slotLabels}\n />\n </div>\n\n {/* LED */}\n <div\n className=\"absolute rounded-full transition-all\"\n style={{\n left: POS.led.left,\n top: POS.led.top,\n width: `${LED_SIZE_PCT}%`,\n aspectRatio: '1 / 1',\n transform: 'translate(-50%, -50%)',\n background: ledOn\n ? 'radial-gradient(circle at 35% 30%, #ff8a8a 0%, #e11 55%, #800 100%)'\n : 'radial-gradient(circle at 35% 30%, #f2f2f2 0%, #bbb 60%, #777 100%)',\n boxShadow: ledOn\n ? '0 0 10px rgba(255, 60, 60, 0.75)'\n : 'inset 0 1px 2px rgba(0,0,0,0.25)',\n border: '1px solid #333',\n }}\n aria-label=\"Status LED\"\n />\n\n {/* Hex-shaped silver retaining nut frames the footswitch */}\n <svg\n viewBox=\"0 0 100 100\"\n className=\"absolute pointer-events-none\"\n style={{\n left: POS.footswitch.left,\n top: POS.footswitch.top,\n width: `${HEX_NUT_SIZE_PCT}%`,\n aspectRatio: '1 / 1',\n transform: 'translate(-50%, -50%)',\n filter: 'drop-shadow(0 2px 2px rgba(0,0,0,0.45))',\n }}\n >\n <defs>\n <radialGradient id=\"silverHexNut\" cx=\"40%\" cy=\"35%\" r=\"65%\">\n <stop offset=\"0%\" stopColor=\"#f8f8f8\" />\n <stop offset=\"45%\" stopColor=\"#c8c8c8\" />\n <stop offset=\"100%\" stopColor=\"#707070\" />\n </radialGradient>\n </defs>\n <polygon\n points=\"5,50 27.5,11 72.5,11 95,50 72.5,89 27.5,89\"\n fill=\"url(#silverHexNut)\"\n stroke=\"#333\"\n strokeWidth=\"2\"\n strokeLinejoin=\"round\"\n />\n </svg>\n\n {/* Pedal I/O cluster — only rendered when consumer wires it up */}\n {(onConnectPedal || onReadPedal || onWritePedal) && (\n <div\n className=\"absolute flex items-center gap-1\"\n style={{\n left: POS.pedalIO.left,\n top: POS.pedalIO.top,\n transform: 'translate(-50%, -50%)',\n }}\n >\n {!pedalConnected ? (\n onConnectPedal && (\n <button\n type=\"button\"\n onClick={onConnectPedal}\n className=\"px-2 py-1 rounded border border-border bg-surface-card text-[10px] font-semibold text-text-primary hover:border-gold-dim transition-colors whitespace-nowrap\"\n >\n Connect\n </button>\n )\n ) : (\n <>\n {onReadPedal && (\n <IconButton\n onClick={onReadPedal}\n disabled={pedalBusy}\n busy={pedalReading}\n label=\"Read programs from pedal\"\n >\n <ArrowUpFromBox />\n </IconButton>\n )}\n {onWritePedal && (\n <IconButton\n onClick={onWritePedal}\n disabled={pedalBusy}\n busy={pedalWriting}\n label=\"Write programs to pedal\"\n >\n <ArrowDownToBox />\n </IconButton>\n )}\n </>\n )}\n </div>\n )}\n\n {/* Footswitch — silver stompbox-style */}\n <button\n onClick={onToggleBypass}\n aria-label={bypassed ? 'Bypassed — click to engage' : 'Engaged — click to bypass'}\n className=\"absolute rounded-full cursor-pointer\"\n style={{\n left: POS.footswitch.left,\n top: POS.footswitch.top,\n width: `${FOOTSWITCH_SIZE_PCT}%`,\n aspectRatio: '1 / 1',\n transform: 'translate(-50%, -50%)',\n background: 'radial-gradient(circle at 35% 30%, #fafafa 0%, #cfcfcf 45%, #888 90%, #555 100%)',\n border: '1.5px solid #222',\n boxShadow: '0 2px 4px rgba(0,0,0,0.4), inset 0 1px 1px rgba(255,255,255,0.6), inset 0 -2px 3px rgba(0,0,0,0.25)',\n }}\n >\n <span\n className=\"absolute rounded-full pointer-events-none\"\n style={{\n left: '50%',\n top: '50%',\n width: '80%',\n aspectRatio: '1 / 1',\n transform: 'translate(-50%, -50%)',\n background: 'radial-gradient(circle at 40% 35%, #f0f0f0 0%, #b0b0b0 60%, #707070 100%)',\n border: '1px solid #444',\n boxShadow: 'inset 0 1px 1px rgba(255,255,255,0.5), inset 0 -1px 2px rgba(0,0,0,0.35)',\n }}\n />\n </button>\n </div>\n\n {/* Web/extension playback controls (not part of the physical pedal) */}\n <div className=\"flex items-center gap-3 flex-wrap justify-center\">\n <button\n onClick={playing ? onPause : onPlay}\n className=\"px-4 py-1.5 rounded border border-border bg-surface-card text-sm font-semibold text-text-primary hover:border-gold-dim transition-colors\"\n >\n {playing ? 'Pause' : 'Play'}\n </button>\n {clips && clips.length > 0 && (\n <ClipSelector\n clips={clips}\n selectedClipId={selectedClipId}\n onSelect={onSelectClip}\n />\n )}\n <div\n role=\"radiogroup\"\n aria-label=\"Output channel mode\"\n title=\"Mono matches the current Easy Spin hardware (DACL to both jacks). Stereo plays the FV-1's native left/right outputs.\"\n className=\"flex items-center rounded border border-border bg-surface-card text-sm overflow-hidden\"\n >\n {(['mono', 'stereo'] as const).map(mode => (\n <button\n key={mode}\n type=\"button\"\n role=\"radio\"\n aria-checked={channelMode === mode}\n onClick={() => onChannelModeChange(mode)}\n className={`px-3 py-1.5 font-semibold transition-colors ${\n channelMode === mode\n ? 'bg-gold text-surface'\n : 'text-text-secondary hover:text-text-primary'\n }`}\n >\n {mode === 'mono' ? 'Mono' : 'Stereo'}\n </button>\n ))}\n </div>\n </div>\n\n {/* Program slots — drop a payload onto a slot to assign it; click a\n slot to make it the active program. */}\n <div className=\"w-full space-y-2\">\n <div className=\"flex items-center justify-between\">\n <h3 className=\"text-xs font-semibold uppercase tracking-wider text-text-muted\">\n Programs on Pedal\n </h3>\n {anyAssigned && onUnassignAllSlots && (\n <button\n type=\"button\"\n onClick={onUnassignAllSlots}\n className=\"text-[11px] text-text-muted hover:text-red-400 transition-colors\"\n title=\"Clear all local slot assignments\"\n >\n Unassign all\n </button>\n )}\n </div>\n <div className=\"grid grid-cols-2 gap-2\">\n {Array.from({ length: PROGRAM_SLOT_COUNT }, (_, i) => {\n const isActive = selectedSlot === i\n const isDragOver = dragOverSlot === i\n const label = slotLabels?.[i]\n const isEmpty = !label\n return (\n <div\n key={i}\n role=\"button\"\n tabIndex={0}\n onClick={e => {\n // Ctrl/Cmd+click on an assigned slot opens the source file\n // (consumer-defined). Plain click selects the slot.\n if ((e.ctrlKey || e.metaKey) && !isEmpty && onOpenSlotSource) {\n e.preventDefault()\n onOpenSlotSource(i)\n return\n }\n onSelectSlot(i)\n }}\n onContextMenu={e => {\n if (!isEmpty && onOpenSlotSource) {\n e.preventDefault()\n onOpenSlotSource(i)\n }\n }}\n onKeyDown={e => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault()\n onSelectSlot(i)\n }\n }}\n onDragOver={e => {\n if (!onAssignSlot) return\n e.preventDefault()\n // Pick a dropEffect that's compatible with whatever the\n // drag source set as its allowed effects. Without this,\n // sources that don't allow 'copy' (e.g. VS Code's Explorer)\n // require Ctrl to drop, because the OS only upgrades to\n // 'copy' when a modifier key is held. Matching the source's\n // allowed effects lets the drop fire without modifiers.\n e.dataTransfer.dropEffect = pickDropEffect(e.dataTransfer.effectAllowed)\n if (dragOverSlot !== i) setDragOverSlot(i)\n }}\n onDragLeave={() => setDragOverSlot(null)}\n onDrop={e => {\n if (!onAssignSlot) return\n e.preventDefault()\n setDragOverSlot(null)\n // Try text/plain first (web-app effect-id pattern), then\n // text/uri-list (VS Code / OS file drags). uri-list payloads\n // are newline-separated; we take the first URI.\n let payload = e.dataTransfer.getData('text/plain')\n if (!payload) {\n const uriList = e.dataTransfer.getData('text/uri-list')\n if (uriList) {\n payload = uriList.split('\\n').map(s => s.trim()).find(s => s && !s.startsWith('#')) ?? ''\n }\n }\n if (payload) onAssignSlot(i, payload)\n }}\n className={[\n 'flex items-center gap-2 px-2 py-2 rounded border text-left transition-colors cursor-pointer',\n 'bg-surface-card text-sm outline-none focus-visible:ring-1 focus-visible:ring-gold-dim',\n isActive\n ? 'border-gold-dim ring-1 ring-gold-dim/60 text-text-primary'\n : 'border-border text-text-primary hover:border-gold-dim',\n isDragOver ? 'border-dashed border-gold-dim bg-gold-dim/10' : '',\n ].join(' ')}\n >\n <span\n className={[\n 'flex-none w-6 h-6 inline-flex items-center justify-center rounded-full text-xs font-bold',\n isActive ? 'bg-gold-dim text-black' : 'bg-black/30 text-text-primary',\n ].join(' ')}\n >\n {i + 1}\n </span>\n <span\n className={[\n 'flex-1 min-w-0 truncate',\n isEmpty ? 'italic text-text-muted' : 'font-medium',\n ].join(' ')}\n >\n {isEmpty ? 'Empty' : label}\n </span>\n {isEmpty && onAssignTrackedToSlot && (\n <button\n type=\"button\"\n onClick={e => {\n e.stopPropagation()\n onAssignTrackedToSlot(i)\n }}\n aria-label={`Assign currently tracked program to slot ${i + 1}`}\n title=\"Assign currently tracked program here\"\n className=\"flex-none p-1 rounded text-text-muted hover:text-gold-dim hover:bg-black/20 transition-colors\"\n >\n <PlusIcon />\n </button>\n )}\n {!isEmpty && onProgramSlot && slotProgrammable && (\n <button\n type=\"button\"\n onClick={e => {\n e.stopPropagation()\n onProgramSlot(i)\n }}\n disabled={programmingSlot !== null}\n aria-label={`Write slot ${i + 1} to pedal`}\n title=\"Write this slot to pedal\"\n className=\"flex-none p-1 rounded text-text-muted hover:text-gold-dim hover:bg-black/20 disabled:opacity-40 disabled:cursor-not-allowed transition-colors\"\n >\n {programmingSlot === i ? <Spinner small /> : <ArrowDownToBox small />}\n </button>\n )}\n {!isEmpty && onUnassignSlot && (\n <button\n type=\"button\"\n onClick={e => {\n e.stopPropagation()\n onUnassignSlot(i)\n }}\n aria-label={`Unassign slot ${i + 1}`}\n title=\"Unassign\"\n className=\"flex-none p-1 rounded text-text-muted hover:text-red-400 hover:bg-black/20 transition-colors\"\n >\n <TrashIcon />\n </button>\n )}\n </div>\n )\n })}\n </div>\n </div>\n </div>\n )\n}\n\ninterface KnobOverlayProps {\n posStyle: { left: string; top: string }\n sizePct: number\n value: number\n label: string\n onChange: (value: number) => void\n}\n\nfunction KnobOverlay({ posStyle, sizePct, value, label, onChange }: KnobOverlayProps) {\n return (\n <div\n className=\"absolute\"\n style={{\n left: posStyle.left,\n top: posStyle.top,\n width: `${sizePct}%`,\n aspectRatio: '1 / 1',\n transform: 'translate(-50%, -50%)',\n }}\n >\n <Knob overlay value={value} label={label} onChange={onChange} />\n </div>\n )\n}\n\ninterface PotLabelProps {\n posStyle: { left: string; top: string }\n text: string\n}\n\nfunction PotLabel({ posStyle, text }: PotLabelProps) {\n return (\n <div\n className=\"absolute text-center text-[11px] sm:text-xs font-semibold text-black whitespace-nowrap pointer-events-none\"\n style={{\n left: posStyle.left,\n top: posStyle.top,\n transform: 'translate(-50%, -50%)',\n }}\n >\n {text}\n </div>\n )\n}\n\ninterface IconButtonProps {\n onClick?: () => void\n disabled?: boolean\n busy?: boolean\n label: string\n children: React.ReactNode\n}\n\nfunction IconButton({ onClick, disabled, busy, label, children }: IconButtonProps) {\n return (\n <button\n type=\"button\"\n onClick={onClick}\n disabled={disabled}\n aria-label={label}\n title={label}\n className=\"p-1 rounded border border-border bg-surface-card text-text-primary hover:border-gold-dim hover:text-gold-dim disabled:opacity-40 disabled:cursor-not-allowed transition-colors\"\n >\n {busy ? <Spinner /> : children}\n </button>\n )\n}\n\nfunction Spinner({ small = false }: { small?: boolean }) {\n const cls = small ? 'w-3.5 h-3.5 animate-spin' : 'w-4 h-4 animate-spin'\n return (\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" className={cls}>\n <path d=\"M21 12a9 9 0 1 1-6.219-8.56\" />\n </svg>\n )\n}\n\nfunction ArrowUpFromBox() {\n return (\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" className=\"w-4 h-4\">\n <path d=\"M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4\" />\n <polyline points=\"17 8 12 3 7 8\" />\n <line x1=\"12\" y1=\"3\" x2=\"12\" y2=\"15\" />\n </svg>\n )\n}\n\nfunction ArrowDownToBox({ small = false }: { small?: boolean }) {\n const cls = small ? 'w-3.5 h-3.5' : 'w-4 h-4'\n return (\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" className={cls}>\n <path d=\"M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4\" />\n <polyline points=\"7 10 12 15 17 10\" />\n <line x1=\"12\" y1=\"15\" x2=\"12\" y2=\"3\" />\n </svg>\n )\n}\n\nfunction pickDropEffect(allowed: DataTransfer['effectAllowed']): 'copy' | 'move' | 'link' | 'none' {\n // Choose something the source explicitly allows so the drop fires without\n // requiring modifier keys. Prefer 'copy' for clarity (sliding cursor with +)\n // when it's allowed, otherwise fall back through the other modes.\n switch (allowed) {\n case 'copy':\n case 'copyLink':\n case 'copyMove':\n case 'all':\n case 'uninitialized':\n return 'copy'\n case 'move':\n case 'linkMove':\n return 'move'\n case 'link':\n return 'link'\n case 'none':\n default:\n return 'none'\n }\n}\n\nfunction PlusIcon() {\n return (\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" className=\"w-3.5 h-3.5\">\n <line x1=\"12\" y1=\"5\" x2=\"12\" y2=\"19\" />\n <line x1=\"5\" y1=\"12\" x2=\"19\" y2=\"12\" />\n </svg>\n )\n}\n\nfunction TrashIcon() {\n return (\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" className=\"w-3.5 h-3.5\">\n <path d=\"M3 6h18\" />\n <path d=\"M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2\" />\n <path d=\"M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6\" />\n <path d=\"M10 11v6M14 11v6\" />\n </svg>\n )\n}\n","/**\n * Converts a compiled FV-1 binary (Uint8Array, big-endian) to an array of\n * 32-bit machine code words suitable for FV1Simulator.loadProgram().\n *\n * An FV-1 program is 128 instructions × 4 bytes = 512 bytes.\n */\nexport function binaryToMachineCode(binary: Uint8Array): number[] {\n const words: number[] = []\n const view = new DataView(binary.buffer, binary.byteOffset, binary.byteLength)\n for (let i = 0; i < binary.length; i += 4) {\n words.push(view.getUint32(i, false)) // big-endian\n }\n return words\n}\n","import { useRef, useState, useCallback, useEffect } from 'react'\nimport { FV1Assembler } from '@audiofab-io/fv1-core'\nimport type { FV1AssemblerProblem } from '@audiofab-io/fv1-core'\nimport { binaryToMachineCode } from '../audio/binary'\n\nexport type ChannelMode = 'mono' | 'stereo'\n\nexport interface SimulatorState {\n /** True when audio is currently playing. */\n playing: boolean\n /** True when the bypass footswitch is engaged (signal passes through dry). */\n bypassed: boolean\n /** Output channel mode — see ChannelMode. */\n channelMode: ChannelMode\n /** Sample rate of the AudioContext (set after init). */\n sampleRate: number | null\n /** EMA-smoothed time spent inside the simulator's processBlock(), in\n * microseconds. Null until the worklet has reported at least once.\n * Frozen at its last value while bypassed (the worklet skips updates\n * when the signal is passing through dry). */\n blockTimeUs: number | null\n}\n\nexport interface UseSimulatorOptions {\n /**\n * URL of the bundled FV-1 audio worklet processor. Required.\n *\n * In Vite-based consumers, prefer:\n * import workletUrl from '@audiofab-io/easy-spin-ui/worklet?url'\n *\n * In VS Code webview consumers, derive the URL via\n * webview.asWebviewUri(...)\n * after copying `node_modules/@audiofab-io/easy-spin-ui/dist/worklet/fv1-processor.js`\n * into your webview's resource directory.\n */\n workletUrl: string\n /** AudioContext sample rate. Defaults to 32 768 Hz to match the FV-1. */\n sampleRate?: number\n}\n\nexport interface AssembleResult {\n success: boolean\n errors?: FV1AssemblerProblem[]\n}\n\n/**\n * Headless hook that drives an off-DOM AudioContext + FV-1 audio worklet.\n *\n * The hook is deliberately decoupled from any \"where do programs come from\"\n * concern — consumers fetch / compile / load binaries themselves and pass\n * them in via `loadProgram`. The same applies to audio clips.\n */\nexport function useSimulator({ workletUrl, sampleRate = 32768 }: UseSimulatorOptions) {\n const ctxRef = useRef<AudioContext | null>(null)\n const workletRef = useRef<AudioWorkletNode | null>(null)\n const sourceRef = useRef<AudioBufferSourceNode | null>(null)\n const clipBufferRef = useRef<AudioBuffer | null>(null)\n const initPromiseRef = useRef<Promise<void> | null>(null)\n\n const [state, setState] = useState<SimulatorState>({\n playing: false,\n bypassed: false,\n channelMode: 'mono',\n sampleRate: null,\n blockTimeUs: null,\n })\n\n const init = useCallback(async () => {\n if (ctxRef.current) return\n if (initPromiseRef.current) return initPromiseRef.current\n\n initPromiseRef.current = (async () => {\n const ctx = new AudioContext({ sampleRate })\n await ctx.audioWorklet.addModule(workletUrl)\n const worklet = new AudioWorkletNode(ctx, 'fv1-processor', {\n outputChannelCount: [2],\n })\n worklet.port.onmessage = ({ data }) => {\n if (data?.type === 'blockTime' && typeof data.us === 'number') {\n setState(s => ({ ...s, blockTimeUs: data.us as number }))\n }\n }\n worklet.connect(ctx.destination)\n ctxRef.current = ctx\n workletRef.current = worklet\n setState(s => ({ ...s, sampleRate: ctx.sampleRate }))\n })()\n\n return initPromiseRef.current\n }, [workletUrl, sampleRate])\n\n /** Load a pre-compiled FV-1 binary (512 bytes, big-endian) into the simulator. */\n const loadProgram = useCallback(async (binary: Uint8Array) => {\n await init()\n const code = binaryToMachineCode(binary)\n workletRef.current!.port.postMessage({\n type: 'loadProgram',\n machineCode: code,\n })\n }, [init])\n\n /**\n * Convenience: assemble FV-1 source and load the result.\n *\n * Returns `{ success: false, errors }` on fatal assembler errors so callers\n * can surface them. Non-fatal warnings are ignored here.\n */\n const loadProgramFromSource = useCallback(async (spnSource: string): Promise<AssembleResult> => {\n await init()\n const assembler = new FV1Assembler()\n const result = assembler.assemble(spnSource)\n const fatal = result.problems.filter(p => p.isfatal)\n if (fatal.length > 0) {\n return { success: false, errors: fatal }\n }\n const binary = FV1Assembler.toUint8Array(result.machineCode)\n const code = binaryToMachineCode(binary)\n workletRef.current!.port.postMessage({\n type: 'loadProgram',\n machineCode: code,\n })\n return { success: true }\n }, [init])\n\n /**\n * Decode an audio clip from raw bytes and stage it as the simulator's input.\n * If audio is currently playing, the new clip starts immediately; otherwise\n * it's just held until `play()` is called.\n */\n const loadClipBuffer = useCallback(async (clipBytes: ArrayBuffer | Uint8Array) => {\n await init()\n const ctx = ctxRef.current!\n const wasPlaying = sourceRef.current !== null\n\n if (sourceRef.current) {\n try { sourceRef.current.stop() } catch { /* already stopped */ }\n sourceRef.current.disconnect()\n sourceRef.current = null\n }\n\n const ab = clipBytes instanceof ArrayBuffer\n ? clipBytes\n : (clipBytes.buffer.slice(clipBytes.byteOffset, clipBytes.byteOffset + clipBytes.byteLength) as ArrayBuffer)\n const buffer = await ctx.decodeAudioData(ab)\n clipBufferRef.current = buffer\n\n if (wasPlaying) {\n const source = ctx.createBufferSource()\n source.buffer = buffer\n source.loop = true\n source.connect(workletRef.current!)\n source.start()\n sourceRef.current = source\n await ctx.resume()\n }\n }, [init])\n\n const play = useCallback(async () => {\n await init()\n const ctx = ctxRef.current!\n const buffer = clipBufferRef.current\n if (!buffer) return\n\n // AudioBufferSourceNode is single-use — create a fresh one each time.\n if (sourceRef.current) {\n try { sourceRef.current.stop() } catch { /* already stopped */ }\n sourceRef.current.disconnect()\n }\n\n const source = ctx.createBufferSource()\n source.buffer = buffer\n source.loop = true\n source.connect(workletRef.current!)\n source.start()\n sourceRef.current = source\n await ctx.resume()\n\n setState(s => ({ ...s, playing: true }))\n }, [init])\n\n const pause = useCallback(() => {\n if (sourceRef.current) {\n try { sourceRef.current.stop() } catch { /* already stopped */ }\n sourceRef.current.disconnect()\n sourceRef.current = null\n }\n ctxRef.current?.suspend()\n setState(s => ({ ...s, playing: false }))\n }, [])\n\n const setPot = useCallback((index: number, value: number) => {\n workletRef.current?.port.postMessage({ type: 'setPot', index, value })\n }, [])\n\n const setBypass = useCallback((active: boolean) => {\n workletRef.current?.port.postMessage({ type: 'bypass', active })\n setState(s => ({ ...s, bypassed: active }))\n }, [])\n\n const setChannelMode = useCallback((mode: ChannelMode) => {\n workletRef.current?.port.postMessage({ type: 'setChannelMode', mode })\n setState(s => ({ ...s, channelMode: mode }))\n }, [])\n\n // Tear down the AudioContext on unmount to avoid leaking audio threads.\n useEffect(() => {\n return () => {\n if (sourceRef.current) {\n try { sourceRef.current.stop() } catch { /* already stopped */ }\n sourceRef.current.disconnect()\n }\n ctxRef.current?.close().catch(() => { /* already closed */ })\n }\n }, [])\n\n return {\n ...state,\n loadProgram,\n loadProgramFromSource,\n loadClipBuffer,\n play,\n pause,\n setPot,\n setBypass,\n setChannelMode,\n }\n}\n"],"mappings":"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"}
|
|
@@ -9,6 +9,11 @@ export interface SimulatorState {
|
|
|
9
9
|
channelMode: ChannelMode;
|
|
10
10
|
/** Sample rate of the AudioContext (set after init). */
|
|
11
11
|
sampleRate: number | null;
|
|
12
|
+
/** EMA-smoothed time spent inside the simulator's processBlock(), in
|
|
13
|
+
* microseconds. Null until the worklet has reported at least once.
|
|
14
|
+
* Frozen at its last value while bypassed (the worklet skips updates
|
|
15
|
+
* when the signal is passing through dry). */
|
|
16
|
+
blockTimeUs: number | null;
|
|
12
17
|
}
|
|
13
18
|
export interface UseSimulatorOptions {
|
|
14
19
|
/**
|
|
@@ -54,4 +59,9 @@ export declare function useSimulator({ workletUrl, sampleRate }: UseSimulatorOpt
|
|
|
54
59
|
channelMode: ChannelMode;
|
|
55
60
|
/** Sample rate of the AudioContext (set after init). */
|
|
56
61
|
sampleRate: number | null;
|
|
62
|
+
/** EMA-smoothed time spent inside the simulator's processBlock(), in
|
|
63
|
+
* microseconds. Null until the worklet has reported at least once.
|
|
64
|
+
* Frozen at its last value while bypassed (the worklet skips updates
|
|
65
|
+
* when the signal is passing through dry). */
|
|
66
|
+
blockTimeUs: number | null;
|
|
57
67
|
};
|
|
@@ -4,5 +4,5 @@
|
|
|
4
4
|
`&&this.pos<this.source.length;)this.advance();else n===`
|
|
5
5
|
`?(e.push({type:t.NEWLINE,value:`
|
|
6
6
|
`,line:this.line,column:this.column}),this.advance()):n===`,`?(e.push({type:t.COMMA,value:`,`,line:this.line,column:this.column}),this.advance()):n===`:`?(e.push({type:t.COLON,value:`:`,line:this.line,column:this.column}),this.advance()):n===`(`?(e.push({type:t.LPAREN,value:`(`,line:this.line,column:this.column}),this.advance()):n===`)`?(e.push({type:t.RPAREN,value:`)`,line:this.line,column:this.column}),this.advance()):/[a-zA-Z_]/.test(n)?e.push(this.readIdentifier()):/[0-9.]/.test(n)||n===`$`||n===`%`?e.push(this.readNumber()):/[-+*/|&<>^!]/.test(n)?e.push({type:t.OPERATOR,value:this.advance(),line:this.line,column:this.column}):this.advance()}return e.push({type:t.EOF,value:``,line:this.line,column:this.column}),e}readIdentifier(){let e=``,n=this.line,r=this.column;for(;/[a-zA-Z0-9_#^.]/.test(this.peek());)e+=this.advance();let i=e.toUpperCase();return[`EQU`,`MEM`].includes(i)?{type:t.DIRECTIVE,value:i,line:n,column:r}:{type:t.IDENTIFIER,value:i,line:n,column:r}}readNumber(){let e=``,n=this.line,r=this.column;if(this.peek()===`$`)for(e+=this.advance();/[0-9a-fA-F]/.test(this.peek());)e+=this.advance();else if(this.peek()===`%`)for(e+=this.advance();/[01_]/.test(this.peek());)e+=this.advance();else if(this.peek()===`0`&&(this.source[this.pos+1]||``).toLowerCase()===`x`)for(e+=this.advance(),e+=this.advance();/[0-9a-fA-F]/.test(this.peek());)e+=this.advance();else for(;/[0-9\.]/.test(this.peek());)e+=this.advance();return{type:t.NUMBER,value:e,line:n,column:r}}},r=class{constructor(e){this.pos=0,this.tokens=e.filter((n,r)=>n.type!==t.NEWLINE||this.isNextSignificant(e,r))}isNextSignificant(e,n){for(let r=n+1;r<e.length;r++)if(e[r].type!==t.NEWLINE)return e[r].type!==t.EOF;return!1}peek(){return this.tokens[this.pos]||{type:t.EOF,value:``,line:-1,column:-1}}advance(){return this.tokens[this.pos++]}match(e){return this.peek().type===e?this.advance():null}parse(){let e=[];for(;this.peek().type!==t.EOF;){let n=this.parseStatement();for(n&&e.push(n);this.match(t.NEWLINE););}return e}parseStatement(){let n=this.peek();if(n.type===t.IDENTIFIER){let e=this.tokens[this.pos+1];if(e&&e.type===t.COLON){let e=this.advance();return this.advance(),{type:`Label`,name:e.value,line:e.line}}if(e&&e.type===t.DIRECTIVE){let e=this.advance(),t=this.advance(),n=this.parseExpression();return{type:`Directive`,name:t.value,identifier:e.value,expression:n,line:t.line}}}if(n.type===t.DIRECTIVE){let n=this.advance(),r=this.match(t.IDENTIFIER);if(!r)throw new e(`Expected identifier after ${n.value}`,n.line,n.column);let i=this.parseExpression();return{type:`Directive`,name:n.value,identifier:r.value,expression:i,line:n.line}}if(n.type===t.IDENTIFIER){let e=this.advance(),n=[];if(this.peek().type!==t.NEWLINE&&this.peek().type!==t.EOF)for(n.push(this.parseExpression());this.match(t.COMMA);)n.push(this.parseExpression());return{type:`Instruction`,mnemonic:e.value,operands:n,line:e.line}}return this.advance(),null}parseExpression(){return this.parseBitwise()}parseBitwise(){let e=this.parseShift();for(;this.peek().type===t.OPERATOR&&[`|`,`&`,`^`].includes(this.peek().value);){let t=this.advance().value,n=this.parseShift();e={type:`Binary`,left:e,operator:t,right:n}}return e}parseShift(){let e=this.parseAdditive();for(;this.peek().type===t.OPERATOR&&[`<`,`>`].includes(this.peek().value);){let t=this.advance().value,n=this.parseAdditive();e={type:`Binary`,left:e,operator:t,right:n}}return e}parseAdditive(){let e=this.parseMultiplicative();for(;this.peek().type===t.OPERATOR&&(this.peek().value===`+`||this.peek().value===`-`);){let t=this.advance().value,n=this.parseMultiplicative();e={type:`Binary`,left:e,operator:t,right:n}}return e}parseMultiplicative(){let e=this.parsePrimary();for(;this.peek().type===t.OPERATOR&&(this.peek().value===`*`||this.peek().value===`/`);){let t=this.advance().value,n=this.parsePrimary();e={type:`Binary`,left:e,operator:t,right:n}}return e}parsePrimary(){let n=this.peek();if(n.type===t.NUMBER)return{type:`Number`,value:this.parseNumberValue(this.advance().value)};if(n.type===t.IDENTIFIER)return{type:`Identifier`,name:this.advance().value};if(n.type===t.LPAREN){this.advance();let r=this.parseExpression();if(!this.match(t.RPAREN))throw new e(`Expected )`,n.line,n.column);return r}if(n.type===t.OPERATOR&&(n.value===`-`||n.value===`+`||n.value===`!`))return{type:`Unary`,operator:this.advance().value,expression:this.parsePrimary()};throw new e(`Unexpected token ${n.value}`,n.line,n.column)}parseNumberValue(e){let t=e.toUpperCase();return t.startsWith(`$`)?parseInt(e.slice(1),16):t.startsWith(`0X`)?parseInt(e,16):t.startsWith(`%`)?parseInt(e.slice(1).replace(/_/g,``),2):parseFloat(e)}},i={SOF:{opcode:13,fields:[{name:`coeff`,bits:16,offset:16,type:`S1_14`},{name:`d`,bits:11,offset:5,type:`S_10`},{name:`op`,bits:5,offset:0,value:13}]},AND:{opcode:14,fields:[{name:`mask`,bits:24,offset:8,type:`U`},{name:`op`,bits:8,offset:0,value:14}]},OR:{opcode:15,fields:[{name:`mask`,bits:24,offset:8,type:`U`},{name:`op`,bits:8,offset:0,value:15}]},XOR:{opcode:16,fields:[{name:`mask`,bits:24,offset:8,type:`U`},{name:`op`,bits:8,offset:0,value:16}]},LOG:{opcode:11,fields:[{name:`coeff`,bits:16,offset:16,type:`S1_14`},{name:`d`,bits:11,offset:5,type:`S4_6`},{name:`op`,bits:5,offset:0,value:11}]},EXP:{opcode:12,fields:[{name:`coeff`,bits:16,offset:16,type:`S1_14`},{name:`d`,bits:11,offset:5,type:`S_10`},{name:`op`,bits:5,offset:0,value:12}]},SKP:{opcode:17,fields:[{name:`flags`,bits:5,offset:27,type:`LFO`},{name:`n`,bits:6,offset:21,type:`S`},{name:`op`,bits:5,offset:0,value:17}]},JMP:{opcode:17,fields:[{name:`flags`,bits:5,offset:27,value:0},{name:`n`,bits:6,offset:21,type:`S`},{name:`op`,bits:5,offset:0,value:17}]},NOP:{opcode:17,fields:[{name:`flags`,bits:5,offset:27,value:0},{name:`n`,bits:6,offset:21,value:0},{name:`op`,bits:5,offset:0,value:17}]},RDAX:{opcode:4,fields:[{name:`addr`,bits:6,offset:5,type:`REG`},{name:`coeff`,bits:16,offset:16,type:`S1_14`},{name:`op`,bits:5,offset:0,value:4}]},WRAX:{opcode:6,fields:[{name:`addr`,bits:6,offset:5,type:`REG`},{name:`coeff`,bits:16,offset:16,type:`S1_14`},{name:`op`,bits:5,offset:0,value:6}]},MAXX:{opcode:9,fields:[{name:`addr`,bits:6,offset:5,type:`REG`},{name:`coeff`,bits:16,offset:16,type:`S1_14`},{name:`op`,bits:5,offset:0,value:9}]},MULX:{opcode:10,fields:[{name:`addr`,bits:6,offset:5,type:`REG`},{name:`op`,bits:5,offset:0,value:10}]},RDFX:{opcode:5,fields:[{name:`addr`,bits:6,offset:5,type:`REG`},{name:`coeff`,bits:16,offset:16,type:`S1_14`},{name:`op`,bits:5,offset:0,value:5}]},WRLX:{opcode:8,fields:[{name:`addr`,bits:6,offset:5,type:`REG`},{name:`coeff`,bits:16,offset:16,type:`S1_14`},{name:`op`,bits:5,offset:0,value:8}]},WRHX:{opcode:7,fields:[{name:`addr`,bits:6,offset:5,type:`REG`},{name:`coeff`,bits:16,offset:16,type:`S1_14`},{name:`op`,bits:5,offset:0,value:7}]},LDAX:{opcode:5,fields:[{name:`coeff`,bits:16,offset:16,value:0},{name:`addr`,bits:6,offset:5,type:`REG`},{name:`op`,bits:5,offset:0,value:5}]},RDA:{opcode:0,fields:[{name:`addr`,bits:16,offset:5,type:`ADDR`},{name:`coeff`,bits:11,offset:21,type:`S1_9`},{name:`op`,bits:5,offset:0,value:0}]},RMPA:{opcode:1,fields:[{name:`coeff`,bits:11,offset:21,type:`S1_9`},{name:`op`,bits:5,offset:0,value:1}]},WRA:{opcode:2,fields:[{name:`addr`,bits:16,offset:5,type:`ADDR`},{name:`coeff`,bits:11,offset:21,type:`S1_9`},{name:`op`,bits:5,offset:0,value:2}]},WRAP:{opcode:3,fields:[{name:`addr`,bits:16,offset:5,type:`ADDR`},{name:`coeff`,bits:11,offset:21,type:`S1_9`},{name:`op`,bits:5,offset:0,value:3}]},WLDS:{opcode:18,fields:[{name:`sinLfo`,bits:1,offset:29,type:`U`},{name:`freq`,bits:9,offset:20,type:`U`},{name:`ampl`,bits:15,offset:5,type:`U`},{name:`op`,bits:5,offset:0,value:18}]},WLDR:{opcode:18,fields:[{name:`type`,bits:1,offset:30,value:1},{name:`rmpLfo`,bits:1,offset:29,type:`U`},{name:`freq`,bits:16,offset:13,type:`U`},{name:`ampl`,bits:2,offset:5,type:`U`},{name:`op`,bits:5,offset:0,value:18}]},JAM:{opcode:19,fields:[{name:`rmpLfo`,bits:1,offset:6,type:`U`},{name:`type`,bits:1,offset:7,value:1},{name:`op`,bits:5,offset:0,value:19}]},CHO:{opcode:20,fields:[{name:`mode`,bits:2,offset:30,type:`U`},{name:`flags`,bits:6,offset:24,type:`U`},{name:`n`,bits:3,offset:21,type:`U`},{name:`param`,bits:16,offset:5,type:`ADDR`},{name:`op`,bits:5,offset:0,value:20}]},CLR:{opcode:14,fields:[{name:`val`,bits:32,offset:0,value:14}]},NOT:{opcode:16,fields:[{name:`val`,bits:32,offset:0,value:16}]},ABSA:{opcode:9,fields:[{name:`val`,bits:32,offset:0,value:9}]}},a=class{static encode(e,t){switch(e){case`S1_14`:return this.toFixedPoint(t,1,14,2);case`S_15`:return this.toFixedPoint(t,0,15,1);case`S1_9`:return this.toFixedPoint(t,1,9,2);case`S_10`:return this.toFixedPoint(t,0,10,1);case`S4_6`:return this.toFixedPoint(t,4,6,16)}return t}static toFixedPoint(e,t,n,r){let i=r/(1<<n),a=-r,o=r-i,s=Math.trunc(Math.min(Math.max(e,a),o)*(1<<n)),c=1+t+n,l=(1<<c)-1;return s<0?s+(1<<c)&l:s&l}static assembleInstruction(e,t,n){let r=0,i=0;for(let e of n.fields){let n=0;e.value===void 0?(n=t[i++],e.type&&(n=this.encode(e.type,n))):n=e.value;let a=e.bits===32?4294967295:(1<<e.bits)-1;r|=(n&a)<<e.offset}return r>>>0}},o=class{constructor(e={}){this.problems=[],this.symbols=new Map,this.memories=[],this.labels=new Map,this.addressToLineMap=new Map,this.usedRegisters=new Set,this.usedLFOs=new Set,this.configuredLFOs=new Set,this.userSymbols=new Set,this.symbolLines=new Map,this.PREDEFINED_SYMBOLS={SIN0_RATE:0,SIN0_RANGE:1,SIN1_RATE:2,SIN1_RANGE:3,RMP0_RATE:4,RMP0_RANGE:5,RMP1_RATE:6,RMP1_RANGE:7,POT0:16,POT1:17,POT2:18,ADCL:20,ADCR:21,DACL:22,DACR:23,ADDR_PTR:24,SIN0:0,SIN1:1,RMP0:2,RMP1:3,COS0:8,COS1:9,RDA:0,SOF:2,RDAL:3,SIN:0,COS:1,REG:2,COMPC:4,COMPA:8,RPTR2:16,NA:32,RUN:16,ZRC:8,ZRO:4,GEZ:2,NEG:1},this.reservedSymbols=new Set,this.options={fv1AsmMemBug:e.fv1AsmMemBug??!0,clampReals:e.clampReals??!0,regCount:e.regCount??32,progSize:e.progSize??128,delaySize:e.delaySize??32768},this.reset()}reset(){this.problems=[],this.symbols.clear(),this.memories=[],this.labels.clear(),this.addressToLineMap.clear(),this.usedRegisters.clear(),this.usedLFOs.clear(),this.configuredLFOs.clear(),this.userSymbols.clear(),this.symbolLines.clear(),this.initSymbols()}initSymbols(){for(let[e,t]of Object.entries(this.PREDEFINED_SYMBOLS))this.symbols.set(e,t),this.reservedSymbols.add(e);for(let e=0;e<this.options.regCount;e++)this.symbols.set(`REG${e}`,32+e),this.reservedSymbols.add(`REG${e}`)}assemble(t){this.reset();try{let e=new r(new n(t).tokenize()).parse();return this.pass1_ResolveDirectives(e),this.pass2_ResolveLabels(e),{machineCode:this.pass3_GenerateCode(e),problems:this.problems,labels:this.labels,symbols:Array.from(this.symbols.entries()).filter(([e])=>this.userSymbols.has(e)).map(([e,t])=>({name:e,value:t.toString(),line:this.symbolLines.get(e)})),memories:this.memories,addressToLineMap:this.addressToLineMap,usedRegistersCount:this.usedRegisters.size,usedLFOs:Array.from(this.usedLFOs)}}catch(t){let n=t instanceof e?t.line:1;return this.problems.push({message:`Parser error: ${t instanceof Error?t.message:String(t)}`,isfatal:!0,line:n}),{machineCode:[],problems:this.problems,labels:new Map,symbols:[],memories:[],addressToLineMap:new Map,usedRegistersCount:0,usedLFOs:[]}}}pass1_ResolveDirectives(e){let t=0;for(let n of e)if(n.type===`Directive`){if(n.name===`EQU`)if(this.reservedSymbols.has(n.identifier))this.problems.push({message:`Cannot redefine reserved symbol '${n.identifier}'`,isfatal:!0,line:n.line});else if(this.userSymbols.has(n.identifier))this.problems.push({message:`Symbol '${n.identifier}' is already defined on line ${this.symbolLines.get(n.identifier)}`,isfatal:!0,line:n.line});else{let e=this.evaluateExpression(n.expression,n.line);this.symbols.set(n.identifier,e),this.userSymbols.add(n.identifier),this.symbolLines.set(n.identifier,n.line)}else if(n.name===`MEM`){if(this.reservedSymbols.has(n.identifier)){this.problems.push({message:`Cannot redefine reserved symbol '${n.identifier}'`,isfatal:!0,line:n.line});continue}let e=this.evaluateExpression(n.expression,n.line),r=t,i=r+(e%2?(e-1)/2-1:e/2),a=r+e-1,o=a+ +!!this.options.fv1AsmMemBug,s={name:n.identifier,size:e,start:r,middle:i,end:a,line:n.line,original:``};this.memories.push(s),this.symbols.set(n.identifier,r),this.symbols.set(n.identifier+`^`,i),this.symbols.set(n.identifier+`#`,o),t=o+1}}}pass2_ResolveLabels(e){let t=0;for(let n of e)n.type===`Label`?this.labels.set(n.name,{line:n.line,instructionLine:t}):n.type===`Instruction`&&t++}pass3_GenerateCode(e){let t=[],n=0;for(let r of e)if(r.type===`Instruction`){let e=i[r.mnemonic];if(!e){this.problems.push({message:`Unknown instruction ${r.mnemonic}`,isfatal:!0,line:r.line}),t.push(0);continue}let o=r.operands.map(e=>e.type===`Identifier`&&this.labels.has(e.name)?this.labels.get(e.name).instructionLine-n-1:this.evaluateExpression(e,r.line));if(r.mnemonic===`WLDS`||r.mnemonic===`WLDR`){let e=o[0],t=this.getLFOName(e);t&&(r.mnemonic===`WLDS`&&(this.configuredLFOs.has(t)&&this.problems.push({message:`LFO ${t} is configured more than once`,isfatal:!0,line:r.line}),this.configuredLFOs.add(t)),this.usedLFOs.add(t))}if(r.mnemonic===`CHO`){let e=o[0],t=o[1],n=this.symbols.get(`RDA`),r=this.symbols.get(`SOF`);if(e===this.symbols.get(`RDAL`))o=[e,2,t,0];else if(e===n||e===r){let n=o[2],i=o[3];e===r&&(i=a.encode(`S1_14`,i)),o=[e,n,t,i]}}else if(r.mnemonic===`WLDR`){let e=o[2];switch(e){case 512:e=3;break;case 1024:e=2;break;case 2048:e=1;break;case 4096:e=0;break;default:this.problems.push({message:`Invalid amplitude ${e} for WLDR`,isfatal:!0,line:r.line})}let t=o[0];[0,2].includes(t)?t=0:[1,3].includes(t)&&(t=1),o=[t,o[1],e]}else if(r.mnemonic===`JAM`){let e=o[0];[0,2].includes(e)?e=0:[1,3].includes(e)&&(e=1),o=[e]}if(e.fields.forEach((e,t)=>{e.type===`REG`&&o[t]!==void 0&&this.trackRegister(o[t],r.line)}),r.mnemonic===`WRAX`||r.mnemonic===`RDAX`){let e=o[0],t=this.getLFONameFromRegister(e);t&&this.usedLFOs.add(t)}t.push(a.assembleInstruction(r.mnemonic,o,e)),this.addressToLineMap.set(n,r.line),n++}for(;t.length<this.options.progSize;)t.push(17);return t}trackRegister(e,t){if(e>=32&&e<=63){let n=e-32;n>=this.options.regCount&&this.problems.push({message:`Register REG${n} exceeds limit ${this.options.regCount}`,isfatal:!0,line:t}),this.usedRegisters.add(n)}}getLFOName(e){switch(e){case 0:return`SIN0`;case 1:return`SIN1`;case 2:return`RMP0`;case 3:return`RMP1`;default:return null}}getLFONameFromRegister(e){switch(e){case 0:case 1:return`SIN0`;case 2:case 3:return`SIN1`;case 4:case 5:return`RMP0`;case 6:case 7:return`RMP1`;default:return null}}evaluateExpression(e,t){switch(e.type){case`Number`:return e.value;case`Identifier`:return this.symbols.has(e.name)?this.symbols.get(e.name):(this.problems.push({message:`Undefined symbol ${e.name}`,isfatal:!0,line:t}),0);case`Binary`:let n=this.evaluateExpression(e.left,t),r=this.evaluateExpression(e.right,t);switch(e.operator){case`+`:return n+r;case`-`:return n-r;case`*`:return n*r;case`/`:return n/r;case`|`:return n|r;case`&`:return n&r;case`^`:return n^r;case`<`:return n<<r>>>0;case`>`:return n>>>r;default:return 0}case`Unary`:let i=this.evaluateExpression(e.expression,t);return e.operator===`-`?-i:e.operator===`!`?~Math.floor(i)>>>0:i}}static formatMachineCode(e){return e.map((e,t)=>`${t.toString().padStart(4,`0`)}\t${e.toString(16).toUpperCase().padStart(8,`0`)}`).join(`
|
|
7
|
-
`)}static toUint8Array(e){let t=new ArrayBuffer(e.length*4),n=new DataView(t);return e.forEach((e,t)=>n.setUint32(t*4,e,!1)),new Uint8Array(t)}static getMiddleAddr(e,t){return e+(t%2?(t-1)/2-1:t/2)}static getEndAddr(e,t,n){return e+t-1+ +!!n}},s=class e{constructor(){this.delaySize=32768,this.delayMask=32767,this.regCount=32,this.progSize=128,this.sin0=0,this.cos0=0,this.sin1=0,this.cos1=0,this.rmp0=0,this.rmp1=0,this.sin0_rate=0,this.sin0_range=0,this.sin1_rate=0,this.sin1_range=0,this.rmp0_rate=0,this.rmp0_range=0,this.rmp1_rate=0,this.rmp1_range=0,this.acc=0,this.pacc=0,this.lr=0,this.lfo=0,this.delayPointer=0,this.firstRun=!0,this.pc=0,this.breakpoints=new Set,this.symbols=[],this.memories=[],this.fv1AsmMemBug=!1,this.traceEnabled=!1,this.traceWriter=null,this.cycleCount=0,this.traceCycle=0,this.traceMaxCycles=0,this.traceRowCount=0,this.traceDelayAddr=-1,this.traceDelayOffset=-1,this.traceDelayOp=``,this.traceDelayValue=0,this.traceInstructionPC=-1,this.currentReadOffsets=new Set,this.traceOnComplete=null,this.delayRam=new Float32Array(this.delaySize),this.registers=new Float32Array(32+this.regCount),this.program=new Uint32Array(this.progSize)}setCapabilities(e,t,n){this.delaySize=e,this.delayMask=e-1,this.regCount=t,this.progSize=n,this.delayRam=new Float32Array(this.delaySize),this.registers=new Float32Array(32+this.regCount),this.program=new Uint32Array(this.progSize),this.reset()}getDelayPointer(){return this.delayPointer}getDelaySize(){return this.delaySize}loadProgram(e){e.length>this.progSize&&console.warn(`Program size (${e.length}) exceeds max size (${this.progSize}). Truncating.`),this.program.fill(0),this.program.set(e.slice(0,this.progSize)),this.reset()}reset(){this.delayRam.fill(0),this.registers.fill(0),this.acc=0,this.pacc=0,this.lr=0,this.lfo=0,this.pc=0,this.delayPointer=0,this.firstRun=!0,this.sin0=0,this.sin1=0,this.cos0=-1,this.cos1=-1,this.rmp0=0,this.rmp1=0,this.sin0_rate=0,this.sin0_range=0,this.sin1_rate=0,this.sin1_range=0,this.rmp0_rate=0,this.rmp0_range=0,this.rmp1_rate=0,this.rmp1_range=0,this.registers[16]=.5,this.registers[17]=.5,this.registers[18]=.5}setBreakpoints(e){this.breakpoints=e}setSymbols(e,t,n=!1){this.symbols=e,this.memories=t,this.fv1AsmMemBug=n}processBlock(e,t,n,r,i,a,o){let s=e.length;for(let c=0;c<s;c++){let[s,l]=this.step(e[c],t[c],i,a,o);n[c]=s,r[c]=l}}step(e,t,n,r,i,a=!1){this.pc===0&&this.beginFrame(e,t,n,r,i);let o=!0;for(;this.pc<this.progSize;){if(this.breakpoints.has(this.pc)&&(!o||!a))return[...this.getOutputs(),!0];this.stepInstruction(),o=!1}return[...this.endFrame(),!1]}getOutputs(){return[this.registers[22],this.registers[23]]}beginFrame(t=0,n=0,r=0,i=0,a=0){this.cycleCount++,this.currentReadOffsets.clear();let o=t=>Math.max(-1,Math.min(e.MAX_ACC,t)),s=e=>Math.floor(Math.max(0,Math.min(.9999999,e))*1024)/1024;this.acc=0,this.lr=0,this.pacc=0,this.pc=0,this.registers[20]=o(t),this.registers[21]=o(n),this.registers[16]=s(r),this.registers[17]=s(i),this.registers[18]=s(a),this.updateStateRegisters()}endFrame(){return this.pc=0,this.firstRun=!1,this.updateLFOs(),this.updateStateRegisters(),this.advanceTraceCycle(),this.delayPointer=(this.delayPointer-1+this.delaySize)%this.delaySize,[this.registers[22],this.registers[23]]}stepInstruction(){if(this.pc>=this.progSize)return this.pc;let e=this.program[this.pc],t=e&31,n=this.acc;this.traceDelayAddr=-1,this.traceDelayOffset=-1,this.traceDelayOp=``,this.traceDelayValue=0,this.traceInstructionPC=this.pc;let r=this.executeInstruction(e);return this.traceEnabled&&this.logTrace(this.traceInstructionPC,t,e,n),t!==17&&(this.pacc=n),this.pc+=1+r,this.pc}executeInstruction(e){let t=e&31,n=0;switch(t){case 0:this.opRDA(e);break;case 1:this.opRMPA(e);break;case 2:this.opWRA(e);break;case 3:this.opWRAP(e);break;case 4:this.opRDAX(e);break;case 5:this.opRDFX(e);break;case 6:this.opWRAX(e);break;case 7:this.opWRHX(e);break;case 8:this.opWRLX(e);break;case 9:this.opMAXX(e);break;case 10:this.opMULX(e);break;case 11:this.opLOG(e);break;case 12:this.opEXP(e);break;case 13:this.opSOF(e);break;case 14:this.opAND(e);break;case 15:this.opOR(e);break;case 16:this.opXOR(e);break;case 17:n=this.opSKP(e);break;case 18:e>>>30&1?this.opWLDR(e):this.opWLDS(e);break;case 19:this.opJAM(e);break;case 20:this.opCHO(e);break;default:break}return n}opRDA(e){let t=e>>>5&32767,n=this.decodeS1_9(e>>>21&2047),r=this.delayPointer+t&this.delayMask,i=this.delayRam[r];this.traceDelayAddr=r,this.traceDelayOffset=t,this.traceDelayOp=`R`,this.traceDelayValue=i,this.currentReadOffsets.add(t),this.lr=i,this.acc+=i*n,this.acc=this.saturate(this.acc)}opWRA(e){let t=e>>>5&32767,n=this.decodeS1_9(e>>>21&2047),r=this.delayPointer+t&this.delayMask;this.traceDelayAddr=r,this.traceDelayOffset=t,this.traceDelayOp=`W`,this.traceDelayValue=this.acc,this.delayRam[r]=this.acc,this.acc*=n,this.acc=this.saturate(this.acc)}opWRAP(e){let t=e>>>5&32767,n=this.decodeS1_9(e>>>21&2047),r=this.delayPointer+t&this.delayMask;this.traceDelayAddr=r,this.traceDelayOffset=t,this.traceDelayOp=`W`,this.traceDelayValue=this.acc,this.delayRam[r]=this.acc,this.acc=this.acc*n+this.lr,this.acc=this.saturate(this.acc)}opRDAX(e){let t=e>>>5&63,n=this.decodeS1_14(e>>>16&65535),r=this.registers[t];this.acc+=r*n,this.acc=this.saturate(this.acc)}opWRAX(e){let t=e>>>5&63,n=this.decodeS1_14(e>>>16&65535);this.registers[t]=this.acc,this.acc*=n,this.acc=this.saturate(this.acc)}opSOF(e){let t=this.decodeS_10(e>>>5&2047),n=this.decodeS1_14(e>>>16&65535);this.acc=this.acc*n+t,this.acc=this.saturate(this.acc)}opRMPA(e){let t=this.decodeS1_9(e>>>21&2047),n=Math.trunc(this.registers[24]*this.delaySize),r=this.delayPointer+n&this.delayMask,i=this.delayRam[r];this.traceDelayAddr=r,this.traceDelayOffset=n,this.traceDelayOp=`R`,this.traceDelayValue=i,this.currentReadOffsets.add(n),this.lr=i,this.acc+=i*t,this.acc=this.saturate(this.acc)}opMULX(e){let t=e>>>5&63;this.acc*=this.registers[t],this.acc=this.saturate(this.acc)}opLOG(e){let t=this.decodeS4_6(e>>>5&2047),n=this.decodeS1_14(e>>>16&65535),r=Math.abs(this.acc),i;i=r>152587890625e-16?Math.log2(r):-16,this.acc=(i*n+t)/16,this.acc=this.saturate(this.acc)}opEXP(e){let t=this.decodeS_10(e>>>5&2047),n=this.decodeS1_14(e>>>16&65535),r=this.acc*16;this.acc=2**r*n+t,this.acc=this.saturate(this.acc)}opRDFX(e){let t=e>>>5&63,n=this.decodeS1_14(e>>>16&65535),r=this.registers[t];this.acc=(this.acc-r)*n+r,this.acc=this.saturate(this.acc)}opMAXX(e){let t=e>>>5&63,n=this.decodeS1_14(e>>>16&65535),r=Math.abs(this.acc),i=Math.abs(this.registers[t]*n);this.acc=Math.max(r,i),this.acc=this.saturate(this.acc)}opSKP(e){let t=e>>>21&63,n=e&4160749568,r=!1;return n&134217728&&this.acc<0&&(r=!0),n&268435456&&this.acc>=0&&(r=!0),n&536870912&&this.acc===0&&(r=!0),n&1073741824&&this.acc*this.pacc<0&&(r=!0),n&2147483648&&!this.firstRun&&(r=!0),r?t:0}opWRLX(e){let t=e>>>5&63,n=this.decodeS1_14(e>>>16&65535);this.registers[t]=this.acc,this.acc=(this.pacc-this.acc)*n+this.pacc,this.acc=this.saturate(this.acc)}opWRHX(e){let t=e>>>5&63,n=this.decodeS1_14(e>>>16&65535);this.registers[t]=this.acc,this.acc=this.pacc+this.acc*n,this.acc=this.saturate(this.acc)}opAND(e){let t=e>>>8&16777215,n=Math.floor(this.acc*8388608);n&=t,this.acc=n/8388608}opOR(e){let t=e>>>8&16777215,n=Math.floor(this.acc*8388608);n|=t,this.acc=n/8388608}opXOR(e){let t=e>>>8&16777215,n=Math.floor(this.acc*8388608);n^=t,this.acc=n/8388608}opJAM(e){let t=e>>>6&3;t===0?this.rmp0=0:t===1&&(this.rmp1=0)}opWLDS(e){let t=e>>>29&1,n=e>>>20&511,r=e>>>5&32767,i=n/512,a=r/32768;t===0?(this.sin0_rate=i,this.sin0_range=a,this.registers[0]=i,this.registers[1]=a,this.cos0=-1,this.sin0=0):(this.sin1_rate=i,this.sin1_range=a,this.registers[2]=i,this.registers[3]=a,this.cos1=-1,this.sin1=0)}opWLDR(e){let t=e>>>29&1,n=e>>>13&65535;n&32768&&(n-=65536);let r=4096>>(e>>>5&3),i=n/16384,a=r/8192;t===0?(this.rmp0_rate=i,this.rmp0_range=a,this.registers[4]=i,this.registers[5]=a,this.rmp0=0):(this.rmp1_rate=i,this.rmp1_range=a,this.registers[6]=i,this.registers[7]=a,this.rmp1=0)}getLfoVal(e,t){return t===0?e&1?this.cos0:this.sin0:t===1?e&1?this.cos1:this.sin1:t===2?this.rmp0:this.rmp1}getLfoRange(e){return e===0?this.sin0_range:e===1?this.sin1_range:e===2?this.rmp0_range:this.rmp1_range}opCHO(e){let t=e>>>30&3;t===0?this.opCHO_RDA(e):t===2?this.opCHO_SOF(e):t===3&&this.opCHO_RDAL(e)}opCHO_RDA(e){let t=e>>>24&63,n=e>>>21&3,r=e>>>5&32767,i=this.getLfoVal(t,n),a=this.getLfoRange(n);a*=8192,t&2&&(this.lfo=i);let o=this.lfo;t&16&&(o+=.5,o>=1&&--o),t&8&&(o=-o);let s,c;if(t&32)s=r,c=Math.min(o,1-o),c=Math.max(0,Math.min(1,4*c-.5));else{let e=o*a+r;s=Math.floor(e),c=e-s}let l=this.delayPointer+s&this.delayMask;this.lr=this.delayRam[l],this.traceDelayAddr=l,this.traceDelayOffset=s,this.traceDelayOp=`R`,this.traceDelayValue=this.lr,this.currentReadOffsets.add(s),t&4&&(c=1-c),this.acc+=this.lr*c,this.acc=this.saturate(this.acc)}opCHO_SOF(e){let t=e>>>24&63,n=e>>>21&3,r=e>>>5&65535,i=this.decodeS_15(r),a=this.getLfoVal(t,n),o=this.getLfoRange(n);t&2&&(this.lfo=a);let s=this.lfo;t&32?(s=Math.min(s,1-s),s=Math.max(0,Math.min(1,4*s-.5))):s*=o,t&4&&(s=1-s),this.acc=s*this.acc+i,this.acc=this.saturate(this.acc)}opCHO_RDAL(e){let t=e>>>24&63,n=e>>>21&3,r=this.getLfoVal(t,n);this.acc=r,this.acc=this.saturate(this.acc)}getPC(){return this.pc}getProgSize(){return this.progSize}setPC(e){this.pc=Math.max(0,Math.min(this.progSize-1,e))}setAcc(e){this.acc=this.saturate(e)}setPacc(e){this.pacc=this.saturate(e)}setRegister(e,t){e<0||e>=32+this.regCount||(t=e>=16&&e<=18?Math.floor(Math.max(0,Math.min(.9999999,t))*1024)/1024:this.saturate(t),this.registers[e]=t)}evaluateExpression(e){let t=e.trim().toUpperCase(),n=``;t.endsWith(`^`)?(n=`^`,t=t.slice(0,-1)):t.endsWith(`#`)&&(n=`#`,t=t.slice(0,-1));let r=this.getState();if(n===``&&r.registers[t]!==void 0)return{label:t,value:r.registers[t]};if(n===``&&t===`ACC`)return{label:`ACC`,value:this.acc};if(n===``&&t===`PACC`)return{label:`PACC`,value:this.pacc};let i=this.symbols.find(e=>e.name.toUpperCase()===t);if(i&&n===``){let e=parseInt(i.value);if(!isNaN(e)&&e>=0&&e<=63)return{label:`REG[${e}] (${i.name})`,value:this.registers[e]}}let a=this.memories.find(e=>e.name.toUpperCase()===t);if(a&&a.start!==void 0){let e=a.start,t=``;if(n===`^`?(e=o.getMiddleAddr(a.start,a.size),t=` (Middle)`):n===`#`&&(e=o.getEndAddr(a.start,a.size,this.fv1AsmMemBug),t=` (End)`),e>=0&&e<this.delaySize)return{label:`MEM[${e}] (${a.name}${t})`,value:this.delayRam[e]}}if(n===``){let e=t.match(/^DELAY\[(\d+)\]$/);if(e){let t=parseInt(e[1]);if(t>=0&&t<this.delaySize)return{label:`DELAY[${t}]`,value:this.delayRam[t]}}}return null}getState(){return{pc:this.pc,acc:this.acc,pacc:this.pacc,lr:this.lr,lfo:this.lfo,registers:Object.fromEntries(Array.from({length:32+this.regCount},(e,t)=>{let n=`[${t}]`;return t===0?n=`SIN0_RATE`:t===1?n=`SIN0_RANGE`:t===2?n=`SIN1_RATE`:t===3?n=`SIN1_RANGE`:t===4?n=`RMP0_RATE`:t===5?n=`RMP0_RANGE`:t===6?n=`RMP1_RATE`:t===7?n=`RMP1_RANGE`:t===8?n=`SIN0`:t===9?n=`COS0`:t===10?n=`SIN1`:t===11?n=`COS1`:t===12?n=`RMP0`:t===13?n=`RMP1`:t===16?n=`POT0`:t===17?n=`POT1`:t===18?n=`POT2`:t===20?n=`ADCL`:t===21?n=`ADCR`:t===22?n=`DACL`:t===23?n=`DACR`:t===24?n=`ADDR_PTR`:t>=32&&t<=63&&(n=`REG${t-32}`),[n,this.registers[t]]})),flags:{RUN:this.firstRun,ZRC:this.acc*this.pacc<0,ZRO:this.acc===0,GEZ:this.acc>=0,NEG:this.acc<0},lfoState:{sin0:this.sin0,cos0:this.cos0,sin1:this.sin1,cos1:this.cos1,rmp0:this.rmp0,rmp1:this.rmp1}}}getCycleCount(){return this.cycleCount}getReadOffsets(){return Array.from(this.currentReadOffsets)}getRegisters(){return this.registers}updateLFOs(){for(this.sin0_rate=this.registers[0],this.sin0_range=this.registers[1],this.sin1_rate=this.registers[2],this.sin1_range=this.registers[3],this.rmp0_rate=this.registers[4],this.rmp0_range=this.registers[5],this.rmp1_rate=this.registers[6],this.rmp1_range=this.registers[7],this.rmp0-=this.rmp0_rate*(1/4096);this.rmp0>=1;)--this.rmp0;for(;this.rmp0<0;)this.rmp0+=1;for(this.rmp1-=this.rmp1_rate*(1/4096);this.rmp1>=1;)--this.rmp1;for(;this.rmp1<0;)this.rmp1+=1;let t=this.sin0_rate*(1/256);this.cos0+=t*this.sin0,this.sin0-=t*this.cos0,this.sin0=Math.max(e.MIN_ACC,Math.min(e.MAX_ACC,this.sin0)),this.cos0=Math.max(e.MIN_ACC,Math.min(e.MAX_ACC,this.cos0));let n=this.sin1_rate*(1/256);this.cos1+=n*this.sin1,this.sin1-=n*this.cos1,this.sin1=Math.max(e.MIN_ACC,Math.min(e.MAX_ACC,this.sin1)),this.cos1=Math.max(e.MIN_ACC,Math.min(e.MAX_ACC,this.cos1))}updateStateRegisters(){this.registers[8]=this.sin0,this.registers[9]=this.cos0,this.registers[10]=this.sin1,this.registers[11]=this.cos1,this.registers[12]=this.rmp0,this.registers[13]=this.rmp1}getDelayRam(){return this.delayRam}decodeS1_14(e){return e&32768?(e-65536)/16384:e/16384}decodeS1_9(e){return e&1024?(e-2048)/512:e/512}decodeS_10(e){return e&1024?(e-2048)/1024:e/1024}decodeS4_6(e){return e&1024?(e-2048)/64:e/64}decodeS_15(e){return e&32768?(e-65536)/32768:e/32768}saturate(t){return t>e.MAX_ACC?e.MAX_ACC:t<e.MIN_ACC?e.MIN_ACC:t}enableTrace(e,t=0,n){this.traceEnabled=!0,this.traceWriter=e,this.traceMaxCycles=t,this.traceCycle=0,this.traceRowCount=0,this.traceOnComplete=n||null,e(`cycle,pc,opcode,delay_op,delay_offset,delay_addr,delay_ptr`),console.log(`[FV1 Trace] Logging enabled (maxCycles=${t||`unlimited`})`)}disableTrace(){this.traceEnabled=!1,this.traceWriter=null,console.log(`[FV1 Trace] Logging disabled. ${this.traceRowCount} rows written.`)}isTraceEnabled(){return this.traceEnabled}getTraceRowCount(){return this.traceRowCount}advanceTraceCycle(){if(this.traceEnabled&&(this.traceCycle++,this.traceMaxCycles>0&&this.traceCycle>=this.traceMaxCycles)){let e=this.traceOnComplete;this.disableTrace(),e&&e()}}logTrace(t,n,r,i){if(!this.traceWriter||this.traceDelayOp===``)return;let a=e.OPCODE_NAMES[n]||`?${n.toString(16)}`;if(n===20){let e=r>>>30&3;if(e===0)a=`CHO_RDA`;else if(e===2)return;else e===3&&(a=`CHO_RDAL`)}else if(n===18)return;let o=`${this.traceCycle},${t},${a},${this.traceDelayOp},${this.traceDelayOp===``?``:this.traceDelayOffset},${this.traceDelayAddr>=0?this.traceDelayAddr:``},${this.delayPointer}`;this.traceWriter(o),this.traceRowCount++}};s.MAX_ACC=1-1/8388608,s.MIN_ACC=-s.MAX_ACC,s.OPCODE_NAMES={0:`RDA`,1:`RMPA`,2:`WRA`,3:`WRAP`,4:`RDAX`,5:`RDFX`,6:`WRAX`,7:`WRHX`,8:`WRLX`,9:`MAXX`,10:`MULX`,11:`LOG`,12:`EXP`,13:`SOF`,14:`AND`,15:`OR`,16:`XOR`,17:`SKP`,18:`WLDx`,19:`JAM`,20:`CHO`};var c=class extends AudioWorkletProcessor{simulator=new s;pot=[.5,.5,.5];bypassed=!1;channelMode=`mono`;constructor(){super(),this.port.onmessage=({data:e})=>{switch(e.type){case`loadProgram`:this.simulator.loadProgram(new Uint32Array(e.machineCode));break;case`setPot`:this.pot[e.index]=e.value;break;case`bypass`:this.bypassed=e.active;break;case`setChannelMode`:this.channelMode=e.mode===`stereo`?`stereo`:`mono`;break}}}process(e,t){let n=e[0],r=t[0];if(!n?.length||!r?.length)return!0;let i=n[0],a=n[1]??i,o=r[0],s=r[1]??o;return this.bypassed?(o.set(i),r[1]&&s.set(a),!0):(this.simulator.processBlock(i,a,o,s,this.pot[0],this.pot[1],this.pot[2]),this.channelMode===`mono`&&r[1]&&s.set(o),!0)}};registerProcessor(`fv1-processor`,c)})();
|
|
7
|
+
`)}static toUint8Array(e){let t=new ArrayBuffer(e.length*4),n=new DataView(t);return e.forEach((e,t)=>n.setUint32(t*4,e,!1)),new Uint8Array(t)}static getMiddleAddr(e,t){return e+(t%2?(t-1)/2-1:t/2)}static getEndAddr(e,t,n){return e+t-1+ +!!n}},s=class e{constructor(){this.delaySize=32768,this.delayMask=32767,this.regCount=32,this.progSize=128,this.sin0=0,this.cos0=0,this.sin1=0,this.cos1=0,this.rmp0=0,this.rmp1=0,this.sin0_rate=0,this.sin0_range=0,this.sin1_rate=0,this.sin1_range=0,this.rmp0_rate=0,this.rmp0_range=0,this.rmp1_rate=0,this.rmp1_range=0,this.acc=0,this.pacc=0,this.lr=0,this.lfo=0,this.delayPointer=0,this.firstRun=!0,this.pc=0,this.breakpoints=new Set,this.symbols=[],this.memories=[],this.fv1AsmMemBug=!1,this.traceEnabled=!1,this.traceWriter=null,this.cycleCount=0,this.traceCycle=0,this.traceMaxCycles=0,this.traceRowCount=0,this.traceDelayAddr=-1,this.traceDelayOffset=-1,this.traceDelayOp=``,this.traceDelayValue=0,this.traceInstructionPC=-1,this.currentReadOffsets=new Set,this.traceOnComplete=null,this.delayRam=new Float32Array(this.delaySize),this.registers=new Float32Array(32+this.regCount),this.program=new Uint32Array(this.progSize)}setCapabilities(e,t,n){this.delaySize=e,this.delayMask=e-1,this.regCount=t,this.progSize=n,this.delayRam=new Float32Array(this.delaySize),this.registers=new Float32Array(32+this.regCount),this.program=new Uint32Array(this.progSize),this.reset()}getDelayPointer(){return this.delayPointer}getDelaySize(){return this.delaySize}loadProgram(e){e.length>this.progSize&&console.warn(`Program size (${e.length}) exceeds max size (${this.progSize}). Truncating.`),this.program.fill(0),this.program.set(e.slice(0,this.progSize)),this.reset()}reset(){this.delayRam.fill(0),this.registers.fill(0),this.acc=0,this.pacc=0,this.lr=0,this.lfo=0,this.pc=0,this.delayPointer=0,this.firstRun=!0,this.sin0=0,this.sin1=0,this.cos0=-1,this.cos1=-1,this.rmp0=0,this.rmp1=0,this.sin0_rate=0,this.sin0_range=0,this.sin1_rate=0,this.sin1_range=0,this.rmp0_rate=0,this.rmp0_range=0,this.rmp1_rate=0,this.rmp1_range=0,this.registers[16]=.5,this.registers[17]=.5,this.registers[18]=.5}setBreakpoints(e){this.breakpoints=e}setSymbols(e,t,n=!1){this.symbols=e,this.memories=t,this.fv1AsmMemBug=n}processBlock(e,t,n,r,i,a,o){let s=e.length;for(let c=0;c<s;c++){let[s,l]=this.step(e[c],t[c],i,a,o);n[c]=s,r[c]=l}}step(e,t,n,r,i,a=!1){this.pc===0&&this.beginFrame(e,t,n,r,i);let o=!0;for(;this.pc<this.progSize;){if(this.breakpoints.has(this.pc)&&(!o||!a))return[...this.getOutputs(),!0];this.stepInstruction(),o=!1}return[...this.endFrame(),!1]}getOutputs(){return[this.registers[22],this.registers[23]]}beginFrame(t=0,n=0,r=0,i=0,a=0){this.cycleCount++,this.currentReadOffsets.clear();let o=t=>Math.max(-1,Math.min(e.MAX_ACC,t)),s=e=>Math.floor(Math.max(0,Math.min(.9999999,e))*1024)/1024;this.acc=0,this.lr=0,this.pacc=0,this.pc=0,this.registers[20]=o(t),this.registers[21]=o(n),this.registers[16]=s(r),this.registers[17]=s(i),this.registers[18]=s(a),this.updateStateRegisters()}endFrame(){return this.pc=0,this.firstRun=!1,this.updateLFOs(),this.updateStateRegisters(),this.advanceTraceCycle(),this.delayPointer=(this.delayPointer-1+this.delaySize)%this.delaySize,[this.registers[22],this.registers[23]]}stepInstruction(){if(this.pc>=this.progSize)return this.pc;let e=this.program[this.pc],t=e&31,n=this.acc;this.traceDelayAddr=-1,this.traceDelayOffset=-1,this.traceDelayOp=``,this.traceDelayValue=0,this.traceInstructionPC=this.pc;let r=this.executeInstruction(e);return this.traceEnabled&&this.logTrace(this.traceInstructionPC,t,e,n),t!==17&&(this.pacc=n),this.pc+=1+r,this.pc}executeInstruction(e){let t=e&31,n=0;switch(t){case 0:this.opRDA(e);break;case 1:this.opRMPA(e);break;case 2:this.opWRA(e);break;case 3:this.opWRAP(e);break;case 4:this.opRDAX(e);break;case 5:this.opRDFX(e);break;case 6:this.opWRAX(e);break;case 7:this.opWRHX(e);break;case 8:this.opWRLX(e);break;case 9:this.opMAXX(e);break;case 10:this.opMULX(e);break;case 11:this.opLOG(e);break;case 12:this.opEXP(e);break;case 13:this.opSOF(e);break;case 14:this.opAND(e);break;case 15:this.opOR(e);break;case 16:this.opXOR(e);break;case 17:n=this.opSKP(e);break;case 18:e>>>30&1?this.opWLDR(e):this.opWLDS(e);break;case 19:this.opJAM(e);break;case 20:this.opCHO(e);break;default:break}return n}opRDA(e){let t=e>>>5&32767,n=this.decodeS1_9(e>>>21&2047),r=this.delayPointer+t&this.delayMask,i=this.delayRam[r];this.traceDelayAddr=r,this.traceDelayOffset=t,this.traceDelayOp=`R`,this.traceDelayValue=i,this.currentReadOffsets.add(t),this.lr=i,this.acc+=i*n,this.acc=this.saturate(this.acc)}opWRA(e){let t=e>>>5&32767,n=this.decodeS1_9(e>>>21&2047),r=this.delayPointer+t&this.delayMask;this.traceDelayAddr=r,this.traceDelayOffset=t,this.traceDelayOp=`W`,this.traceDelayValue=this.acc,this.delayRam[r]=this.acc,this.acc*=n,this.acc=this.saturate(this.acc)}opWRAP(e){let t=e>>>5&32767,n=this.decodeS1_9(e>>>21&2047),r=this.delayPointer+t&this.delayMask;this.traceDelayAddr=r,this.traceDelayOffset=t,this.traceDelayOp=`W`,this.traceDelayValue=this.acc,this.delayRam[r]=this.acc,this.acc=this.acc*n+this.lr,this.acc=this.saturate(this.acc)}opRDAX(e){let t=e>>>5&63,n=this.decodeS1_14(e>>>16&65535),r=this.registers[t];this.acc+=r*n,this.acc=this.saturate(this.acc)}opWRAX(e){let t=e>>>5&63,n=this.decodeS1_14(e>>>16&65535);this.registers[t]=this.acc,this.acc*=n,this.acc=this.saturate(this.acc)}opSOF(e){let t=this.decodeS_10(e>>>5&2047),n=this.decodeS1_14(e>>>16&65535);this.acc=this.acc*n+t,this.acc=this.saturate(this.acc)}opRMPA(e){let t=this.decodeS1_9(e>>>21&2047),n=Math.trunc(this.registers[24]*this.delaySize),r=this.delayPointer+n&this.delayMask,i=this.delayRam[r];this.traceDelayAddr=r,this.traceDelayOffset=n,this.traceDelayOp=`R`,this.traceDelayValue=i,this.currentReadOffsets.add(n),this.lr=i,this.acc+=i*t,this.acc=this.saturate(this.acc)}opMULX(e){let t=e>>>5&63;this.acc*=this.registers[t],this.acc=this.saturate(this.acc)}opLOG(e){let t=this.decodeS4_6(e>>>5&2047),n=this.decodeS1_14(e>>>16&65535),r=Math.abs(this.acc),i;i=r>152587890625e-16?Math.log2(r):-16,this.acc=(i*n+t)/16,this.acc=this.saturate(this.acc)}opEXP(e){let t=this.decodeS_10(e>>>5&2047),n=this.decodeS1_14(e>>>16&65535),r=this.acc*16;this.acc=2**r*n+t,this.acc=this.saturate(this.acc)}opRDFX(e){let t=e>>>5&63,n=this.decodeS1_14(e>>>16&65535),r=this.registers[t];this.acc=(this.acc-r)*n+r,this.acc=this.saturate(this.acc)}opMAXX(e){let t=e>>>5&63,n=this.decodeS1_14(e>>>16&65535),r=Math.abs(this.acc),i=Math.abs(this.registers[t]*n);this.acc=Math.max(r,i),this.acc=this.saturate(this.acc)}opSKP(e){let t=e>>>21&63,n=e&4160749568,r=!1;return n&134217728&&this.acc<0&&(r=!0),n&268435456&&this.acc>=0&&(r=!0),n&536870912&&this.acc===0&&(r=!0),n&1073741824&&this.acc*this.pacc<0&&(r=!0),n&2147483648&&!this.firstRun&&(r=!0),r?t:0}opWRLX(e){let t=e>>>5&63,n=this.decodeS1_14(e>>>16&65535);this.registers[t]=this.acc,this.acc=(this.pacc-this.acc)*n+this.pacc,this.acc=this.saturate(this.acc)}opWRHX(e){let t=e>>>5&63,n=this.decodeS1_14(e>>>16&65535);this.registers[t]=this.acc,this.acc=this.pacc+this.acc*n,this.acc=this.saturate(this.acc)}opAND(e){let t=e>>>8&16777215,n=Math.floor(this.acc*8388608);n&=t,this.acc=n/8388608}opOR(e){let t=e>>>8&16777215,n=Math.floor(this.acc*8388608);n|=t,this.acc=n/8388608}opXOR(e){let t=e>>>8&16777215,n=Math.floor(this.acc*8388608);n^=t,this.acc=n/8388608}opJAM(e){let t=e>>>6&3;t===0?this.rmp0=0:t===1&&(this.rmp1=0)}opWLDS(e){let t=e>>>29&1,n=e>>>20&511,r=e>>>5&32767,i=n/512,a=r/32768;t===0?(this.sin0_rate=i,this.sin0_range=a,this.registers[0]=i,this.registers[1]=a,this.cos0=-1,this.sin0=0):(this.sin1_rate=i,this.sin1_range=a,this.registers[2]=i,this.registers[3]=a,this.cos1=-1,this.sin1=0)}opWLDR(e){let t=e>>>29&1,n=e>>>13&65535;n&32768&&(n-=65536);let r=4096>>(e>>>5&3),i=n/16384,a=r/8192;t===0?(this.rmp0_rate=i,this.rmp0_range=a,this.registers[4]=i,this.registers[5]=a,this.rmp0=0):(this.rmp1_rate=i,this.rmp1_range=a,this.registers[6]=i,this.registers[7]=a,this.rmp1=0)}getLfoVal(e,t){return t===0?e&1?this.cos0:this.sin0:t===1?e&1?this.cos1:this.sin1:t===2?this.rmp0:this.rmp1}getLfoRange(e){return e===0?this.sin0_range:e===1?this.sin1_range:e===2?this.rmp0_range:this.rmp1_range}opCHO(e){let t=e>>>30&3;t===0?this.opCHO_RDA(e):t===2?this.opCHO_SOF(e):t===3&&this.opCHO_RDAL(e)}opCHO_RDA(e){let t=e>>>24&63,n=e>>>21&3,r=e>>>5&32767,i=this.getLfoVal(t,n),a=this.getLfoRange(n);a*=8192,t&2&&(this.lfo=i);let o=this.lfo;t&16&&(o+=.5,o>=1&&--o),t&8&&(o=-o);let s,c;if(t&32)s=r,c=Math.min(o,1-o),c=Math.max(0,Math.min(1,4*c-.5));else{let e=o*a+r;s=Math.floor(e),c=e-s}let l=this.delayPointer+s&this.delayMask;this.lr=this.delayRam[l],this.traceDelayAddr=l,this.traceDelayOffset=s,this.traceDelayOp=`R`,this.traceDelayValue=this.lr,this.currentReadOffsets.add(s),t&4&&(c=1-c),this.acc+=this.lr*c,this.acc=this.saturate(this.acc)}opCHO_SOF(e){let t=e>>>24&63,n=e>>>21&3,r=e>>>5&65535,i=this.decodeS_15(r),a=this.getLfoVal(t,n),o=this.getLfoRange(n);t&2&&(this.lfo=a);let s=this.lfo;t&32?(s=Math.min(s,1-s),s=Math.max(0,Math.min(1,4*s-.5))):s*=o,t&4&&(s=1-s),this.acc=s*this.acc+i,this.acc=this.saturate(this.acc)}opCHO_RDAL(e){let t=e>>>24&63,n=e>>>21&3,r=this.getLfoVal(t,n);this.acc=r,this.acc=this.saturate(this.acc)}getPC(){return this.pc}getProgSize(){return this.progSize}setPC(e){this.pc=Math.max(0,Math.min(this.progSize-1,e))}setAcc(e){this.acc=this.saturate(e)}setPacc(e){this.pacc=this.saturate(e)}setRegister(e,t){e<0||e>=32+this.regCount||(t=e>=16&&e<=18?Math.floor(Math.max(0,Math.min(.9999999,t))*1024)/1024:this.saturate(t),this.registers[e]=t)}evaluateExpression(e){let t=e.trim().toUpperCase(),n=``;t.endsWith(`^`)?(n=`^`,t=t.slice(0,-1)):t.endsWith(`#`)&&(n=`#`,t=t.slice(0,-1));let r=this.getState();if(n===``&&r.registers[t]!==void 0)return{label:t,value:r.registers[t]};if(n===``&&t===`ACC`)return{label:`ACC`,value:this.acc};if(n===``&&t===`PACC`)return{label:`PACC`,value:this.pacc};let i=this.symbols.find(e=>e.name.toUpperCase()===t);if(i&&n===``){let e=parseInt(i.value);if(!isNaN(e)&&e>=0&&e<=63)return{label:`REG[${e}] (${i.name})`,value:this.registers[e]}}let a=this.memories.find(e=>e.name.toUpperCase()===t);if(a&&a.start!==void 0){let e=a.start,t=``;if(n===`^`?(e=o.getMiddleAddr(a.start,a.size),t=` (Middle)`):n===`#`&&(e=o.getEndAddr(a.start,a.size,this.fv1AsmMemBug),t=` (End)`),e>=0&&e<this.delaySize)return{label:`MEM[${e}] (${a.name}${t})`,value:this.delayRam[e]}}if(n===``){let e=t.match(/^DELAY\[(\d+)\]$/);if(e){let t=parseInt(e[1]);if(t>=0&&t<this.delaySize)return{label:`DELAY[${t}]`,value:this.delayRam[t]}}}return null}getState(){return{pc:this.pc,acc:this.acc,pacc:this.pacc,lr:this.lr,lfo:this.lfo,registers:Object.fromEntries(Array.from({length:32+this.regCount},(e,t)=>{let n=`[${t}]`;return t===0?n=`SIN0_RATE`:t===1?n=`SIN0_RANGE`:t===2?n=`SIN1_RATE`:t===3?n=`SIN1_RANGE`:t===4?n=`RMP0_RATE`:t===5?n=`RMP0_RANGE`:t===6?n=`RMP1_RATE`:t===7?n=`RMP1_RANGE`:t===8?n=`SIN0`:t===9?n=`COS0`:t===10?n=`SIN1`:t===11?n=`COS1`:t===12?n=`RMP0`:t===13?n=`RMP1`:t===16?n=`POT0`:t===17?n=`POT1`:t===18?n=`POT2`:t===20?n=`ADCL`:t===21?n=`ADCR`:t===22?n=`DACL`:t===23?n=`DACR`:t===24?n=`ADDR_PTR`:t>=32&&t<=63&&(n=`REG${t-32}`),[n,this.registers[t]]})),flags:{RUN:this.firstRun,ZRC:this.acc*this.pacc<0,ZRO:this.acc===0,GEZ:this.acc>=0,NEG:this.acc<0},lfoState:{sin0:this.sin0,cos0:this.cos0,sin1:this.sin1,cos1:this.cos1,rmp0:this.rmp0,rmp1:this.rmp1}}}getCycleCount(){return this.cycleCount}getReadOffsets(){return Array.from(this.currentReadOffsets)}getRegisters(){return this.registers}updateLFOs(){for(this.sin0_rate=this.registers[0],this.sin0_range=this.registers[1],this.sin1_rate=this.registers[2],this.sin1_range=this.registers[3],this.rmp0_rate=this.registers[4],this.rmp0_range=this.registers[5],this.rmp1_rate=this.registers[6],this.rmp1_range=this.registers[7],this.rmp0-=this.rmp0_rate*(1/4096);this.rmp0>=1;)--this.rmp0;for(;this.rmp0<0;)this.rmp0+=1;for(this.rmp1-=this.rmp1_rate*(1/4096);this.rmp1>=1;)--this.rmp1;for(;this.rmp1<0;)this.rmp1+=1;let t=this.sin0_rate*(1/256);this.cos0+=t*this.sin0,this.sin0-=t*this.cos0,this.sin0=Math.max(e.MIN_ACC,Math.min(e.MAX_ACC,this.sin0)),this.cos0=Math.max(e.MIN_ACC,Math.min(e.MAX_ACC,this.cos0));let n=this.sin1_rate*(1/256);this.cos1+=n*this.sin1,this.sin1-=n*this.cos1,this.sin1=Math.max(e.MIN_ACC,Math.min(e.MAX_ACC,this.sin1)),this.cos1=Math.max(e.MIN_ACC,Math.min(e.MAX_ACC,this.cos1))}updateStateRegisters(){this.registers[8]=this.sin0,this.registers[9]=this.cos0,this.registers[10]=this.sin1,this.registers[11]=this.cos1,this.registers[12]=this.rmp0,this.registers[13]=this.rmp1}getDelayRam(){return this.delayRam}decodeS1_14(e){return e&32768?(e-65536)/16384:e/16384}decodeS1_9(e){return e&1024?(e-2048)/512:e/512}decodeS_10(e){return e&1024?(e-2048)/1024:e/1024}decodeS4_6(e){return e&1024?(e-2048)/64:e/64}decodeS_15(e){return e&32768?(e-65536)/32768:e/32768}saturate(t){return t>e.MAX_ACC?e.MAX_ACC:t<e.MIN_ACC?e.MIN_ACC:t}enableTrace(e,t=0,n){this.traceEnabled=!0,this.traceWriter=e,this.traceMaxCycles=t,this.traceCycle=0,this.traceRowCount=0,this.traceOnComplete=n||null,e(`cycle,pc,opcode,delay_op,delay_offset,delay_addr,delay_ptr`),console.log(`[FV1 Trace] Logging enabled (maxCycles=${t||`unlimited`})`)}disableTrace(){this.traceEnabled=!1,this.traceWriter=null,console.log(`[FV1 Trace] Logging disabled. ${this.traceRowCount} rows written.`)}isTraceEnabled(){return this.traceEnabled}getTraceRowCount(){return this.traceRowCount}advanceTraceCycle(){if(this.traceEnabled&&(this.traceCycle++,this.traceMaxCycles>0&&this.traceCycle>=this.traceMaxCycles)){let e=this.traceOnComplete;this.disableTrace(),e&&e()}}logTrace(t,n,r,i){if(!this.traceWriter||this.traceDelayOp===``)return;let a=e.OPCODE_NAMES[n]||`?${n.toString(16)}`;if(n===20){let e=r>>>30&3;if(e===0)a=`CHO_RDA`;else if(e===2)return;else e===3&&(a=`CHO_RDAL`)}else if(n===18)return;let o=`${this.traceCycle},${t},${a},${this.traceDelayOp},${this.traceDelayOp===``?``:this.traceDelayOffset},${this.traceDelayAddr>=0?this.traceDelayAddr:``},${this.delayPointer}`;this.traceWriter(o),this.traceRowCount++}};s.MAX_ACC=1-1/8388608,s.MIN_ACC=-s.MAX_ACC,s.OPCODE_NAMES={0:`RDA`,1:`RMPA`,2:`WRA`,3:`WRAP`,4:`RDAX`,5:`RDFX`,6:`WRAX`,7:`WRHX`,8:`WRLX`,9:`MAXX`,10:`MULX`,11:`LOG`,12:`EXP`,13:`SOF`,14:`AND`,15:`OR`,16:`XOR`,17:`SKP`,18:`WLDx`,19:`JAM`,20:`CHO`};var c=class e extends AudioWorkletProcessor{simulator=new s;pot=[.5,.5,.5];bypassed=!1;channelMode=`mono`;blockTimeUsEma=0;blocksSinceReport=0;static BLOCK_TIME_REPORT_INTERVAL=24;constructor(){super(),this.port.onmessage=({data:e})=>{switch(e.type){case`loadProgram`:this.simulator.loadProgram(new Uint32Array(e.machineCode));break;case`setPot`:this.pot[e.index]=e.value;break;case`bypass`:this.bypassed=e.active;break;case`setChannelMode`:this.channelMode=e.mode===`stereo`?`stereo`:`mono`;break}}}process(t,n){let r=t[0],i=n[0];if(!r?.length||!i?.length)return!0;let a=r[0],o=r[1]??a,s=i[0],c=i[1]??s;if(this.bypassed)return s.set(a),i[1]&&c.set(o),!0;let l=performance.now();this.simulator.processBlock(a,o,s,c,this.pot[0],this.pot[1],this.pot[2]);let u=(performance.now()-l)*1e3;return this.blockTimeUsEma=this.blockTimeUsEma===0?u:this.blockTimeUsEma*.95+u*.05,this.channelMode===`mono`&&i[1]&&c.set(s),++this.blocksSinceReport>=e.BLOCK_TIME_REPORT_INTERVAL&&(this.blocksSinceReport=0,this.port.postMessage({type:`blockTime`,us:this.blockTimeUsEma})),!0}};registerProcessor(`fv1-processor`,c)})();
|
|
8
8
|
//# sourceMappingURL=fv1-processor.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fv1-processor.js","names":[],"sources":["../../node_modules/@audiofab-io/fv1-core/dist/assembler/FV1Parser.js","../../node_modules/@audiofab-io/fv1-core/dist/assembler/FV1Encoder.js","../../node_modules/@audiofab-io/fv1-core/dist/assembler/FV1Assembler.js","../../node_modules/@audiofab-io/fv1-core/dist/simulator/FV1Simulator.js","../../src/worklet/fv1-processor.ts"],"sourcesContent":["export class ParserError extends Error {\n constructor(message, line, column) {\n super(message);\n this.line = line;\n this.column = column;\n this.name = 'ParserError';\n }\n}\nexport var TokenType;\n(function (TokenType) {\n TokenType[TokenType[\"IDENTIFIER\"] = 0] = \"IDENTIFIER\";\n TokenType[TokenType[\"NUMBER\"] = 1] = \"NUMBER\";\n TokenType[TokenType[\"MNEMONIC\"] = 2] = \"MNEMONIC\";\n TokenType[TokenType[\"DIRECTIVE\"] = 3] = \"DIRECTIVE\";\n TokenType[TokenType[\"OPERATOR\"] = 4] = \"OPERATOR\";\n TokenType[TokenType[\"COMMA\"] = 5] = \"COMMA\";\n TokenType[TokenType[\"COLON\"] = 6] = \"COLON\";\n TokenType[TokenType[\"NEWLINE\"] = 7] = \"NEWLINE\";\n TokenType[TokenType[\"EOF\"] = 8] = \"EOF\";\n TokenType[TokenType[\"LPAREN\"] = 9] = \"LPAREN\";\n TokenType[TokenType[\"RPAREN\"] = 10] = \"RPAREN\";\n})(TokenType || (TokenType = {}));\nexport class Lexer {\n constructor(source) {\n this.source = source;\n this.pos = 0;\n this.line = 1;\n this.column = 1;\n }\n peek() {\n return this.source[this.pos] || '';\n }\n advance() {\n const char = this.peek();\n this.pos++;\n if (char === '\\n') {\n this.line++;\n this.column = 1;\n }\n else {\n this.column++;\n }\n return char;\n }\n tokenize() {\n const tokens = [];\n while (this.pos < this.source.length) {\n const char = this.peek();\n if (/\\s/.test(char) && char !== '\\n') {\n this.advance();\n }\n else if (char === ';') {\n // Skip comments\n while (this.peek() !== '\\n' && this.pos < this.source.length) {\n this.advance();\n }\n }\n else if (char === '\\n') {\n tokens.push({ type: TokenType.NEWLINE, value: '\\n', line: this.line, column: this.column });\n this.advance();\n }\n else if (char === ',') {\n tokens.push({ type: TokenType.COMMA, value: ',', line: this.line, column: this.column });\n this.advance();\n }\n else if (char === ':') {\n tokens.push({ type: TokenType.COLON, value: ':', line: this.line, column: this.column });\n this.advance();\n }\n else if (char === '(') {\n tokens.push({ type: TokenType.LPAREN, value: '(', line: this.line, column: this.column });\n this.advance();\n }\n else if (char === ')') {\n tokens.push({ type: TokenType.RPAREN, value: ')', line: this.line, column: this.column });\n this.advance();\n }\n else if (/[a-zA-Z_]/.test(char)) {\n tokens.push(this.readIdentifier());\n }\n else if (/[0-9.]/.test(char) || char === '$' || char === '%') {\n tokens.push(this.readNumber());\n }\n else if (/[-+*/|&<>^!]/.test(char)) {\n tokens.push({ type: TokenType.OPERATOR, value: this.advance(), line: this.line, column: this.column });\n }\n else {\n // Unknown character\n this.advance();\n }\n }\n tokens.push({ type: TokenType.EOF, value: '', line: this.line, column: this.column });\n return tokens;\n }\n readIdentifier() {\n let value = '';\n const startLine = this.line;\n const startCol = this.column;\n while (/[a-zA-Z0-9_#^.]/.test(this.peek())) {\n value += this.advance();\n }\n const upper = value.toUpperCase();\n if (['EQU', 'MEM'].includes(upper)) {\n return { type: TokenType.DIRECTIVE, value: upper, line: startLine, column: startCol };\n }\n // Mnemonics are checked during parsing or here. Let's keep them as identifiers for now \n // and resolve them in the parser.\n return { type: TokenType.IDENTIFIER, value: upper, line: startLine, column: startCol };\n }\n readNumber() {\n let value = '';\n const startLine = this.line;\n const startCol = this.column;\n if (this.peek() === '$') {\n value += this.advance();\n while (/[0-9a-fA-F]/.test(this.peek()))\n value += this.advance();\n }\n else if (this.peek() === '%') {\n value += this.advance();\n while (/[01_]/.test(this.peek()))\n value += this.advance();\n }\n else if (this.peek() === '0' && (this.source[this.pos + 1] || '').toLowerCase() === 'x') {\n value += this.advance(); // 0\n value += this.advance(); // x\n while (/[0-9a-fA-F]/.test(this.peek()))\n value += this.advance();\n }\n else {\n while (/[0-9\\.]/.test(this.peek()))\n value += this.advance();\n }\n return { type: TokenType.NUMBER, value, line: startLine, column: startCol };\n }\n}\nexport class Parser {\n constructor(tokens) {\n this.pos = 0;\n this.tokens = tokens.filter((t, i) => t.type !== TokenType.NEWLINE || this.isNextSignificant(tokens, i));\n }\n isNextSignificant(tokens, index) {\n // Only keep newlines if they are followed by something that isn't a newline or EOF\n for (let i = index + 1; i < tokens.length; i++) {\n if (tokens[i].type !== TokenType.NEWLINE) {\n return tokens[i].type !== TokenType.EOF;\n }\n }\n return false;\n }\n peek() {\n return this.tokens[this.pos] || { type: TokenType.EOF, value: '', line: -1, column: -1 };\n }\n advance() {\n return this.tokens[this.pos++];\n }\n match(type) {\n if (this.peek().type === type)\n return this.advance();\n return null;\n }\n parse() {\n const nodes = [];\n while (this.peek().type !== TokenType.EOF) {\n const node = this.parseStatement();\n if (node)\n nodes.push(node);\n // Consume optional newline\n while (this.match(TokenType.NEWLINE))\n ;\n }\n return nodes;\n }\n parseStatement() {\n const token = this.peek();\n if (token.type === TokenType.IDENTIFIER) {\n const next = this.tokens[this.pos + 1];\n // Label: IDENTIFIER:\n if (next && next.type === TokenType.COLON) {\n const label = this.advance();\n this.advance(); // consume :\n return { type: 'Label', name: label.value, line: label.line };\n }\n // Directive: IDENTIFIER EQU EXPR or EQU IDENTIFIER EXPR\n if (next && next.type === TokenType.DIRECTIVE) {\n const id = this.advance();\n const dir = this.advance();\n const expr = this.parseExpression();\n return { type: 'Directive', name: dir.value, identifier: id.value, expression: expr, line: dir.line };\n }\n }\n if (token.type === TokenType.DIRECTIVE) {\n const dir = this.advance();\n const id = this.match(TokenType.IDENTIFIER);\n if (!id)\n throw new ParserError(`Expected identifier after ${dir.value}`, dir.line, dir.column);\n const expr = this.parseExpression();\n return { type: 'Directive', name: dir.value, identifier: id.value, expression: expr, line: dir.line };\n }\n if (token.type === TokenType.IDENTIFIER) {\n const mnemonic = this.advance();\n const operands = [];\n if (this.peek().type !== TokenType.NEWLINE && this.peek().type !== TokenType.EOF) {\n operands.push(this.parseExpression());\n while (this.match(TokenType.COMMA)) {\n operands.push(this.parseExpression());\n }\n }\n return { type: 'Instruction', mnemonic: mnemonic.value, operands, line: mnemonic.line };\n }\n this.advance(); // Skip unknown\n return null;\n }\n parseExpression() {\n return this.parseBitwise();\n }\n parseBitwise() {\n let left = this.parseShift();\n while (this.peek().type === TokenType.OPERATOR && (['|', '&', '^'].includes(this.peek().value))) {\n const operator = this.advance().value;\n const right = this.parseShift();\n left = { type: 'Binary', left, operator, right };\n }\n return left;\n }\n parseShift() {\n let left = this.parseAdditive();\n while (this.peek().type === TokenType.OPERATOR && (['<', '>'].includes(this.peek().value))) {\n const operator = this.advance().value;\n const right = this.parseAdditive();\n left = { type: 'Binary', left, operator, right };\n }\n return left;\n }\n parseAdditive() {\n let left = this.parseMultiplicative();\n while (this.peek().type === TokenType.OPERATOR && (this.peek().value === '+' || this.peek().value === '-')) {\n const operator = this.advance().value;\n const right = this.parseMultiplicative();\n left = { type: 'Binary', left, operator, right };\n }\n return left;\n }\n parseMultiplicative() {\n let left = this.parsePrimary();\n while (this.peek().type === TokenType.OPERATOR && (this.peek().value === '*' || this.peek().value === '/')) {\n const operator = this.advance().value;\n const right = this.parsePrimary();\n left = { type: 'Binary', left, operator, right };\n }\n return left;\n }\n parsePrimary() {\n const token = this.peek();\n if (token.type === TokenType.NUMBER) {\n return { type: 'Number', value: this.parseNumberValue(this.advance().value) };\n }\n if (token.type === TokenType.IDENTIFIER) {\n return { type: 'Identifier', name: this.advance().value };\n }\n if (token.type === TokenType.LPAREN) {\n this.advance();\n const expr = this.parseExpression();\n if (!this.match(TokenType.RPAREN))\n throw new ParserError(`Expected )`, token.line, token.column);\n return expr;\n }\n if (token.type === TokenType.OPERATOR && (token.value === '-' || token.value === '+' || token.value === '!')) {\n const operator = this.advance().value;\n return { type: 'Unary', operator, expression: this.parsePrimary() };\n }\n throw new ParserError(`Unexpected token ${token.value}`, token.line, token.column);\n }\n parseNumberValue(val) {\n const upper = val.toUpperCase();\n if (upper.startsWith('$'))\n return parseInt(val.slice(1), 16);\n if (upper.startsWith('0X'))\n return parseInt(val, 16);\n if (upper.startsWith('%'))\n return parseInt(val.slice(1).replace(/_/g, ''), 2);\n return parseFloat(val);\n }\n}\n//# sourceMappingURL=FV1Parser.js.map","export const INSTRUCTION_SET = {\n // Accumulator\n 'SOF': {\n opcode: 0b01101, fields: [\n { name: 'coeff', bits: 16, offset: 16, type: 'S1_14' },\n { name: 'd', bits: 11, offset: 5, type: 'S_10' },\n { name: 'op', bits: 5, offset: 0, value: 0b01101 }\n ]\n },\n 'AND': {\n opcode: 0b01110, fields: [\n { name: 'mask', bits: 24, offset: 8, type: 'U' },\n { name: 'op', bits: 8, offset: 0, value: 0b01110 }\n ]\n },\n 'OR': {\n opcode: 0b01111, fields: [\n { name: 'mask', bits: 24, offset: 8, type: 'U' },\n { name: 'op', bits: 8, offset: 0, value: 0b01111 }\n ]\n },\n 'XOR': {\n opcode: 0b10000, fields: [\n { name: 'mask', bits: 24, offset: 8, type: 'U' },\n { name: 'op', bits: 8, offset: 0, value: 0b10000 }\n ]\n },\n 'LOG': {\n opcode: 0b01011, fields: [\n { name: 'coeff', bits: 16, offset: 16, type: 'S1_14' },\n { name: 'd', bits: 11, offset: 5, type: 'S4_6' },\n { name: 'op', bits: 5, offset: 0, value: 0b01011 }\n ]\n },\n 'EXP': {\n opcode: 0b01100, fields: [\n { name: 'coeff', bits: 16, offset: 16, type: 'S1_14' },\n { name: 'd', bits: 11, offset: 5, type: 'S_10' },\n { name: 'op', bits: 5, offset: 0, value: 0b01100 }\n ]\n },\n 'SKP': {\n opcode: 0b10001, fields: [\n { name: 'flags', bits: 5, offset: 27, type: 'LFO' }, // Special handling for flag bits\n { name: 'n', bits: 6, offset: 21, type: 'S' },\n { name: 'op', bits: 5, offset: 0, value: 0b10001 }\n ]\n },\n 'JMP': {\n opcode: 0b10001, fields: [\n { name: 'flags', bits: 5, offset: 27, value: 0 },\n { name: 'n', bits: 6, offset: 21, type: 'S' },\n { name: 'op', bits: 5, offset: 0, value: 0b10001 }\n ]\n },\n 'NOP': {\n opcode: 0b10001, fields: [\n { name: 'flags', bits: 5, offset: 27, value: 0 },\n { name: 'n', bits: 6, offset: 21, value: 0 },\n { name: 'op', bits: 5, offset: 0, value: 0b10001 }\n ]\n },\n // Register\n 'RDAX': {\n opcode: 0b00100, fields: [\n { name: 'addr', bits: 6, offset: 5, type: 'REG' },\n { name: 'coeff', bits: 16, offset: 16, type: 'S1_14' },\n { name: 'op', bits: 5, offset: 0, value: 0b00100 }\n ]\n },\n 'WRAX': {\n opcode: 0b00110, fields: [\n { name: 'addr', bits: 6, offset: 5, type: 'REG' },\n { name: 'coeff', bits: 16, offset: 16, type: 'S1_14' },\n { name: 'op', bits: 5, offset: 0, value: 0b00110 }\n ]\n },\n 'MAXX': {\n opcode: 0b01001, fields: [\n { name: 'addr', bits: 6, offset: 5, type: 'REG' },\n { name: 'coeff', bits: 16, offset: 16, type: 'S1_14' },\n { name: 'op', bits: 5, offset: 0, value: 0b01001 }\n ]\n },\n 'MULX': {\n opcode: 0b01010, fields: [\n { name: 'addr', bits: 6, offset: 5, type: 'REG' },\n { name: 'op', bits: 5, offset: 0, value: 0b01010 }\n ]\n },\n 'RDFX': {\n opcode: 0b00101, fields: [\n { name: 'addr', bits: 6, offset: 5, type: 'REG' },\n { name: 'coeff', bits: 16, offset: 16, type: 'S1_14' },\n { name: 'op', bits: 5, offset: 0, value: 0b00101 }\n ]\n },\n 'WRLX': {\n opcode: 0b01000, fields: [\n { name: 'addr', bits: 6, offset: 5, type: 'REG' },\n { name: 'coeff', bits: 16, offset: 16, type: 'S1_14' },\n { name: 'op', bits: 5, offset: 0, value: 0b01000 }\n ]\n },\n 'WRHX': {\n opcode: 0b00111, fields: [\n { name: 'addr', bits: 6, offset: 5, type: 'REG' },\n { name: 'coeff', bits: 16, offset: 16, type: 'S1_14' },\n { name: 'op', bits: 5, offset: 0, value: 0b00111 }\n ]\n },\n 'LDAX': {\n opcode: 0b00101, fields: [\n { name: 'coeff', bits: 16, offset: 16, value: 0 },\n { name: 'addr', bits: 6, offset: 5, type: 'REG' },\n { name: 'op', bits: 5, offset: 0, value: 0b00101 }\n ]\n },\n // Delay RAM\n 'RDA': {\n opcode: 0b00000, fields: [\n { name: 'addr', bits: 16, offset: 5, type: 'ADDR' },\n { name: 'coeff', bits: 11, offset: 21, type: 'S1_9' },\n { name: 'op', bits: 5, offset: 0, value: 0b00000 }\n ]\n },\n 'RMPA': {\n opcode: 0b00001, fields: [\n { name: 'coeff', bits: 11, offset: 21, type: 'S1_9' },\n { name: 'op', bits: 5, offset: 0, value: 0b00001 }\n ]\n },\n 'WRA': {\n opcode: 0b00010, fields: [\n { name: 'addr', bits: 16, offset: 5, type: 'ADDR' },\n { name: 'coeff', bits: 11, offset: 21, type: 'S1_9' },\n { name: 'op', bits: 5, offset: 0, value: 0b00010 }\n ]\n },\n 'WRAP': {\n opcode: 0b00011, fields: [\n { name: 'addr', bits: 16, offset: 5, type: 'ADDR' },\n { name: 'coeff', bits: 11, offset: 21, type: 'S1_9' },\n { name: 'op', bits: 5, offset: 0, value: 0b00011 }\n ]\n },\n // LFO/CHO\n 'WLDS': {\n opcode: 0b10010, fields: [\n { name: 'sinLfo', bits: 1, offset: 29, type: 'U' }, // N\n { name: 'freq', bits: 9, offset: 20, type: 'U' }, // F\n { name: 'ampl', bits: 15, offset: 5, type: 'U' }, // A\n { name: 'op', bits: 5, offset: 0, value: 0b10010 }\n ]\n },\n 'WLDR': {\n opcode: 0b10010, fields: [\n { name: 'type', bits: 1, offset: 30, value: 1 }, // Always 1 for WLDR\n { name: 'rmpLfo', bits: 1, offset: 29, type: 'U' }, // N\n { name: 'freq', bits: 16, offset: 13, type: 'U' }, // F (signed 16-bit)\n { name: 'ampl', bits: 2, offset: 5, type: 'U' }, // A (backward encoding handled in assembler)\n { name: 'op', bits: 5, offset: 0, value: 0b10010 }\n ]\n },\n 'JAM': {\n opcode: 0b10011, fields: [\n { name: 'rmpLfo', bits: 1, offset: 6, type: 'U' },\n { name: 'type', bits: 1, offset: 7, value: 1 },\n { name: 'op', bits: 5, offset: 0, value: 0b10011 }\n ]\n },\n 'CHO': {\n opcode: 0b10100, fields: [\n { name: 'mode', bits: 2, offset: 30, type: 'U' },\n { name: 'flags', bits: 6, offset: 24, type: 'U' },\n { name: 'n', bits: 3, offset: 21, type: 'U' },\n { name: 'param', bits: 16, offset: 5, type: 'ADDR' }, // Can be addr or coeff\n { name: 'op', bits: 5, offset: 0, value: 0b10100 }\n ]\n },\n // Pseudo-ops\n 'CLR': { opcode: 0b01110, fields: [{ name: 'val', bits: 32, offset: 0, value: 0b01110 }] },\n 'NOT': { opcode: 0b10000, fields: [{ name: 'val', bits: 32, offset: 0, value: 0b10000 }] },\n 'ABSA': { opcode: 0b01001, fields: [{ name: 'val', bits: 32, offset: 0, value: 0b01001 }] },\n};\nexport class Encoder {\n static encode(format, value) {\n switch (format) {\n case 'S1_14': return this.toFixedPoint(value, 1, 14, 2.0);\n case 'S_15': return this.toFixedPoint(value, 0, 15, 1.0);\n case 'S1_9': return this.toFixedPoint(value, 1, 9, 2.0);\n case 'S_10': return this.toFixedPoint(value, 0, 10, 1.0);\n case 'S4_6': return this.toFixedPoint(value, 4, 6, 16.0);\n }\n return value;\n }\n static toFixedPoint(value, intBits, fracBits, maxValue) {\n const lsb = maxValue / (1 << fracBits);\n const min = -maxValue;\n const max = maxValue - lsb;\n let num = Math.min(Math.max(value, min), max);\n let encoded = Math.trunc(num * (1 << fracBits));\n const totalBits = 1 + intBits + fracBits;\n const mask = (1 << totalBits) - 1;\n return (encoded < 0) ? (encoded + (1 << totalBits)) & mask : encoded & mask;\n }\n static assembleInstruction(mnemonic, operands, schema) {\n let result = 0;\n let operandIdx = 0;\n for (const field of schema.fields) {\n let val = 0;\n if (field.value !== undefined) {\n val = field.value;\n }\n else {\n val = operands[operandIdx++];\n if (field.type)\n val = this.encode(field.type, val);\n }\n const mask = field.bits === 32 ? 0xFFFFFFFF : (1 << field.bits) - 1;\n result |= (val & mask) << field.offset;\n }\n return result >>> 0;\n }\n}\n//# sourceMappingURL=FV1Encoder.js.map","import { Lexer, Parser, ParserError } from './FV1Parser.js';\nimport { INSTRUCTION_SET, Encoder } from './FV1Encoder.js';\nexport class FV1Assembler {\n constructor(options = {}) {\n this.problems = [];\n this.symbols = new Map();\n this.memories = [];\n this.labels = new Map();\n this.addressToLineMap = new Map();\n this.usedRegisters = new Set();\n this.usedLFOs = new Set();\n this.configuredLFOs = new Set();\n this.userSymbols = new Set();\n this.symbolLines = new Map();\n this.PREDEFINED_SYMBOLS = {\n 'SIN0_RATE': 0x00, 'SIN0_RANGE': 0x01, 'SIN1_RATE': 0x02, 'SIN1_RANGE': 0x03,\n 'RMP0_RATE': 0x04, 'RMP0_RANGE': 0x05, 'RMP1_RATE': 0x06, 'RMP1_RANGE': 0x07,\n 'POT0': 0x10, 'POT1': 0x11, 'POT2': 0x12, 'ADCL': 0x14, 'ADCR': 0x15,\n 'DACL': 0x16, 'DACR': 0x17, 'ADDR_PTR': 0x18,\n 'SIN0': 0x00, 'SIN1': 0x01, 'RMP0': 0x02, 'RMP1': 0x03,\n 'COS0': 0x08, 'COS1': 0x09,\n 'RDA': 0x00, 'SOF': 0x02, 'RDAL': 0x03,\n 'SIN': 0x00, 'COS': 0x01, 'REG': 0x02, 'COMPC': 0x04,\n 'COMPA': 0x08, 'RPTR2': 0x10, 'NA': 0x20,\n 'RUN': 0x10, 'ZRC': 0x08, 'ZRO': 0x04,\n 'GEZ': 0x02, 'NEG': 0x01\n };\n this.reservedSymbols = new Set();\n this.options = {\n fv1AsmMemBug: options.fv1AsmMemBug ?? true,\n clampReals: options.clampReals ?? true,\n regCount: options.regCount ?? 32,\n progSize: options.progSize ?? 128,\n delaySize: options.delaySize ?? 32768\n };\n this.reset();\n }\n reset() {\n this.problems = [];\n this.symbols.clear();\n this.memories = [];\n this.labels.clear();\n this.addressToLineMap.clear();\n this.usedRegisters.clear();\n this.usedLFOs.clear();\n this.configuredLFOs.clear();\n this.userSymbols.clear();\n this.symbolLines.clear(); // Added this line\n this.initSymbols(); // Added this line\n }\n initSymbols() {\n // Load predefined symbols\n for (const [key, val] of Object.entries(this.PREDEFINED_SYMBOLS)) {\n this.symbols.set(key, val);\n this.reservedSymbols.add(key);\n }\n // Load REG0-31\n for (let i = 0; i < this.options.regCount; i++) {\n this.symbols.set(`REG${i}`, 0x20 + i);\n this.reservedSymbols.add(`REG${i}`);\n }\n }\n assemble(source) {\n this.reset();\n try {\n const lexer = new Lexer(source);\n const tokens = lexer.tokenize();\n const parser = new Parser(tokens);\n const ast = parser.parse();\n this.pass1_ResolveDirectives(ast);\n this.pass2_ResolveLabels(ast);\n const machineCode = this.pass3_GenerateCode(ast);\n return {\n machineCode,\n problems: this.problems,\n labels: this.labels,\n symbols: Array.from(this.symbols.entries())\n .filter(([name]) => this.userSymbols.has(name))\n .map(([name, value]) => ({ name, value: value.toString(), line: this.symbolLines.get(name) })),\n memories: this.memories,\n addressToLineMap: this.addressToLineMap,\n usedRegistersCount: this.usedRegisters.size,\n usedLFOs: Array.from(this.usedLFOs)\n };\n }\n catch (e) {\n const line = (e instanceof ParserError) ? e.line : 1;\n this.problems.push({ message: `Parser error: ${e instanceof Error ? e.message : String(e)}`, isfatal: true, line });\n return {\n machineCode: [],\n problems: this.problems,\n labels: new Map(),\n symbols: [],\n memories: [],\n addressToLineMap: new Map(),\n usedRegistersCount: 0,\n usedLFOs: []\n };\n }\n }\n pass1_ResolveDirectives(ast) {\n let nextDelayAddr = 0;\n for (const node of ast) {\n if (node.type === 'Directive') {\n if (node.name === 'EQU') {\n if (this.reservedSymbols.has(node.identifier)) {\n this.problems.push({ message: `Cannot redefine reserved symbol '${node.identifier}'`, isfatal: true, line: node.line });\n }\n else if (this.userSymbols.has(node.identifier)) {\n this.problems.push({ message: `Symbol '${node.identifier}' is already defined on line ${this.symbolLines.get(node.identifier)}`, isfatal: true, line: node.line });\n }\n else {\n const value = this.evaluateExpression(node.expression, node.line);\n this.symbols.set(node.identifier, value);\n this.userSymbols.add(node.identifier);\n this.symbolLines.set(node.identifier, node.line);\n }\n }\n else if (node.name === 'MEM') {\n if (this.reservedSymbols.has(node.identifier)) {\n this.problems.push({ message: `Cannot redefine reserved symbol '${node.identifier}'`, isfatal: true, line: node.line });\n continue;\n }\n const size = this.evaluateExpression(node.expression, node.line);\n const start = nextDelayAddr;\n const middle = start + (size % 2 ? (size - 1) / 2 - 1 : size / 2);\n const end = start + size - 1;\n const buggyEnd = end + (this.options.fv1AsmMemBug ? 1 : 0);\n const mem = { name: node.identifier, size, start, middle, end, line: node.line, original: '' };\n this.memories.push(mem);\n // Register special suffixes\n this.symbols.set(node.identifier, start);\n this.symbols.set(node.identifier + '^', middle);\n this.symbols.set(node.identifier + '#', buggyEnd);\n nextDelayAddr = buggyEnd + 1;\n }\n }\n }\n }\n pass2_ResolveLabels(ast) {\n let pc = 0;\n for (const node of ast) {\n if (node.type === 'Label') {\n this.labels.set(node.name, { line: node.line, instructionLine: pc });\n }\n else if (node.type === 'Instruction') {\n pc++;\n }\n }\n }\n pass3_GenerateCode(ast) {\n const code = [];\n let pc = 0;\n for (const node of ast) {\n if (node.type === 'Instruction') {\n const schema = INSTRUCTION_SET[node.mnemonic];\n if (!schema) {\n this.problems.push({ message: `Unknown instruction ${node.mnemonic}`, isfatal: true, line: node.line });\n code.push(0);\n continue;\n }\n let operands = node.operands.map(op => {\n // Special case for labels in JMP/SKP\n if (op.type === 'Identifier' && this.labels.has(op.name)) {\n return this.labels.get(op.name).instructionLine - pc - 1;\n }\n return this.evaluateExpression(op, node.line);\n });\n // --- Specialized Encoding Logic ---\n // LFO Tracking for configurations\n if (node.mnemonic === 'WLDS' || node.mnemonic === 'WLDR') {\n const lfoReg = operands[0];\n const lfoName = this.getLFOName(lfoReg);\n if (lfoName) {\n if (node.mnemonic === 'WLDS') {\n if (this.configuredLFOs.has(lfoName)) {\n this.problems.push({ message: `LFO ${lfoName} is configured more than once`, isfatal: true, line: node.line });\n }\n this.configuredLFOs.add(lfoName);\n }\n this.usedLFOs.add(lfoName);\n }\n }\n if (node.mnemonic === 'CHO') {\n const mode = operands[0];\n const n = operands[1];\n const rdaMode = this.symbols.get('RDA');\n const sofMode = this.symbols.get('SOF');\n const rdalMode = this.symbols.get('RDAL');\n if (mode === rdalMode) {\n // CHO RDAL, N -> [mode, flags=0x02(fixed bit 25), n, param=0]\n operands = [mode, 0x02, n, 0];\n }\n else if (mode === rdaMode || mode === sofMode) {\n const flags = operands[2];\n let param = operands[3];\n if (mode === sofMode) {\n param = Encoder.encode('S1_14', param);\n }\n operands = [mode, flags, n, param];\n }\n }\n else if (node.mnemonic === 'WLDR') {\n // Match previous backwards-encoded amplitude\n let ampl = operands[2];\n switch (ampl) {\n case 512:\n ampl = 3;\n break;\n case 1024:\n ampl = 2;\n break;\n case 2048:\n ampl = 1;\n break;\n case 4096:\n ampl = 0;\n break;\n default:\n this.problems.push({ message: `Invalid amplitude ${ampl} for WLDR`, isfatal: true, line: node.line });\n }\n // Handle RMP LFO mapping\n let rmpLfo = operands[0];\n if ([0, 2].includes(rmpLfo))\n rmpLfo = 0;\n else if ([1, 3].includes(rmpLfo))\n rmpLfo = 1;\n operands = [rmpLfo, operands[1], ampl];\n }\n else if (node.mnemonic === 'JAM') {\n let rmpLfo = operands[0];\n if ([0, 2].includes(rmpLfo))\n rmpLfo = 0;\n else if ([1, 3].includes(rmpLfo))\n rmpLfo = 1;\n operands = [rmpLfo];\n }\n // Track register usage\n schema.fields.forEach((field, i) => {\n if (field.type === 'REG' && operands[i] !== undefined) {\n this.trackRegister(operands[i], node.line);\n }\n });\n // Additional LFO tracking for register writes to RATE/RANGE\n if (node.mnemonic === 'WRAX' || node.mnemonic === 'RDAX') {\n const regNum = operands[0];\n const lfoName = this.getLFONameFromRegister(regNum);\n if (lfoName) {\n this.usedLFOs.add(lfoName);\n }\n }\n code.push(Encoder.assembleInstruction(node.mnemonic, operands, schema));\n this.addressToLineMap.set(pc, node.line);\n pc++;\n }\n }\n // Pad to progSize\n while (code.length < this.options.progSize)\n code.push(0x00000011); // NOP\n return code;\n }\n trackRegister(addr, line) {\n if (addr >= 0x20 && addr <= 0x3F) {\n const regNum = addr - 0x20;\n if (regNum >= this.options.regCount) {\n this.problems.push({ message: `Register REG${regNum} exceeds limit ${this.options.regCount}`, isfatal: true, line });\n }\n this.usedRegisters.add(regNum);\n }\n }\n getLFOName(lfoId) {\n switch (lfoId) {\n case 0: return 'SIN0';\n case 1: return 'SIN1';\n case 2: return 'RMP0';\n case 3: return 'RMP1';\n default: return null;\n }\n }\n getLFONameFromRegister(addr) {\n // 0x00=SIN0_RATE, 0x01=SIN0_RANGE, 0x02=SIN1_RATE, 0x03=SIN1_RANGE\n // 0x04=RMP0_RATE, 0x05=RMP0_RANGE, 0x06=RMP1_RATE, 0x07=RMP1_RANGE\n switch (addr) {\n case 0x00:\n case 0x01: return 'SIN0';\n case 0x02:\n case 0x03: return 'SIN1';\n case 0x04:\n case 0x05: return 'RMP0';\n case 0x06:\n case 0x07: return 'RMP1';\n default: return null;\n }\n }\n evaluateExpression(expr, line) {\n switch (expr.type) {\n case 'Number': return expr.value;\n case 'Identifier':\n if (this.symbols.has(expr.name))\n return this.symbols.get(expr.name);\n this.problems.push({ message: `Undefined symbol ${expr.name}`, isfatal: true, line });\n return 0;\n case 'Binary':\n const left = this.evaluateExpression(expr.left, line);\n const right = this.evaluateExpression(expr.right, line);\n switch (expr.operator) {\n case '+': return left + right;\n case '-': return left - right;\n case '*': return left * right;\n case '/': return left / right;\n case '|': return left | right;\n case '&': return left & right;\n case '^': return left ^ right;\n case '<': return (left << right) >>> 0;\n case '>': return (left >>> right);\n default: return 0;\n }\n case 'Unary':\n const val = this.evaluateExpression(expr.expression, line);\n if (expr.operator === '-')\n return -val;\n if (expr.operator === '!')\n return (~Math.floor(val)) >>> 0;\n return val;\n }\n }\n static formatMachineCode(machineCode) {\n return machineCode.map((word, index) => `${index.toString().padStart(4, '0')}\\t${word.toString(16).toUpperCase().padStart(8, '0')}`).join('\\n');\n }\n static toUint8Array(machineCode) {\n const buffer = new ArrayBuffer(machineCode.length * 4);\n const view = new DataView(buffer);\n machineCode.forEach((val, i) => view.setUint32(i * 4, val, false));\n return new Uint8Array(buffer);\n }\n static getMiddleAddr(start, size) {\n return start + (size % 2 ? (size - 1) / 2 - 1 : size / 2);\n }\n static getEndAddr(start, size, fv1AsmMemBug) {\n return start + size - 1 + (fv1AsmMemBug ? 1 : 0);\n }\n}\n//# sourceMappingURL=FV1Assembler.js.map","/**\n * FV-1 DSP Simulator\n *\n * Simulates the Spin Semiconductor FV-1 DSP chip.\n * This class is designed to be platform-agnostic (Node.js or Browser/AudioWorklet).\n */\nimport { FV1Assembler } from '../assembler/FV1Assembler.js';\nexport class FV1Simulator {\n // Register aliases (Getters/Setters)\n // 0-7: Parameters\n // These are now handled by updateStateRegisters for debugger view\n // 8-13: Internal State accumulators (aliased as registers for the debugger)\n // These are now handled by updateStateRegisters for debugger view\n constructor() {\n // Constants\n // Capabilities (Configurable)\n this.delaySize = 32768;\n this.delayMask = 32767; // For efficient circular buffer\n this.regCount = 32;\n this.progSize = 128;\n // --- Float-based LFO state (from Expert Sleepers C port) ---\n this.sin0 = 0;\n this.cos0 = 0;\n this.sin1 = 0;\n this.cos1 = 0;\n this.rmp0 = 0;\n this.rmp1 = 0;\n this.sin0_rate = 0;\n this.sin0_range = 0;\n this.sin1_rate = 0;\n this.sin1_range = 0;\n this.rmp0_rate = 0;\n this.rmp0_range = 0;\n this.rmp1_rate = 0;\n this.rmp1_range = 0;\n this.acc = 0;\n this.pacc = 0;\n this.lr = 0; // Last Read register\n this.lfo = 0; // Internal LFO fregister (for CHO)\n this.delayPointer = 0; // Circular buffer pointer\n this.firstRun = true;\n this.pc = 0; // Program Counter\n this.breakpoints = new Set();\n // Symbol metadata (optional, for debugging)\n this.symbols = [];\n this.memories = [];\n this.fv1AsmMemBug = false;\n // --- Trace Logging ---\n this.traceEnabled = false;\n this.traceWriter = null; // Streaming callback\n this.cycleCount = 0;\n this.traceCycle = 0;\n this.traceMaxCycles = 0; // 0 = unlimited\n this.traceRowCount = 0;\n this.traceDelayAddr = -1; // computed physical address in delay RAM\n this.traceDelayOffset = -1; // raw offset from instruction (identifies MEM block)\n this.traceDelayOp = ''; // 'R' for read, 'W' for write\n this.traceDelayValue = 0; // value read/written\n this.traceInstructionPC = -1; // PC of currently executing instruction\n this.currentReadOffsets = new Set(); // Tracks read offsets in current sample cycle\n this.traceOnComplete = null;\n this.delayRam = new Float32Array(this.delaySize);\n this.registers = new Float32Array(32 + this.regCount);\n this.program = new Uint32Array(this.progSize);\n }\n /**\n * Configures simulator hardware limits.\n */\n setCapabilities(delaySize, regCount, progSize) {\n this.delaySize = delaySize;\n this.delayMask = delaySize - 1; // Assuming power of 2 for now, but modulo is fallback\n this.regCount = regCount; // Number of user registers\n this.progSize = progSize;\n // Reallocate if needed\n this.delayRam = new Float32Array(this.delaySize);\n this.registers = new Float32Array(32 + this.regCount); // 32 system + N user registers\n this.program = new Uint32Array(this.progSize);\n this.reset();\n }\n getDelayPointer() {\n return this.delayPointer;\n }\n getDelaySize() {\n return this.delaySize;\n }\n /**\n * Loads the machine code into the simulator.\n * @param code Array of 32-bit integers representing the assembled program.\n */\n loadProgram(code) {\n if (code.length > this.progSize) {\n console.warn(`Program size (${code.length}) exceeds max size (${this.progSize}). Truncating.`);\n }\n this.program.fill(0);\n this.program.set(code.slice(0, this.progSize));\n this.reset();\n }\n /**\n * Resets the simulator state (clears memory, registers, accumulator).\n */\n reset() {\n this.delayRam.fill(0);\n this.registers.fill(0);\n this.acc = 0;\n this.pacc = 0;\n this.lr = 0;\n this.lfo = 0;\n this.pc = 0;\n this.delayPointer = 0;\n this.firstRun = true;\n this.sin0 = 0;\n this.sin1 = 0;\n // Peak amplitude from Java SinLFO.java initialized to -0x7fff00 mapped to float (-1.0)\n // BUT wait, in C the initialization is not explicit, we can just use 1.0 or -1.0\n // SpinCAD sets cos to -0x7fff00l which is approx -1.0\n this.cos0 = -1.0;\n this.cos1 = -1.0;\n this.rmp0 = 0;\n this.rmp1 = 0;\n this.sin0_rate = 0;\n this.sin0_range = 0;\n this.sin1_rate = 0;\n this.sin1_range = 0;\n this.rmp0_rate = 0;\n this.rmp0_range = 0;\n this.rmp1_rate = 0;\n this.rmp1_range = 0;\n // Default POT values to 0.5\n this.registers[16] = 0.5;\n this.registers[17] = 0.5;\n this.registers[18] = 0.5;\n }\n /**\n * Set breakpoints at specific instruction addresses.\n * @param addresses Set of addresses to break at.\n */\n setBreakpoints(addresses) {\n this.breakpoints = addresses;\n }\n /**\n * Set symbol and memory metadata for expression evaluation.\n */\n setSymbols(symbols, memories, fv1AsmMemBug = false) {\n this.symbols = symbols;\n this.memories = memories;\n this.fv1AsmMemBug = fv1AsmMemBug;\n }\n /**\n * Process a block of audio samples.\n * Useful for real-time audio processing in AudioWorklets.\n */\n processBlock(inputL, inputR, outputL, outputR, pot0, pot1, pot2) {\n const len = inputL.length;\n for (let i = 0; i < len; i++) {\n const [outL, outR] = this.step(inputL[i], inputR[i], pot0, pot1, pot2);\n outputL[i] = outL;\n outputR[i] = outR;\n }\n }\n /**\n * Process a single sample frame.\n * Executes instructions until the end of the program or a breakpoint is hit.\n * @param skipCurrentBreakpoint If true, will not break on the instruction at the current PC.\n * @returns [outL, outR, breakpointHit]\n */\n step(inL, inR, pot0, pot1, pot2, skipCurrentBreakpoint = false) {\n // Only begin a new frame if we are at PC 0 (either start or after wrap around)\n if (this.pc === 0) {\n this.beginFrame(inL, inR, pot0, pot1, pot2);\n }\n let firstInstruction = true;\n while (this.pc < this.progSize) {\n if (this.breakpoints.has(this.pc)) {\n if (!firstInstruction || !skipCurrentBreakpoint) {\n return [...this.getOutputs(), true];\n }\n }\n this.stepInstruction();\n firstInstruction = false;\n }\n return [...this.endFrame(), false];\n }\n getOutputs() {\n return [this.registers[22], this.registers[23]];\n }\n beginFrame(inL = 0, inR = 0, pot0 = 0, pot1 = 0, pot2 = 0) {\n this.cycleCount++;\n this.currentReadOffsets.clear();\n // Saturate inputs (ADC is -1.0 to 0.999..., POT is 0 to 0.999...)\n // POT has 10-bit resolution (1024 levels)\n const sat = (v) => Math.max(-1.0, Math.min(FV1Simulator.MAX_ACC, v));\n const satPot = (v) => {\n const quantized = Math.floor(Math.max(0, Math.min(0.9999999, v)) * 1024) / 1024;\n return quantized;\n };\n // Execute Program Setup\n this.acc = 0; // Accumulator is cleared at start of run\n this.lr = 0; // LR is transient\n this.pacc = 0;\n this.pc = 0;\n // Map inputs to registers (Standard FV-1 mapping)\n this.registers[20] = sat(inL);\n this.registers[21] = sat(inR);\n this.registers[16] = satPot(pot0);\n this.registers[17] = satPot(pot1);\n this.registers[18] = satPot(pot2);\n this.updateStateRegisters();\n }\n endFrame() {\n this.pc = 0;\n this.firstRun = false;\n this.updateLFOs();\n this.updateStateRegisters();\n this.advanceTraceCycle();\n // Advance Delay Pointer (Circular Buffer)\n this.delayPointer = (this.delayPointer - 1 + this.delaySize) % this.delaySize;\n // Outputs (DACL = REG22, DACR = REG23)\n return [this.registers[22], this.registers[23]];\n }\n /**\n * Executes a single instruction at the current PC.\n * @returns The next PC address.\n */\n stepInstruction() {\n if (this.pc >= this.progSize)\n return this.pc;\n const inst = this.program[this.pc];\n const opcode = inst & 0x1F;\n const preOpAcc = this.acc;\n // Reset per-instruction trace state\n this.traceDelayAddr = -1;\n this.traceDelayOffset = -1;\n this.traceDelayOp = '';\n this.traceDelayValue = 0;\n this.traceInstructionPC = this.pc;\n const skip = this.executeInstruction(inst);\n // Trace log AFTER instruction executes so ACC reflects the result\n if (this.traceEnabled) {\n this.logTrace(this.traceInstructionPC, opcode, inst, preOpAcc);\n }\n if (opcode !== 0x11) { // Not SKP\n this.pacc = preOpAcc;\n }\n this.pc += 1 + skip;\n return this.pc;\n }\n executeInstruction(inst) {\n const opcode = inst & 0x1F; // Bottom 5 bits for opcode\n let skip = 0;\n switch (opcode) {\n case 0x00: // RDA (Read Delay Accumulate)\n this.opRDA(inst);\n break;\n case 0x01: // RMPA (Read Memory Pointer Accumulate)\n this.opRMPA(inst);\n break;\n case 0x02: // WRA (Write Delay Accumulate)\n this.opWRA(inst);\n break;\n case 0x03: // WRAP (Write Delay Accumulate & Pointer)\n this.opWRAP(inst);\n break;\n case 0x04: // RDAX (Read Register Accumulate)\n this.opRDAX(inst);\n break;\n case 0x05: // RDFX (Read Register Filter)\n this.opRDFX(inst);\n break;\n case 0x06: // WRAX (Write Register Accumulate)\n this.opWRAX(inst);\n break;\n case 0x07: // WRHX (Write Register High)\n this.opWRHX(inst);\n break;\n case 0x08: // WRLX (Write Register Low)\n this.opWRLX(inst);\n break;\n case 0x09: // MAXX\n this.opMAXX(inst);\n break;\n case 0x0A: // MULX\n this.opMULX(inst);\n break;\n case 0x0B: // LOG\n this.opLOG(inst);\n break;\n case 0x0C: // EXP\n this.opEXP(inst);\n break;\n case 0x0D: // SOF\n this.opSOF(inst);\n break;\n case 0x0E: // AND\n this.opAND(inst);\n break;\n case 0x0F: // OR\n this.opOR(inst);\n break;\n case 0x10: // XOR\n this.opXOR(inst);\n break;\n case 0x11: // SKP\n skip = this.opSKP(inst);\n break;\n case 0x12: // WLDS / WLDR\n // Check bit 30 to distinguish WLDS (0) and WLDR (1)\n if ((inst >>> 30) & 1) {\n this.opWLDR(inst);\n }\n else {\n this.opWLDS(inst);\n }\n break;\n case 0x13: // JAM\n this.opJAM(inst);\n break;\n case 0x14: // CHO\n this.opCHO(inst);\n break;\n default:\n // console.warn(`Unknown opcode: ${opcode.toString(16)}`);\n break;\n }\n return skip;\n }\n // --- Opcode Implementations ---\n opRDA(inst) {\n // ... (existing comments)\n const addr = (inst >>> 5) & 0x7FFF;\n const coeff = this.decodeS1_9((inst >>> 21) & 0x7FF);\n // Address is relative to current delay pointer in circular buffer\n const readAddr = (this.delayPointer + addr) & this.delayMask;\n const val = this.delayRam[readAddr];\n this.traceDelayAddr = readAddr;\n this.traceDelayOffset = addr;\n this.traceDelayOp = 'R';\n this.traceDelayValue = val;\n this.currentReadOffsets.add(addr);\n this.lr = val;\n this.acc += val * coeff;\n this.acc = this.saturate(this.acc);\n }\n opWRA(inst) {\n // WRA addr, coeff\n // Delay[addr] = ACC; ACC = ACC * coeff\n // Encoding: CCCCCCCCCCCAAAAAAAAAAAAAAAA00010\n const addr = (inst >>> 5) & 0x7FFF;\n const coeff = this.decodeS1_9((inst >>> 21) & 0x7FF);\n const writeAddr = (this.delayPointer + addr) & this.delayMask;\n this.traceDelayAddr = writeAddr;\n this.traceDelayOffset = addr;\n this.traceDelayOp = 'W';\n this.traceDelayValue = this.acc;\n this.delayRam[writeAddr] = this.acc;\n this.acc *= coeff;\n this.acc = this.saturate(this.acc);\n }\n opWRAP(inst) {\n // WRAP addr, coeff\n // Delay[addr] = ACC; ACC = ACC * coeff + LR\n // Note: Pointer decrement happens at end of step, not here.\n // Encoding: CCCCCCCCCCCAAAAAAAAAAAAAAAA00011\n const addr = (inst >>> 5) & 0x7FFF;\n const coeff = this.decodeS1_9((inst >>> 21) & 0x7FF);\n const writeAddr = (this.delayPointer + addr) & this.delayMask;\n this.traceDelayAddr = writeAddr;\n this.traceDelayOffset = addr;\n this.traceDelayOp = 'W';\n this.traceDelayValue = this.acc;\n this.delayRam[writeAddr] = this.acc;\n // ACC = ACC * coeff + LR\n this.acc = this.acc * coeff + this.lr;\n this.acc = this.saturate(this.acc);\n }\n opRDAX(inst) {\n // RDAX reg, coeff\n // ACC = ACC + (Reg[reg] * coeff)\n // Encoding: CCCCCCCCCCCCCCCC00000AAAAAA00100\n const reg = (inst >>> 5) & 0x3F;\n const coeff = this.decodeS1_14((inst >>> 16) & 0xFFFF);\n const val = this.registers[reg];\n this.acc += val * coeff;\n this.acc = this.saturate(this.acc);\n }\n opWRAX(inst) {\n // WRAX reg, coeff\n // Reg[reg] = ACC; ACC = ACC * coeff\n // Encoding: CCCCCCCCCCCCCCCC00000AAAAAA00110\n const reg = (inst >>> 5) & 0x3F;\n const coeff = this.decodeS1_14((inst >>> 16) & 0xFFFF);\n this.registers[reg] = this.acc;\n this.acc *= coeff;\n this.acc = this.saturate(this.acc);\n }\n opSOF(inst) {\n // SOF c, d\n // ACC = ACC * c + d\n // Encoding: CCCCCCCCCCCCCCCCDDDDDDDDDDD01101\n const d = this.decodeS_10((inst >>> 5) & 0x7FF);\n const c = this.decodeS1_14((inst >>> 16) & 0xFFFF);\n this.acc = this.acc * c + d;\n this.acc = this.saturate(this.acc);\n }\n opRMPA(inst) {\n // RMPA coeff\n // Read memory pointer. ADDR_PTR is mapped to REG24.\n // Encoding: CCCCCCCCCCC000000000001100000001 (or similar, coeff is top)\n const coeff = this.decodeS1_9((inst >>> 21) & 0x7FF);\n // Hardware truncates toward zero when converting the S.23 ADDR_PTR\n // to an integer offset. Math.floor would round tiny negative values\n // (~1e-20) to -1 and produce a parasitic read at delayPointer - 1,\n // which on this FV-1 architecture coincides with the chorus block's\n // simple_audio_output write from ~67 ms ago — creating a near-unity-\n // gain loop that takes hundreds of seconds to decay.\n const ptr = Math.trunc(this.registers[24] * this.delaySize);\n const readAddr = (this.delayPointer + ptr) & this.delayMask;\n const val = this.delayRam[readAddr];\n this.traceDelayAddr = readAddr;\n this.traceDelayOffset = ptr;\n this.traceDelayOp = 'R';\n this.traceDelayValue = val;\n this.currentReadOffsets.add(ptr);\n this.lr = val;\n this.acc += val * coeff;\n this.acc = this.saturate(this.acc);\n }\n opMULX(inst) {\n // Encoding: 000000000000000000000AAAAAA01010\n const reg = (inst >>> 5) & 0x3F;\n this.acc = this.acc * this.registers[reg];\n this.acc = this.saturate(this.acc);\n }\n opLOG(inst) {\n // ACC = log2(|ACC|) * coeff + d\n // Encoding: CCCCCCCCCCCCCCCCDDDDDDDDDDD01011\n const d = this.decodeS4_6((inst >>> 5) & 0x7FF);\n const coeff = this.decodeS1_14((inst >>> 16) & 0xFFFF);\n const val = Math.abs(this.acc);\n let logVal;\n if (val > 1.52587890625e-5) { // 2^-16, approx 96dB limit\n logVal = Math.log2(val);\n }\n else {\n logVal = -16.0;\n }\n // Result is in S4.19 format, so we divide by 16 to keep it in our S.23 float space\n this.acc = (logVal * coeff + d) / 16.0;\n this.acc = this.saturate(this.acc);\n }\n opEXP(inst) {\n // ACC = 2^ACC\n // Encoding: CCCCCCCCCCCCCCCCDDDDDDDDDDD01100\n const d = this.decodeS_10((inst >>> 5) & 0x7FF);\n const coeff = this.decodeS1_14((inst >>> 16) & 0xFFFF);\n const valS419 = this.acc * 16.0;\n // Result is linear S.23, which naturally fits our -1..1 float range\n this.acc = Math.pow(2, valS419) * coeff + d;\n this.acc = this.saturate(this.acc);\n }\n opRDFX(inst) {\n // RDFX reg, coeff\n // ACC = (REG[reg] - ACC) * coeff + REG[reg]\n // Encoding: CCCCCCCCCCCCCCCC00000AAAAAA00101\n const reg = (inst >>> 5) & 0x3F;\n const coeff = this.decodeS1_14((inst >>> 16) & 0xFFFF);\n const rx = this.registers[reg];\n this.acc = (this.acc - rx) * coeff + rx;\n this.acc = this.saturate(this.acc);\n }\n opMAXX(inst) {\n // Encoding: CCCCCCCCCCCCCCCC00000AAAAAA01001\n const reg = (inst >>> 5) & 0x3F;\n const coeff = this.decodeS1_14((inst >>> 16) & 0xFFFF);\n const a = Math.abs(this.acc);\n const b = Math.abs(this.registers[reg] * coeff);\n // MAXX result is always the magnitude (absolute value)\n this.acc = Math.max(a, b);\n this.acc = this.saturate(this.acc);\n }\n opSKP(inst) {\n // SKP condition, n\n // Encoding: CCCCCNNNNNN000000000000000010001\n const n = (inst >>> 21) & 0x3F;\n const flags = inst & 0xF8000000;\n let conditionMet = false;\n // Flags: RUN=0x80000000, ZRC=0x40000000, ZRO=0x20000000, GEZ=0x10000000, NEG=0x08000000\n if ((flags & 0x08000000) && this.acc < 0)\n conditionMet = true; // NEG\n if ((flags & 0x10000000) && this.acc >= 0)\n conditionMet = true; // GEZ\n if ((flags & 0x20000000) && this.acc === 0)\n conditionMet = true; // ZRO\n // ZRC (Zero Crossing) requires previous acc\n if ((flags & 0x40000000) && (this.acc * this.pacc < 0))\n conditionMet = true;\n // RUN flag: Skip if NOT first run\n if ((flags & 0x80000000) && !this.firstRun)\n conditionMet = true;\n return conditionMet ? n : 0;\n }\n opWRLX(inst) {\n // WRLX reg, coeff\n // Reg[reg] = ACC; ACC = (PACC - ACC) * coeff + PACC\n // Encoding: CCCCCCCCCCCCCCCC00000AAAAAA01000\n const reg = (inst >>> 5) & 0x3F;\n const coeff = this.decodeS1_14((inst >>> 16) & 0xFFFF);\n this.registers[reg] = this.acc;\n this.acc = (this.pacc - this.acc) * coeff + this.pacc;\n this.acc = this.saturate(this.acc);\n }\n opWRHX(inst) {\n // WRHX reg, coeff\n // Reg[reg] = ACC; ACC = PACC + ACC * coeff\n // Encoding: CCCCCCCCCCCCCCCC00000AAAAAA00111\n const reg = (inst >>> 5) & 0x3F;\n const coeff = this.decodeS1_14((inst >>> 16) & 0xFFFF);\n this.registers[reg] = this.acc;\n this.acc = this.pacc + this.acc * coeff;\n this.acc = this.saturate(this.acc);\n }\n opAND(inst) {\n // AND mask\n // Encoding: MMMMMMMMMMMMMMMMMMMMMMMM00001110\n const mask = (inst >>> 8) & 0xFFFFFF;\n // Convert ACC to 24-bit int, apply mask, convert back\n let iAcc = Math.floor(this.acc * 8388608.0); // 2^23\n iAcc &= mask;\n this.acc = iAcc / 8388608.0;\n }\n opOR(inst) {\n // OR mask\n // Encoding: MMMMMMMMMMMMMMMMMMMMMMMM00001111\n const mask = (inst >>> 8) & 0xFFFFFF;\n let iAcc = Math.floor(this.acc * 8388608.0);\n iAcc |= mask;\n this.acc = iAcc / 8388608.0;\n }\n opXOR(inst) {\n // XOR mask\n // Encoding: MMMMMMMMMMMMMMMMMMMMMMMM00010000\n const mask = (inst >>> 8) & 0xFFFFFF;\n let iAcc = Math.floor(this.acc * 8388608.0);\n iAcc ^= mask;\n this.acc = iAcc / 8388608.0;\n }\n opJAM(inst) {\n // JAM lfo\n // Encoding: 0000000000000000000000001N010011\n const lfo = (inst >>> 6) & 0x3; // 0=RMP0, 1=RMP1\n if (lfo === 0)\n this.rmp0 = 0;\n else if (lfo === 1)\n this.rmp1 = 0;\n }\n opWLDS(inst) {\n // WLDS lfo, freq, amp\n const lfoSelect = (inst >>> 29) & 0x1;\n const freqRaw = (inst >>> 20) & 0x1FF;\n const ampRaw = (inst >>> 5) & 0x7FFF;\n // Freq is an unsigned 9-bit value (0 to 511), amp is unsigned 15-bit (0 to 32767).\n // The FV-1 hardware uses power-of-2 fixed-point arithmetic (bit shifts),\n // so amplitude is divided by 2^15=32768, not 32767. Using 32767 causes the\n // computed delay address range to slightly exceed memory block boundaries.\n const f = freqRaw / 512.0;\n const a = ampRaw / 32768.0;\n if (lfoSelect === 0) {\n this.sin0_rate = f;\n this.sin0_range = a;\n this.registers[0] = f; // SIN0_RATE (reg0)\n this.registers[1] = a; // SIN0_RANGE (reg1)\n this.cos0 = -1.0;\n this.sin0 = 0.0;\n }\n else {\n this.sin1_rate = f;\n this.sin1_range = a;\n this.registers[2] = f; // SIN1_RATE (reg2)\n this.registers[3] = a; // SIN1_RANGE (reg3)\n this.cos1 = -1.0;\n this.sin1 = 0.0;\n }\n }\n opWLDR(inst) {\n // WLDR lfo, freq, amp\n // Encoding: 01NFFFFFFFFFFFFFFFF000000AA10010\n const lfoSelect = (inst >>> 29) & 0x1; // 0=RMP0, 1=RMP1\n // Freq is signed 16-bit\n let freq = (inst >>> 13) & 0xFFFF;\n if (freq & 0x8000)\n freq -= 65536;\n // Amp is a 2-bit code\n const ampCode = (inst >>> 5) & 0x3;\n const amp = 4096 >> ampCode; // 0->4096, 1->2048, 2->1024, 3->512\n // C logic: rate = f/16384.0, range = a/8192.0\n const f_val = freq / 16384.0;\n const a_val = amp / 8192.0;\n if (lfoSelect === 0) {\n this.rmp0_rate = f_val;\n this.rmp0_range = a_val;\n this.registers[4] = f_val; // RMP0_RATE (reg4)\n this.registers[5] = a_val; // RMP0_RANGE (reg5)\n this.rmp0 = 0.0;\n }\n else {\n this.rmp1_rate = f_val;\n this.rmp1_range = a_val;\n this.registers[6] = f_val; // RMP1_RATE (reg6)\n this.registers[7] = a_val; // RMP1_RANGE (reg7)\n this.rmp1 = 0.0;\n }\n }\n getLfoVal(flags, lfoSelect) {\n if (lfoSelect === 0) {\n return (flags & 1) ? this.cos0 : this.sin0;\n }\n else if (lfoSelect === 1) {\n return (flags & 1) ? this.cos1 : this.sin1;\n }\n else if (lfoSelect === 2) {\n return this.rmp0;\n }\n else {\n return this.rmp1;\n }\n }\n getLfoRange(lfoSelect) {\n if (lfoSelect === 0)\n return this.sin0_range;\n if (lfoSelect === 1)\n return this.sin1_range;\n if (lfoSelect === 2)\n return this.rmp0_range;\n return this.rmp1_range;\n }\n opCHO(inst) {\n const mode = (inst >>> 30) & 0x3;\n if (mode === 0) {\n this.opCHO_RDA(inst);\n }\n else if (mode === 2) {\n this.opCHO_SOF(inst);\n }\n else if (mode === 3) {\n this.opCHO_RDAL(inst);\n }\n }\n opCHO_RDA(inst) {\n const flags = (inst >>> 24) & 0x3F;\n const lfoSelect = (inst >>> 21) & 0x3;\n const offset = (inst >>> 5) & 0x7FFF;\n const lfoIn = this.getLfoVal(flags, lfoSelect);\n let range = this.getLfoRange(lfoSelect);\n range *= 8192.0;\n if (flags & 2) { // cho_reg\n this.lfo = lfoIn;\n }\n let v = this.lfo;\n if (flags & 16) { // cho_rptr2\n v += 0.5;\n if (v >= 1.0)\n v -= 1.0;\n }\n if (flags & 8) { // cho_compa\n v = -v;\n }\n let index;\n let c;\n if (flags & 32) { // cho_na\n index = offset;\n c = Math.min(v, 1.0 - v);\n c = Math.max(0.0, Math.min(1.0, 4.0 * c - 0.5));\n }\n else {\n // Match the FV-1 / reference C: combine v*range with offset BEFORE\n // flooring. Separating them (e.g. trunc(v*range) + offset) gives the\n // wrong integer index when v*range is negative, because Math.trunc\n // rounds toward zero. Linear interpolation needs floor semantics.\n const addr = v * range + offset;\n index = Math.floor(addr);\n c = addr - index;\n }\n const readAddr = (this.delayPointer + index) & this.delayMask;\n this.lr = this.delayRam[readAddr];\n this.traceDelayAddr = readAddr;\n this.traceDelayOffset = index;\n this.traceDelayOp = 'R';\n this.traceDelayValue = this.lr;\n this.currentReadOffsets.add(index);\n if (flags & 4) { // cho_compc\n c = 1.0 - c;\n }\n this.acc += this.lr * c;\n this.acc = this.saturate(this.acc);\n }\n opCHO_SOF(inst) {\n const flags = (inst >>> 24) & 0x3F;\n const lfoSelect = (inst >>> 21) & 0x3;\n const coeffRaw = (inst >>> 5) & 0xFFFF;\n const coeff = this.decodeS_15(coeffRaw);\n const lfoIn = this.getLfoVal(flags, lfoSelect);\n const range = this.getLfoRange(lfoSelect);\n if (flags & 2) { // cho_reg\n this.lfo = lfoIn;\n }\n let v = this.lfo;\n if (flags & 32) { // cho_na\n v = Math.min(v, 1.0 - v);\n v = Math.max(0.0, Math.min(1.0, 4.0 * v - 0.5));\n }\n else {\n v *= range;\n }\n if (flags & 4) { // cho_compc\n v = 1.0 - v;\n }\n this.acc = v * this.acc + coeff;\n this.acc = this.saturate(this.acc);\n }\n opCHO_RDAL(inst) {\n const flags = (inst >>> 24) & 0x3F;\n const lfoSelect = (inst >>> 21) & 0x3;\n const lfoIn = this.getLfoVal(flags, lfoSelect);\n this.acc = lfoIn;\n this.acc = this.saturate(this.acc);\n }\n // --- Debugging / State Access ---\n getPC() {\n return this.pc;\n }\n getProgSize() {\n return this.progSize;\n }\n setPC(pc) {\n this.pc = Math.max(0, Math.min(this.progSize - 1, pc));\n }\n setAcc(val) {\n this.acc = this.saturate(val);\n }\n setPacc(val) {\n this.pacc = this.saturate(val);\n }\n /**\n * Sets a register value with hardware-accurate saturation and quantization.\n * @param idx Register index (0-63)\n * @param val Raw value (float)\n */\n setRegister(idx, val) {\n if (idx < 0 || idx >= (32 + this.regCount))\n return;\n // POT registers (16, 17, 18) are 10-bit quantized 0..1\n if (idx >= 16 && idx <= 18) {\n val = Math.floor(Math.max(0, Math.min(0.9999999, val)) * 1024) / 1024;\n }\n else {\n // Other registers (ADC, DAC, User) are S.23 saturated\n val = this.saturate(val);\n }\n this.registers[idx] = val;\n }\n /**\n * Evaluates a string expression (register name, symbol, memory suffix).\n * @returns { result: string, value: number } or null\n */\n evaluateExpression(expr) {\n let expression = expr.trim().toUpperCase();\n // Handle suffixes ^ and #\n let suffix = \"\";\n if (expression.endsWith(\"^\")) {\n suffix = \"^\";\n expression = expression.slice(0, -1);\n }\n else if (expression.endsWith(\"#\")) {\n suffix = \"#\";\n expression = expression.slice(0, -1);\n }\n // 1. Check if it's a register name\n const state = this.getState();\n if (suffix === \"\" && state.registers[expression] !== undefined) {\n return { label: expression, value: state.registers[expression] };\n }\n // 2. Check if it's ACC/PACC\n if (suffix === \"\" && expression === \"ACC\") {\n return { label: \"ACC\", value: this.acc };\n }\n if (suffix === \"\" && expression === \"PACC\") {\n return { label: \"PACC\", value: this.pacc };\n }\n // 3. Check symbols (EQU)\n const sym = this.symbols.find(s => s.name.toUpperCase() === expression);\n if (sym && suffix === \"\") {\n const addr = parseInt(sym.value);\n if (!isNaN(addr) && addr >= 0 && addr <= 63) {\n return { label: `REG[${addr}] (${sym.name})`, value: this.registers[addr] };\n }\n }\n // 4. Check memories (MEM)\n const mem = this.memories.find(m => m.name.toUpperCase() === expression);\n if (mem && mem.start !== undefined) {\n let addr = mem.start;\n let typeLabel = \"\";\n if (suffix === \"^\") {\n addr = FV1Assembler.getMiddleAddr(mem.start, mem.size);\n typeLabel = \" (Middle)\";\n }\n else if (suffix === \"#\") {\n addr = FV1Assembler.getEndAddr(mem.start, mem.size, this.fv1AsmMemBug);\n typeLabel = \" (End)\";\n }\n if (addr >= 0 && addr < this.delaySize) {\n return { label: `MEM[${addr}] (${mem.name}${typeLabel})`, value: this.delayRam[addr] };\n }\n }\n // 5. Check DELAY[idx]\n if (suffix === \"\") {\n const delayMatch = expression.match(/^DELAY\\[(\\d+)\\]$/);\n if (delayMatch) {\n const idx = parseInt(delayMatch[1]);\n if (idx >= 0 && idx < this.delaySize) {\n return { label: `DELAY[${idx}]`, value: this.delayRam[idx] };\n }\n }\n }\n return null;\n }\n getState() {\n return {\n pc: this.pc,\n acc: this.acc,\n pacc: this.pacc,\n lr: this.lr,\n lfo: this.lfo,\n // Official Register Naming\n registers: Object.fromEntries(Array.from({ length: 32 + this.regCount }, (_, i) => {\n let name = `[${i}]`;\n if (i === 0)\n name = \"SIN0_RATE\";\n else if (i === 1)\n name = \"SIN0_RANGE\";\n else if (i === 2)\n name = \"SIN1_RATE\";\n else if (i === 3)\n name = \"SIN1_RANGE\";\n else if (i === 4)\n name = \"RMP0_RATE\";\n else if (i === 5)\n name = \"RMP0_RANGE\";\n else if (i === 6)\n name = \"RMP1_RATE\";\n else if (i === 7)\n name = \"RMP1_RANGE\";\n else if (i === 8)\n name = \"SIN0\";\n else if (i === 9)\n name = \"COS0\";\n else if (i === 10)\n name = \"SIN1\";\n else if (i === 11)\n name = \"COS1\";\n else if (i === 12)\n name = \"RMP0\";\n else if (i === 13)\n name = \"RMP1\";\n else if (i === 16)\n name = \"POT0\";\n else if (i === 17)\n name = \"POT1\";\n else if (i === 18)\n name = \"POT2\";\n else if (i === 20)\n name = \"ADCL\";\n else if (i === 21)\n name = \"ADCR\";\n else if (i === 22)\n name = \"DACL\";\n else if (i === 23)\n name = \"DACR\";\n else if (i === 24)\n name = \"ADDR_PTR\";\n else if (i >= 32 && i <= 63)\n name = `REG${i - 32}`;\n return [name, this.registers[i]];\n })),\n // Flags\n flags: {\n RUN: this.firstRun,\n ZRC: (this.acc * this.pacc < 0),\n ZRO: (this.acc === 0),\n GEZ: (this.acc >= 0),\n NEG: (this.acc < 0)\n },\n // LFO Internal positions\n lfoState: {\n sin0: this.sin0, cos0: this.cos0,\n sin1: this.sin1, cos1: this.cos1,\n rmp0: this.rmp0, rmp1: this.rmp1\n }\n };\n }\n getCycleCount() {\n return this.cycleCount;\n }\n getReadOffsets() {\n return Array.from(this.currentReadOffsets);\n }\n getRegisters() {\n return this.registers;\n }\n updateLFOs() {\n // Sync internal LFO modulations explicitly modified by WRAX or WRHX\n this.sin0_rate = this.registers[0];\n this.sin0_range = this.registers[1];\n this.sin1_rate = this.registers[2];\n this.sin1_range = this.registers[3];\n this.rmp0_rate = this.registers[4];\n this.rmp0_range = this.registers[5];\n this.rmp1_rate = this.registers[6];\n this.rmp1_range = this.registers[7];\n // C logic update_rmp0/1\n this.rmp0 -= this.rmp0_rate * (1.0 / 4096.0);\n while (this.rmp0 >= 1.0)\n this.rmp0 -= 1.0;\n while (this.rmp0 < 0.0)\n this.rmp0 += 1.0;\n this.rmp1 -= this.rmp1_rate * (1.0 / 4096.0);\n while (this.rmp1 >= 1.0)\n this.rmp1 -= 1.0;\n while (this.rmp1 < 0.0)\n this.rmp1 += 1.0;\n // SIN LFO update using coupled-form oscillator.\n // The FV-1 hardware updates cos first, then uses the updated cos for sin.\n // Clamp to [-1.0, MAX_ACC] to prevent float drift from exceeding the\n // FV-1's 24-bit fixed-point register range.\n const x0 = this.sin0_rate * (1.0 / 256.0);\n this.cos0 += x0 * this.sin0;\n this.sin0 -= x0 * this.cos0;\n this.sin0 = Math.max(FV1Simulator.MIN_ACC, Math.min(FV1Simulator.MAX_ACC, this.sin0));\n this.cos0 = Math.max(FV1Simulator.MIN_ACC, Math.min(FV1Simulator.MAX_ACC, this.cos0));\n const x1 = this.sin1_rate * (1.0 / 256.0);\n this.cos1 += x1 * this.sin1;\n this.sin1 -= x1 * this.cos1;\n this.sin1 = Math.max(FV1Simulator.MIN_ACC, Math.min(FV1Simulator.MAX_ACC, this.sin1));\n this.cos1 = Math.max(FV1Simulator.MIN_ACC, Math.min(FV1Simulator.MAX_ACC, this.cos1));\n }\n updateStateRegisters() {\n // ONLY update accumulators here! Rate/Range is dictated by the program loop!\n // Writing registers[0..7] here would explicitly overwrite mid-frame WRAX modulations!\n // LFO State Accumulators\n this.registers[8] = this.sin0;\n this.registers[9] = this.cos0;\n this.registers[10] = this.sin1;\n this.registers[11] = this.cos1;\n this.registers[12] = this.rmp0;\n this.registers[13] = this.rmp1;\n }\n getDelayRam() {\n return this.delayRam;\n }\n // --- Helpers ---\n decodeS1_14(raw) {\n // 16 bits: 1 sign, 1 integer, 14 fractional\n if (raw & 0x8000)\n return (raw - 0x10000) / 16384.0;\n return raw / 16384.0;\n }\n decodeS1_9(raw) {\n // 11 bits: 1 sign, 1 integer, 9 fractional\n if (raw & 0x400)\n return (raw - 0x800) / 512.0;\n return raw / 512.0;\n }\n decodeS_10(raw) {\n // 11 bits: 1 sign, 0 integer, 10 fractional\n if (raw & 0x400)\n return (raw - 0x800) / 1024.0;\n return raw / 1024.0;\n }\n decodeS4_6(raw) {\n // 11 bits: 1 sign, 4 integer, 6 fractional\n if (raw & 0x400)\n return (raw - 0x800) / 64.0;\n return raw / 64.0;\n }\n decodeS_15(raw) {\n // 16 bits: 1 sign, 0 integer, 15 fractional\n if (raw & 0x8000)\n return (raw - 0x10000) / 32768.0;\n return raw / 32768.0;\n }\n saturate(val) {\n if (val > FV1Simulator.MAX_ACC)\n return FV1Simulator.MAX_ACC;\n if (val < FV1Simulator.MIN_ACC)\n return FV1Simulator.MIN_ACC;\n return val;\n }\n /**\n * Enable trace logging with a streaming writer callback.\n * Each row is emitted immediately via the writer — nothing is stored in memory.\n * @param writer Callback that receives each CSV row (including header).\n * @param maxCycles Maximum number of sample cycles to log (0 = unlimited).\n * @param onComplete Optional callback when trace auto-completes.\n */\n enableTrace(writer, maxCycles = 0, onComplete) {\n this.traceEnabled = true;\n this.traceWriter = writer;\n this.traceMaxCycles = maxCycles;\n this.traceCycle = 0;\n this.traceRowCount = 0;\n this.traceOnComplete = onComplete || null;\n // Emit CSV Header immediately (Reduced set for delay debugging)\n writer(`cycle,pc,opcode,delay_op,delay_offset,delay_addr,delay_ptr`);\n console.log(`[FV1 Trace] Logging enabled (maxCycles=${maxCycles || 'unlimited'})`);\n }\n /**\n * Disable trace logging.\n */\n disableTrace() {\n this.traceEnabled = false;\n this.traceWriter = null;\n console.log(`[FV1 Trace] Logging disabled. ${this.traceRowCount} rows written.`);\n }\n /**\n * Returns whether trace logging is currently active.\n */\n isTraceEnabled() {\n return this.traceEnabled;\n }\n /**\n * Returns the number of trace rows emitted so far.\n */\n getTraceRowCount() {\n return this.traceRowCount;\n }\n /**\n * Called at end-of-frame to advance the trace cycle counter.\n * If maxCycles is reached, trace is automatically disabled.\n */\n advanceTraceCycle() {\n if (!this.traceEnabled)\n return;\n this.traceCycle++;\n if (this.traceMaxCycles > 0 && this.traceCycle >= this.traceMaxCycles) {\n const onComplete = this.traceOnComplete;\n this.disableTrace();\n if (onComplete)\n onComplete();\n }\n }\n logTrace(pc, opcode, inst, accBefore) {\n if (!this.traceWriter)\n return;\n // FILTER: Only log delay memory operations\n if (this.traceDelayOp === '')\n return;\n const opName = FV1Simulator.OPCODE_NAMES[opcode] || `?${opcode.toString(16)}`;\n // Resolve CHO sub-type\n let fullOpName = opName;\n if (opcode === 0x14) {\n const mode = (inst >>> 30) & 0x3;\n if (mode === 0)\n fullOpName = 'CHO_RDA';\n else if (mode === 2) {\n // CHO_SOF does not access delay RAM, so we filter it out\n return;\n }\n else if (mode === 3)\n fullOpName = 'CHO_RDAL';\n }\n else if (opcode === 0x12) {\n // WLDS/WLDR do not access delay RAM directly in a way we track here\n return;\n }\n const row = `${this.traceCycle},${pc},${fullOpName},` +\n `${this.traceDelayOp},${this.traceDelayOp !== '' ? this.traceDelayOffset : ''},${this.traceDelayAddr >= 0 ? this.traceDelayAddr : ''},${this.delayPointer}`;\n this.traceWriter(row);\n this.traceRowCount++;\n }\n}\nFV1Simulator.MAX_ACC = 1.0 - (1.0 / 8388608.0); // 24-bit S.23: 1 - 2^-23\nFV1Simulator.MIN_ACC = -FV1Simulator.MAX_ACC; // Symmetrically bound to prevent limits bias\n// --- Trace Logging System ---\nFV1Simulator.OPCODE_NAMES = {\n 0x00: 'RDA', 0x01: 'RMPA', 0x02: 'WRA', 0x03: 'WRAP',\n 0x04: 'RDAX', 0x05: 'RDFX', 0x06: 'WRAX', 0x07: 'WRHX',\n 0x08: 'WRLX', 0x09: 'MAXX', 0x0A: 'MULX', 0x0B: 'LOG',\n 0x0C: 'EXP', 0x0D: 'SOF', 0x0E: 'AND', 0x0F: 'OR',\n 0x10: 'XOR', 0x11: 'SKP', 0x12: 'WLDx', 0x13: 'JAM',\n 0x14: 'CHO'\n};\n//# sourceMappingURL=FV1Simulator.js.map","import { FV1Simulator } from '@audiofab-io/fv1-core'\n\ntype ChannelMode = 'mono' | 'stereo'\n\nclass FV1Processor extends AudioWorkletProcessor {\n private simulator = new FV1Simulator()\n private pot = [0.5, 0.5, 0.5]\n private bypassed = false\n /** Mono emulates the current Easy Spin hardware (only the left DAC is wired\n * to both jack tips). Stereo plays the FV-1's native left/right outputs. */\n private channelMode: ChannelMode = 'mono'\n\n constructor() {\n super()\n this.port.onmessage = ({ data }) => {\n switch (data.type) {\n case 'loadProgram':\n this.simulator.loadProgram(new Uint32Array(data.machineCode))\n break\n case 'setPot':\n this.pot[data.index] = data.value\n break\n case 'bypass':\n this.bypassed = data.active\n break\n case 'setChannelMode':\n this.channelMode = data.mode === 'stereo' ? 'stereo' : 'mono'\n break\n }\n }\n }\n\n process(inputs: Float32Array[][], outputs: Float32Array[][]): boolean {\n const input = inputs[0]\n const output = outputs[0]\n if (!input?.length || !output?.length) return true\n\n const inL = input[0]\n const inR = input[1] ?? inL\n const outL = output[0]\n const outR = output[1] ?? outL\n\n if (this.bypassed) {\n outL.set(inL)\n if (output[1]) outR.set(inR)\n return true\n }\n\n this.simulator.processBlock(inL, inR, outL, outR,\n this.pot[0], this.pot[1], this.pot[2])\n\n // Mono: mirror the left (FV-1 DACL) output to the right channel so the\n // simulator matches the current mono pedal, where only DACL drives the jack.\n if (this.channelMode === 'mono' && output[1]) {\n outR.set(outL)\n }\n return true\n }\n}\n\nregisterProcessor('fv1-processor', FV1Processor)\n"],"x_google_ignoreList":[0,1,2,3],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"fv1-processor.js","names":[],"sources":["../../node_modules/@audiofab-io/fv1-core/dist/assembler/FV1Parser.js","../../node_modules/@audiofab-io/fv1-core/dist/assembler/FV1Encoder.js","../../node_modules/@audiofab-io/fv1-core/dist/assembler/FV1Assembler.js","../../node_modules/@audiofab-io/fv1-core/dist/simulator/FV1Simulator.js","../../src/worklet/fv1-processor.ts"],"sourcesContent":["export class ParserError extends Error {\n constructor(message, line, column) {\n super(message);\n this.line = line;\n this.column = column;\n this.name = 'ParserError';\n }\n}\nexport var TokenType;\n(function (TokenType) {\n TokenType[TokenType[\"IDENTIFIER\"] = 0] = \"IDENTIFIER\";\n TokenType[TokenType[\"NUMBER\"] = 1] = \"NUMBER\";\n TokenType[TokenType[\"MNEMONIC\"] = 2] = \"MNEMONIC\";\n TokenType[TokenType[\"DIRECTIVE\"] = 3] = \"DIRECTIVE\";\n TokenType[TokenType[\"OPERATOR\"] = 4] = \"OPERATOR\";\n TokenType[TokenType[\"COMMA\"] = 5] = \"COMMA\";\n TokenType[TokenType[\"COLON\"] = 6] = \"COLON\";\n TokenType[TokenType[\"NEWLINE\"] = 7] = \"NEWLINE\";\n TokenType[TokenType[\"EOF\"] = 8] = \"EOF\";\n TokenType[TokenType[\"LPAREN\"] = 9] = \"LPAREN\";\n TokenType[TokenType[\"RPAREN\"] = 10] = \"RPAREN\";\n})(TokenType || (TokenType = {}));\nexport class Lexer {\n constructor(source) {\n this.source = source;\n this.pos = 0;\n this.line = 1;\n this.column = 1;\n }\n peek() {\n return this.source[this.pos] || '';\n }\n advance() {\n const char = this.peek();\n this.pos++;\n if (char === '\\n') {\n this.line++;\n this.column = 1;\n }\n else {\n this.column++;\n }\n return char;\n }\n tokenize() {\n const tokens = [];\n while (this.pos < this.source.length) {\n const char = this.peek();\n if (/\\s/.test(char) && char !== '\\n') {\n this.advance();\n }\n else if (char === ';') {\n // Skip comments\n while (this.peek() !== '\\n' && this.pos < this.source.length) {\n this.advance();\n }\n }\n else if (char === '\\n') {\n tokens.push({ type: TokenType.NEWLINE, value: '\\n', line: this.line, column: this.column });\n this.advance();\n }\n else if (char === ',') {\n tokens.push({ type: TokenType.COMMA, value: ',', line: this.line, column: this.column });\n this.advance();\n }\n else if (char === ':') {\n tokens.push({ type: TokenType.COLON, value: ':', line: this.line, column: this.column });\n this.advance();\n }\n else if (char === '(') {\n tokens.push({ type: TokenType.LPAREN, value: '(', line: this.line, column: this.column });\n this.advance();\n }\n else if (char === ')') {\n tokens.push({ type: TokenType.RPAREN, value: ')', line: this.line, column: this.column });\n this.advance();\n }\n else if (/[a-zA-Z_]/.test(char)) {\n tokens.push(this.readIdentifier());\n }\n else if (/[0-9.]/.test(char) || char === '$' || char === '%') {\n tokens.push(this.readNumber());\n }\n else if (/[-+*/|&<>^!]/.test(char)) {\n tokens.push({ type: TokenType.OPERATOR, value: this.advance(), line: this.line, column: this.column });\n }\n else {\n // Unknown character\n this.advance();\n }\n }\n tokens.push({ type: TokenType.EOF, value: '', line: this.line, column: this.column });\n return tokens;\n }\n readIdentifier() {\n let value = '';\n const startLine = this.line;\n const startCol = this.column;\n while (/[a-zA-Z0-9_#^.]/.test(this.peek())) {\n value += this.advance();\n }\n const upper = value.toUpperCase();\n if (['EQU', 'MEM'].includes(upper)) {\n return { type: TokenType.DIRECTIVE, value: upper, line: startLine, column: startCol };\n }\n // Mnemonics are checked during parsing or here. Let's keep them as identifiers for now \n // and resolve them in the parser.\n return { type: TokenType.IDENTIFIER, value: upper, line: startLine, column: startCol };\n }\n readNumber() {\n let value = '';\n const startLine = this.line;\n const startCol = this.column;\n if (this.peek() === '$') {\n value += this.advance();\n while (/[0-9a-fA-F]/.test(this.peek()))\n value += this.advance();\n }\n else if (this.peek() === '%') {\n value += this.advance();\n while (/[01_]/.test(this.peek()))\n value += this.advance();\n }\n else if (this.peek() === '0' && (this.source[this.pos + 1] || '').toLowerCase() === 'x') {\n value += this.advance(); // 0\n value += this.advance(); // x\n while (/[0-9a-fA-F]/.test(this.peek()))\n value += this.advance();\n }\n else {\n while (/[0-9\\.]/.test(this.peek()))\n value += this.advance();\n }\n return { type: TokenType.NUMBER, value, line: startLine, column: startCol };\n }\n}\nexport class Parser {\n constructor(tokens) {\n this.pos = 0;\n this.tokens = tokens.filter((t, i) => t.type !== TokenType.NEWLINE || this.isNextSignificant(tokens, i));\n }\n isNextSignificant(tokens, index) {\n // Only keep newlines if they are followed by something that isn't a newline or EOF\n for (let i = index + 1; i < tokens.length; i++) {\n if (tokens[i].type !== TokenType.NEWLINE) {\n return tokens[i].type !== TokenType.EOF;\n }\n }\n return false;\n }\n peek() {\n return this.tokens[this.pos] || { type: TokenType.EOF, value: '', line: -1, column: -1 };\n }\n advance() {\n return this.tokens[this.pos++];\n }\n match(type) {\n if (this.peek().type === type)\n return this.advance();\n return null;\n }\n parse() {\n const nodes = [];\n while (this.peek().type !== TokenType.EOF) {\n const node = this.parseStatement();\n if (node)\n nodes.push(node);\n // Consume optional newline\n while (this.match(TokenType.NEWLINE))\n ;\n }\n return nodes;\n }\n parseStatement() {\n const token = this.peek();\n if (token.type === TokenType.IDENTIFIER) {\n const next = this.tokens[this.pos + 1];\n // Label: IDENTIFIER:\n if (next && next.type === TokenType.COLON) {\n const label = this.advance();\n this.advance(); // consume :\n return { type: 'Label', name: label.value, line: label.line };\n }\n // Directive: IDENTIFIER EQU EXPR or EQU IDENTIFIER EXPR\n if (next && next.type === TokenType.DIRECTIVE) {\n const id = this.advance();\n const dir = this.advance();\n const expr = this.parseExpression();\n return { type: 'Directive', name: dir.value, identifier: id.value, expression: expr, line: dir.line };\n }\n }\n if (token.type === TokenType.DIRECTIVE) {\n const dir = this.advance();\n const id = this.match(TokenType.IDENTIFIER);\n if (!id)\n throw new ParserError(`Expected identifier after ${dir.value}`, dir.line, dir.column);\n const expr = this.parseExpression();\n return { type: 'Directive', name: dir.value, identifier: id.value, expression: expr, line: dir.line };\n }\n if (token.type === TokenType.IDENTIFIER) {\n const mnemonic = this.advance();\n const operands = [];\n if (this.peek().type !== TokenType.NEWLINE && this.peek().type !== TokenType.EOF) {\n operands.push(this.parseExpression());\n while (this.match(TokenType.COMMA)) {\n operands.push(this.parseExpression());\n }\n }\n return { type: 'Instruction', mnemonic: mnemonic.value, operands, line: mnemonic.line };\n }\n this.advance(); // Skip unknown\n return null;\n }\n parseExpression() {\n return this.parseBitwise();\n }\n parseBitwise() {\n let left = this.parseShift();\n while (this.peek().type === TokenType.OPERATOR && (['|', '&', '^'].includes(this.peek().value))) {\n const operator = this.advance().value;\n const right = this.parseShift();\n left = { type: 'Binary', left, operator, right };\n }\n return left;\n }\n parseShift() {\n let left = this.parseAdditive();\n while (this.peek().type === TokenType.OPERATOR && (['<', '>'].includes(this.peek().value))) {\n const operator = this.advance().value;\n const right = this.parseAdditive();\n left = { type: 'Binary', left, operator, right };\n }\n return left;\n }\n parseAdditive() {\n let left = this.parseMultiplicative();\n while (this.peek().type === TokenType.OPERATOR && (this.peek().value === '+' || this.peek().value === '-')) {\n const operator = this.advance().value;\n const right = this.parseMultiplicative();\n left = { type: 'Binary', left, operator, right };\n }\n return left;\n }\n parseMultiplicative() {\n let left = this.parsePrimary();\n while (this.peek().type === TokenType.OPERATOR && (this.peek().value === '*' || this.peek().value === '/')) {\n const operator = this.advance().value;\n const right = this.parsePrimary();\n left = { type: 'Binary', left, operator, right };\n }\n return left;\n }\n parsePrimary() {\n const token = this.peek();\n if (token.type === TokenType.NUMBER) {\n return { type: 'Number', value: this.parseNumberValue(this.advance().value) };\n }\n if (token.type === TokenType.IDENTIFIER) {\n return { type: 'Identifier', name: this.advance().value };\n }\n if (token.type === TokenType.LPAREN) {\n this.advance();\n const expr = this.parseExpression();\n if (!this.match(TokenType.RPAREN))\n throw new ParserError(`Expected )`, token.line, token.column);\n return expr;\n }\n if (token.type === TokenType.OPERATOR && (token.value === '-' || token.value === '+' || token.value === '!')) {\n const operator = this.advance().value;\n return { type: 'Unary', operator, expression: this.parsePrimary() };\n }\n throw new ParserError(`Unexpected token ${token.value}`, token.line, token.column);\n }\n parseNumberValue(val) {\n const upper = val.toUpperCase();\n if (upper.startsWith('$'))\n return parseInt(val.slice(1), 16);\n if (upper.startsWith('0X'))\n return parseInt(val, 16);\n if (upper.startsWith('%'))\n return parseInt(val.slice(1).replace(/_/g, ''), 2);\n return parseFloat(val);\n }\n}\n//# sourceMappingURL=FV1Parser.js.map","export const INSTRUCTION_SET = {\n // Accumulator\n 'SOF': {\n opcode: 0b01101, fields: [\n { name: 'coeff', bits: 16, offset: 16, type: 'S1_14' },\n { name: 'd', bits: 11, offset: 5, type: 'S_10' },\n { name: 'op', bits: 5, offset: 0, value: 0b01101 }\n ]\n },\n 'AND': {\n opcode: 0b01110, fields: [\n { name: 'mask', bits: 24, offset: 8, type: 'U' },\n { name: 'op', bits: 8, offset: 0, value: 0b01110 }\n ]\n },\n 'OR': {\n opcode: 0b01111, fields: [\n { name: 'mask', bits: 24, offset: 8, type: 'U' },\n { name: 'op', bits: 8, offset: 0, value: 0b01111 }\n ]\n },\n 'XOR': {\n opcode: 0b10000, fields: [\n { name: 'mask', bits: 24, offset: 8, type: 'U' },\n { name: 'op', bits: 8, offset: 0, value: 0b10000 }\n ]\n },\n 'LOG': {\n opcode: 0b01011, fields: [\n { name: 'coeff', bits: 16, offset: 16, type: 'S1_14' },\n { name: 'd', bits: 11, offset: 5, type: 'S4_6' },\n { name: 'op', bits: 5, offset: 0, value: 0b01011 }\n ]\n },\n 'EXP': {\n opcode: 0b01100, fields: [\n { name: 'coeff', bits: 16, offset: 16, type: 'S1_14' },\n { name: 'd', bits: 11, offset: 5, type: 'S_10' },\n { name: 'op', bits: 5, offset: 0, value: 0b01100 }\n ]\n },\n 'SKP': {\n opcode: 0b10001, fields: [\n { name: 'flags', bits: 5, offset: 27, type: 'LFO' }, // Special handling for flag bits\n { name: 'n', bits: 6, offset: 21, type: 'S' },\n { name: 'op', bits: 5, offset: 0, value: 0b10001 }\n ]\n },\n 'JMP': {\n opcode: 0b10001, fields: [\n { name: 'flags', bits: 5, offset: 27, value: 0 },\n { name: 'n', bits: 6, offset: 21, type: 'S' },\n { name: 'op', bits: 5, offset: 0, value: 0b10001 }\n ]\n },\n 'NOP': {\n opcode: 0b10001, fields: [\n { name: 'flags', bits: 5, offset: 27, value: 0 },\n { name: 'n', bits: 6, offset: 21, value: 0 },\n { name: 'op', bits: 5, offset: 0, value: 0b10001 }\n ]\n },\n // Register\n 'RDAX': {\n opcode: 0b00100, fields: [\n { name: 'addr', bits: 6, offset: 5, type: 'REG' },\n { name: 'coeff', bits: 16, offset: 16, type: 'S1_14' },\n { name: 'op', bits: 5, offset: 0, value: 0b00100 }\n ]\n },\n 'WRAX': {\n opcode: 0b00110, fields: [\n { name: 'addr', bits: 6, offset: 5, type: 'REG' },\n { name: 'coeff', bits: 16, offset: 16, type: 'S1_14' },\n { name: 'op', bits: 5, offset: 0, value: 0b00110 }\n ]\n },\n 'MAXX': {\n opcode: 0b01001, fields: [\n { name: 'addr', bits: 6, offset: 5, type: 'REG' },\n { name: 'coeff', bits: 16, offset: 16, type: 'S1_14' },\n { name: 'op', bits: 5, offset: 0, value: 0b01001 }\n ]\n },\n 'MULX': {\n opcode: 0b01010, fields: [\n { name: 'addr', bits: 6, offset: 5, type: 'REG' },\n { name: 'op', bits: 5, offset: 0, value: 0b01010 }\n ]\n },\n 'RDFX': {\n opcode: 0b00101, fields: [\n { name: 'addr', bits: 6, offset: 5, type: 'REG' },\n { name: 'coeff', bits: 16, offset: 16, type: 'S1_14' },\n { name: 'op', bits: 5, offset: 0, value: 0b00101 }\n ]\n },\n 'WRLX': {\n opcode: 0b01000, fields: [\n { name: 'addr', bits: 6, offset: 5, type: 'REG' },\n { name: 'coeff', bits: 16, offset: 16, type: 'S1_14' },\n { name: 'op', bits: 5, offset: 0, value: 0b01000 }\n ]\n },\n 'WRHX': {\n opcode: 0b00111, fields: [\n { name: 'addr', bits: 6, offset: 5, type: 'REG' },\n { name: 'coeff', bits: 16, offset: 16, type: 'S1_14' },\n { name: 'op', bits: 5, offset: 0, value: 0b00111 }\n ]\n },\n 'LDAX': {\n opcode: 0b00101, fields: [\n { name: 'coeff', bits: 16, offset: 16, value: 0 },\n { name: 'addr', bits: 6, offset: 5, type: 'REG' },\n { name: 'op', bits: 5, offset: 0, value: 0b00101 }\n ]\n },\n // Delay RAM\n 'RDA': {\n opcode: 0b00000, fields: [\n { name: 'addr', bits: 16, offset: 5, type: 'ADDR' },\n { name: 'coeff', bits: 11, offset: 21, type: 'S1_9' },\n { name: 'op', bits: 5, offset: 0, value: 0b00000 }\n ]\n },\n 'RMPA': {\n opcode: 0b00001, fields: [\n { name: 'coeff', bits: 11, offset: 21, type: 'S1_9' },\n { name: 'op', bits: 5, offset: 0, value: 0b00001 }\n ]\n },\n 'WRA': {\n opcode: 0b00010, fields: [\n { name: 'addr', bits: 16, offset: 5, type: 'ADDR' },\n { name: 'coeff', bits: 11, offset: 21, type: 'S1_9' },\n { name: 'op', bits: 5, offset: 0, value: 0b00010 }\n ]\n },\n 'WRAP': {\n opcode: 0b00011, fields: [\n { name: 'addr', bits: 16, offset: 5, type: 'ADDR' },\n { name: 'coeff', bits: 11, offset: 21, type: 'S1_9' },\n { name: 'op', bits: 5, offset: 0, value: 0b00011 }\n ]\n },\n // LFO/CHO\n 'WLDS': {\n opcode: 0b10010, fields: [\n { name: 'sinLfo', bits: 1, offset: 29, type: 'U' }, // N\n { name: 'freq', bits: 9, offset: 20, type: 'U' }, // F\n { name: 'ampl', bits: 15, offset: 5, type: 'U' }, // A\n { name: 'op', bits: 5, offset: 0, value: 0b10010 }\n ]\n },\n 'WLDR': {\n opcode: 0b10010, fields: [\n { name: 'type', bits: 1, offset: 30, value: 1 }, // Always 1 for WLDR\n { name: 'rmpLfo', bits: 1, offset: 29, type: 'U' }, // N\n { name: 'freq', bits: 16, offset: 13, type: 'U' }, // F (signed 16-bit)\n { name: 'ampl', bits: 2, offset: 5, type: 'U' }, // A (backward encoding handled in assembler)\n { name: 'op', bits: 5, offset: 0, value: 0b10010 }\n ]\n },\n 'JAM': {\n opcode: 0b10011, fields: [\n { name: 'rmpLfo', bits: 1, offset: 6, type: 'U' },\n { name: 'type', bits: 1, offset: 7, value: 1 },\n { name: 'op', bits: 5, offset: 0, value: 0b10011 }\n ]\n },\n 'CHO': {\n opcode: 0b10100, fields: [\n { name: 'mode', bits: 2, offset: 30, type: 'U' },\n { name: 'flags', bits: 6, offset: 24, type: 'U' },\n { name: 'n', bits: 3, offset: 21, type: 'U' },\n { name: 'param', bits: 16, offset: 5, type: 'ADDR' }, // Can be addr or coeff\n { name: 'op', bits: 5, offset: 0, value: 0b10100 }\n ]\n },\n // Pseudo-ops\n 'CLR': { opcode: 0b01110, fields: [{ name: 'val', bits: 32, offset: 0, value: 0b01110 }] },\n 'NOT': { opcode: 0b10000, fields: [{ name: 'val', bits: 32, offset: 0, value: 0b10000 }] },\n 'ABSA': { opcode: 0b01001, fields: [{ name: 'val', bits: 32, offset: 0, value: 0b01001 }] },\n};\nexport class Encoder {\n static encode(format, value) {\n switch (format) {\n case 'S1_14': return this.toFixedPoint(value, 1, 14, 2.0);\n case 'S_15': return this.toFixedPoint(value, 0, 15, 1.0);\n case 'S1_9': return this.toFixedPoint(value, 1, 9, 2.0);\n case 'S_10': return this.toFixedPoint(value, 0, 10, 1.0);\n case 'S4_6': return this.toFixedPoint(value, 4, 6, 16.0);\n }\n return value;\n }\n static toFixedPoint(value, intBits, fracBits, maxValue) {\n const lsb = maxValue / (1 << fracBits);\n const min = -maxValue;\n const max = maxValue - lsb;\n let num = Math.min(Math.max(value, min), max);\n let encoded = Math.trunc(num * (1 << fracBits));\n const totalBits = 1 + intBits + fracBits;\n const mask = (1 << totalBits) - 1;\n return (encoded < 0) ? (encoded + (1 << totalBits)) & mask : encoded & mask;\n }\n static assembleInstruction(mnemonic, operands, schema) {\n let result = 0;\n let operandIdx = 0;\n for (const field of schema.fields) {\n let val = 0;\n if (field.value !== undefined) {\n val = field.value;\n }\n else {\n val = operands[operandIdx++];\n if (field.type)\n val = this.encode(field.type, val);\n }\n const mask = field.bits === 32 ? 0xFFFFFFFF : (1 << field.bits) - 1;\n result |= (val & mask) << field.offset;\n }\n return result >>> 0;\n }\n}\n//# sourceMappingURL=FV1Encoder.js.map","import { Lexer, Parser, ParserError } from './FV1Parser.js';\nimport { INSTRUCTION_SET, Encoder } from './FV1Encoder.js';\nexport class FV1Assembler {\n constructor(options = {}) {\n this.problems = [];\n this.symbols = new Map();\n this.memories = [];\n this.labels = new Map();\n this.addressToLineMap = new Map();\n this.usedRegisters = new Set();\n this.usedLFOs = new Set();\n this.configuredLFOs = new Set();\n this.userSymbols = new Set();\n this.symbolLines = new Map();\n this.PREDEFINED_SYMBOLS = {\n 'SIN0_RATE': 0x00, 'SIN0_RANGE': 0x01, 'SIN1_RATE': 0x02, 'SIN1_RANGE': 0x03,\n 'RMP0_RATE': 0x04, 'RMP0_RANGE': 0x05, 'RMP1_RATE': 0x06, 'RMP1_RANGE': 0x07,\n 'POT0': 0x10, 'POT1': 0x11, 'POT2': 0x12, 'ADCL': 0x14, 'ADCR': 0x15,\n 'DACL': 0x16, 'DACR': 0x17, 'ADDR_PTR': 0x18,\n 'SIN0': 0x00, 'SIN1': 0x01, 'RMP0': 0x02, 'RMP1': 0x03,\n 'COS0': 0x08, 'COS1': 0x09,\n 'RDA': 0x00, 'SOF': 0x02, 'RDAL': 0x03,\n 'SIN': 0x00, 'COS': 0x01, 'REG': 0x02, 'COMPC': 0x04,\n 'COMPA': 0x08, 'RPTR2': 0x10, 'NA': 0x20,\n 'RUN': 0x10, 'ZRC': 0x08, 'ZRO': 0x04,\n 'GEZ': 0x02, 'NEG': 0x01\n };\n this.reservedSymbols = new Set();\n this.options = {\n fv1AsmMemBug: options.fv1AsmMemBug ?? true,\n clampReals: options.clampReals ?? true,\n regCount: options.regCount ?? 32,\n progSize: options.progSize ?? 128,\n delaySize: options.delaySize ?? 32768\n };\n this.reset();\n }\n reset() {\n this.problems = [];\n this.symbols.clear();\n this.memories = [];\n this.labels.clear();\n this.addressToLineMap.clear();\n this.usedRegisters.clear();\n this.usedLFOs.clear();\n this.configuredLFOs.clear();\n this.userSymbols.clear();\n this.symbolLines.clear(); // Added this line\n this.initSymbols(); // Added this line\n }\n initSymbols() {\n // Load predefined symbols\n for (const [key, val] of Object.entries(this.PREDEFINED_SYMBOLS)) {\n this.symbols.set(key, val);\n this.reservedSymbols.add(key);\n }\n // Load REG0-31\n for (let i = 0; i < this.options.regCount; i++) {\n this.symbols.set(`REG${i}`, 0x20 + i);\n this.reservedSymbols.add(`REG${i}`);\n }\n }\n assemble(source) {\n this.reset();\n try {\n const lexer = new Lexer(source);\n const tokens = lexer.tokenize();\n const parser = new Parser(tokens);\n const ast = parser.parse();\n this.pass1_ResolveDirectives(ast);\n this.pass2_ResolveLabels(ast);\n const machineCode = this.pass3_GenerateCode(ast);\n return {\n machineCode,\n problems: this.problems,\n labels: this.labels,\n symbols: Array.from(this.symbols.entries())\n .filter(([name]) => this.userSymbols.has(name))\n .map(([name, value]) => ({ name, value: value.toString(), line: this.symbolLines.get(name) })),\n memories: this.memories,\n addressToLineMap: this.addressToLineMap,\n usedRegistersCount: this.usedRegisters.size,\n usedLFOs: Array.from(this.usedLFOs)\n };\n }\n catch (e) {\n const line = (e instanceof ParserError) ? e.line : 1;\n this.problems.push({ message: `Parser error: ${e instanceof Error ? e.message : String(e)}`, isfatal: true, line });\n return {\n machineCode: [],\n problems: this.problems,\n labels: new Map(),\n symbols: [],\n memories: [],\n addressToLineMap: new Map(),\n usedRegistersCount: 0,\n usedLFOs: []\n };\n }\n }\n pass1_ResolveDirectives(ast) {\n let nextDelayAddr = 0;\n for (const node of ast) {\n if (node.type === 'Directive') {\n if (node.name === 'EQU') {\n if (this.reservedSymbols.has(node.identifier)) {\n this.problems.push({ message: `Cannot redefine reserved symbol '${node.identifier}'`, isfatal: true, line: node.line });\n }\n else if (this.userSymbols.has(node.identifier)) {\n this.problems.push({ message: `Symbol '${node.identifier}' is already defined on line ${this.symbolLines.get(node.identifier)}`, isfatal: true, line: node.line });\n }\n else {\n const value = this.evaluateExpression(node.expression, node.line);\n this.symbols.set(node.identifier, value);\n this.userSymbols.add(node.identifier);\n this.symbolLines.set(node.identifier, node.line);\n }\n }\n else if (node.name === 'MEM') {\n if (this.reservedSymbols.has(node.identifier)) {\n this.problems.push({ message: `Cannot redefine reserved symbol '${node.identifier}'`, isfatal: true, line: node.line });\n continue;\n }\n const size = this.evaluateExpression(node.expression, node.line);\n const start = nextDelayAddr;\n const middle = start + (size % 2 ? (size - 1) / 2 - 1 : size / 2);\n const end = start + size - 1;\n const buggyEnd = end + (this.options.fv1AsmMemBug ? 1 : 0);\n const mem = { name: node.identifier, size, start, middle, end, line: node.line, original: '' };\n this.memories.push(mem);\n // Register special suffixes\n this.symbols.set(node.identifier, start);\n this.symbols.set(node.identifier + '^', middle);\n this.symbols.set(node.identifier + '#', buggyEnd);\n nextDelayAddr = buggyEnd + 1;\n }\n }\n }\n }\n pass2_ResolveLabels(ast) {\n let pc = 0;\n for (const node of ast) {\n if (node.type === 'Label') {\n this.labels.set(node.name, { line: node.line, instructionLine: pc });\n }\n else if (node.type === 'Instruction') {\n pc++;\n }\n }\n }\n pass3_GenerateCode(ast) {\n const code = [];\n let pc = 0;\n for (const node of ast) {\n if (node.type === 'Instruction') {\n const schema = INSTRUCTION_SET[node.mnemonic];\n if (!schema) {\n this.problems.push({ message: `Unknown instruction ${node.mnemonic}`, isfatal: true, line: node.line });\n code.push(0);\n continue;\n }\n let operands = node.operands.map(op => {\n // Special case for labels in JMP/SKP\n if (op.type === 'Identifier' && this.labels.has(op.name)) {\n return this.labels.get(op.name).instructionLine - pc - 1;\n }\n return this.evaluateExpression(op, node.line);\n });\n // --- Specialized Encoding Logic ---\n // LFO Tracking for configurations\n if (node.mnemonic === 'WLDS' || node.mnemonic === 'WLDR') {\n const lfoReg = operands[0];\n const lfoName = this.getLFOName(lfoReg);\n if (lfoName) {\n if (node.mnemonic === 'WLDS') {\n if (this.configuredLFOs.has(lfoName)) {\n this.problems.push({ message: `LFO ${lfoName} is configured more than once`, isfatal: true, line: node.line });\n }\n this.configuredLFOs.add(lfoName);\n }\n this.usedLFOs.add(lfoName);\n }\n }\n if (node.mnemonic === 'CHO') {\n const mode = operands[0];\n const n = operands[1];\n const rdaMode = this.symbols.get('RDA');\n const sofMode = this.symbols.get('SOF');\n const rdalMode = this.symbols.get('RDAL');\n if (mode === rdalMode) {\n // CHO RDAL, N -> [mode, flags=0x02(fixed bit 25), n, param=0]\n operands = [mode, 0x02, n, 0];\n }\n else if (mode === rdaMode || mode === sofMode) {\n const flags = operands[2];\n let param = operands[3];\n if (mode === sofMode) {\n param = Encoder.encode('S1_14', param);\n }\n operands = [mode, flags, n, param];\n }\n }\n else if (node.mnemonic === 'WLDR') {\n // Match previous backwards-encoded amplitude\n let ampl = operands[2];\n switch (ampl) {\n case 512:\n ampl = 3;\n break;\n case 1024:\n ampl = 2;\n break;\n case 2048:\n ampl = 1;\n break;\n case 4096:\n ampl = 0;\n break;\n default:\n this.problems.push({ message: `Invalid amplitude ${ampl} for WLDR`, isfatal: true, line: node.line });\n }\n // Handle RMP LFO mapping\n let rmpLfo = operands[0];\n if ([0, 2].includes(rmpLfo))\n rmpLfo = 0;\n else if ([1, 3].includes(rmpLfo))\n rmpLfo = 1;\n operands = [rmpLfo, operands[1], ampl];\n }\n else if (node.mnemonic === 'JAM') {\n let rmpLfo = operands[0];\n if ([0, 2].includes(rmpLfo))\n rmpLfo = 0;\n else if ([1, 3].includes(rmpLfo))\n rmpLfo = 1;\n operands = [rmpLfo];\n }\n // Track register usage\n schema.fields.forEach((field, i) => {\n if (field.type === 'REG' && operands[i] !== undefined) {\n this.trackRegister(operands[i], node.line);\n }\n });\n // Additional LFO tracking for register writes to RATE/RANGE\n if (node.mnemonic === 'WRAX' || node.mnemonic === 'RDAX') {\n const regNum = operands[0];\n const lfoName = this.getLFONameFromRegister(regNum);\n if (lfoName) {\n this.usedLFOs.add(lfoName);\n }\n }\n code.push(Encoder.assembleInstruction(node.mnemonic, operands, schema));\n this.addressToLineMap.set(pc, node.line);\n pc++;\n }\n }\n // Pad to progSize\n while (code.length < this.options.progSize)\n code.push(0x00000011); // NOP\n return code;\n }\n trackRegister(addr, line) {\n if (addr >= 0x20 && addr <= 0x3F) {\n const regNum = addr - 0x20;\n if (regNum >= this.options.regCount) {\n this.problems.push({ message: `Register REG${regNum} exceeds limit ${this.options.regCount}`, isfatal: true, line });\n }\n this.usedRegisters.add(regNum);\n }\n }\n getLFOName(lfoId) {\n switch (lfoId) {\n case 0: return 'SIN0';\n case 1: return 'SIN1';\n case 2: return 'RMP0';\n case 3: return 'RMP1';\n default: return null;\n }\n }\n getLFONameFromRegister(addr) {\n // 0x00=SIN0_RATE, 0x01=SIN0_RANGE, 0x02=SIN1_RATE, 0x03=SIN1_RANGE\n // 0x04=RMP0_RATE, 0x05=RMP0_RANGE, 0x06=RMP1_RATE, 0x07=RMP1_RANGE\n switch (addr) {\n case 0x00:\n case 0x01: return 'SIN0';\n case 0x02:\n case 0x03: return 'SIN1';\n case 0x04:\n case 0x05: return 'RMP0';\n case 0x06:\n case 0x07: return 'RMP1';\n default: return null;\n }\n }\n evaluateExpression(expr, line) {\n switch (expr.type) {\n case 'Number': return expr.value;\n case 'Identifier':\n if (this.symbols.has(expr.name))\n return this.symbols.get(expr.name);\n this.problems.push({ message: `Undefined symbol ${expr.name}`, isfatal: true, line });\n return 0;\n case 'Binary':\n const left = this.evaluateExpression(expr.left, line);\n const right = this.evaluateExpression(expr.right, line);\n switch (expr.operator) {\n case '+': return left + right;\n case '-': return left - right;\n case '*': return left * right;\n case '/': return left / right;\n case '|': return left | right;\n case '&': return left & right;\n case '^': return left ^ right;\n case '<': return (left << right) >>> 0;\n case '>': return (left >>> right);\n default: return 0;\n }\n case 'Unary':\n const val = this.evaluateExpression(expr.expression, line);\n if (expr.operator === '-')\n return -val;\n if (expr.operator === '!')\n return (~Math.floor(val)) >>> 0;\n return val;\n }\n }\n static formatMachineCode(machineCode) {\n return machineCode.map((word, index) => `${index.toString().padStart(4, '0')}\\t${word.toString(16).toUpperCase().padStart(8, '0')}`).join('\\n');\n }\n static toUint8Array(machineCode) {\n const buffer = new ArrayBuffer(machineCode.length * 4);\n const view = new DataView(buffer);\n machineCode.forEach((val, i) => view.setUint32(i * 4, val, false));\n return new Uint8Array(buffer);\n }\n static getMiddleAddr(start, size) {\n return start + (size % 2 ? (size - 1) / 2 - 1 : size / 2);\n }\n static getEndAddr(start, size, fv1AsmMemBug) {\n return start + size - 1 + (fv1AsmMemBug ? 1 : 0);\n }\n}\n//# sourceMappingURL=FV1Assembler.js.map","/**\n * FV-1 DSP Simulator\n *\n * Simulates the Spin Semiconductor FV-1 DSP chip.\n * This class is designed to be platform-agnostic (Node.js or Browser/AudioWorklet).\n */\nimport { FV1Assembler } from '../assembler/FV1Assembler.js';\nexport class FV1Simulator {\n // Register aliases (Getters/Setters)\n // 0-7: Parameters\n // These are now handled by updateStateRegisters for debugger view\n // 8-13: Internal State accumulators (aliased as registers for the debugger)\n // These are now handled by updateStateRegisters for debugger view\n constructor() {\n // Constants\n // Capabilities (Configurable)\n this.delaySize = 32768;\n this.delayMask = 32767; // For efficient circular buffer\n this.regCount = 32;\n this.progSize = 128;\n // --- Float-based LFO state (from Expert Sleepers C port) ---\n this.sin0 = 0;\n this.cos0 = 0;\n this.sin1 = 0;\n this.cos1 = 0;\n this.rmp0 = 0;\n this.rmp1 = 0;\n this.sin0_rate = 0;\n this.sin0_range = 0;\n this.sin1_rate = 0;\n this.sin1_range = 0;\n this.rmp0_rate = 0;\n this.rmp0_range = 0;\n this.rmp1_rate = 0;\n this.rmp1_range = 0;\n this.acc = 0;\n this.pacc = 0;\n this.lr = 0; // Last Read register\n this.lfo = 0; // Internal LFO fregister (for CHO)\n this.delayPointer = 0; // Circular buffer pointer\n this.firstRun = true;\n this.pc = 0; // Program Counter\n this.breakpoints = new Set();\n // Symbol metadata (optional, for debugging)\n this.symbols = [];\n this.memories = [];\n this.fv1AsmMemBug = false;\n // --- Trace Logging ---\n this.traceEnabled = false;\n this.traceWriter = null; // Streaming callback\n this.cycleCount = 0;\n this.traceCycle = 0;\n this.traceMaxCycles = 0; // 0 = unlimited\n this.traceRowCount = 0;\n this.traceDelayAddr = -1; // computed physical address in delay RAM\n this.traceDelayOffset = -1; // raw offset from instruction (identifies MEM block)\n this.traceDelayOp = ''; // 'R' for read, 'W' for write\n this.traceDelayValue = 0; // value read/written\n this.traceInstructionPC = -1; // PC of currently executing instruction\n this.currentReadOffsets = new Set(); // Tracks read offsets in current sample cycle\n this.traceOnComplete = null;\n this.delayRam = new Float32Array(this.delaySize);\n this.registers = new Float32Array(32 + this.regCount);\n this.program = new Uint32Array(this.progSize);\n }\n /**\n * Configures simulator hardware limits.\n */\n setCapabilities(delaySize, regCount, progSize) {\n this.delaySize = delaySize;\n this.delayMask = delaySize - 1; // Assuming power of 2 for now, but modulo is fallback\n this.regCount = regCount; // Number of user registers\n this.progSize = progSize;\n // Reallocate if needed\n this.delayRam = new Float32Array(this.delaySize);\n this.registers = new Float32Array(32 + this.regCount); // 32 system + N user registers\n this.program = new Uint32Array(this.progSize);\n this.reset();\n }\n getDelayPointer() {\n return this.delayPointer;\n }\n getDelaySize() {\n return this.delaySize;\n }\n /**\n * Loads the machine code into the simulator.\n * @param code Array of 32-bit integers representing the assembled program.\n */\n loadProgram(code) {\n if (code.length > this.progSize) {\n console.warn(`Program size (${code.length}) exceeds max size (${this.progSize}). Truncating.`);\n }\n this.program.fill(0);\n this.program.set(code.slice(0, this.progSize));\n this.reset();\n }\n /**\n * Resets the simulator state (clears memory, registers, accumulator).\n */\n reset() {\n this.delayRam.fill(0);\n this.registers.fill(0);\n this.acc = 0;\n this.pacc = 0;\n this.lr = 0;\n this.lfo = 0;\n this.pc = 0;\n this.delayPointer = 0;\n this.firstRun = true;\n this.sin0 = 0;\n this.sin1 = 0;\n // Peak amplitude from Java SinLFO.java initialized to -0x7fff00 mapped to float (-1.0)\n // BUT wait, in C the initialization is not explicit, we can just use 1.0 or -1.0\n // SpinCAD sets cos to -0x7fff00l which is approx -1.0\n this.cos0 = -1.0;\n this.cos1 = -1.0;\n this.rmp0 = 0;\n this.rmp1 = 0;\n this.sin0_rate = 0;\n this.sin0_range = 0;\n this.sin1_rate = 0;\n this.sin1_range = 0;\n this.rmp0_rate = 0;\n this.rmp0_range = 0;\n this.rmp1_rate = 0;\n this.rmp1_range = 0;\n // Default POT values to 0.5\n this.registers[16] = 0.5;\n this.registers[17] = 0.5;\n this.registers[18] = 0.5;\n }\n /**\n * Set breakpoints at specific instruction addresses.\n * @param addresses Set of addresses to break at.\n */\n setBreakpoints(addresses) {\n this.breakpoints = addresses;\n }\n /**\n * Set symbol and memory metadata for expression evaluation.\n */\n setSymbols(symbols, memories, fv1AsmMemBug = false) {\n this.symbols = symbols;\n this.memories = memories;\n this.fv1AsmMemBug = fv1AsmMemBug;\n }\n /**\n * Process a block of audio samples.\n * Useful for real-time audio processing in AudioWorklets.\n */\n processBlock(inputL, inputR, outputL, outputR, pot0, pot1, pot2) {\n const len = inputL.length;\n for (let i = 0; i < len; i++) {\n const [outL, outR] = this.step(inputL[i], inputR[i], pot0, pot1, pot2);\n outputL[i] = outL;\n outputR[i] = outR;\n }\n }\n /**\n * Process a single sample frame.\n * Executes instructions until the end of the program or a breakpoint is hit.\n * @param skipCurrentBreakpoint If true, will not break on the instruction at the current PC.\n * @returns [outL, outR, breakpointHit]\n */\n step(inL, inR, pot0, pot1, pot2, skipCurrentBreakpoint = false) {\n // Only begin a new frame if we are at PC 0 (either start or after wrap around)\n if (this.pc === 0) {\n this.beginFrame(inL, inR, pot0, pot1, pot2);\n }\n let firstInstruction = true;\n while (this.pc < this.progSize) {\n if (this.breakpoints.has(this.pc)) {\n if (!firstInstruction || !skipCurrentBreakpoint) {\n return [...this.getOutputs(), true];\n }\n }\n this.stepInstruction();\n firstInstruction = false;\n }\n return [...this.endFrame(), false];\n }\n getOutputs() {\n return [this.registers[22], this.registers[23]];\n }\n beginFrame(inL = 0, inR = 0, pot0 = 0, pot1 = 0, pot2 = 0) {\n this.cycleCount++;\n this.currentReadOffsets.clear();\n // Saturate inputs (ADC is -1.0 to 0.999..., POT is 0 to 0.999...)\n // POT has 10-bit resolution (1024 levels)\n const sat = (v) => Math.max(-1.0, Math.min(FV1Simulator.MAX_ACC, v));\n const satPot = (v) => {\n const quantized = Math.floor(Math.max(0, Math.min(0.9999999, v)) * 1024) / 1024;\n return quantized;\n };\n // Execute Program Setup\n this.acc = 0; // Accumulator is cleared at start of run\n this.lr = 0; // LR is transient\n this.pacc = 0;\n this.pc = 0;\n // Map inputs to registers (Standard FV-1 mapping)\n this.registers[20] = sat(inL);\n this.registers[21] = sat(inR);\n this.registers[16] = satPot(pot0);\n this.registers[17] = satPot(pot1);\n this.registers[18] = satPot(pot2);\n this.updateStateRegisters();\n }\n endFrame() {\n this.pc = 0;\n this.firstRun = false;\n this.updateLFOs();\n this.updateStateRegisters();\n this.advanceTraceCycle();\n // Advance Delay Pointer (Circular Buffer)\n this.delayPointer = (this.delayPointer - 1 + this.delaySize) % this.delaySize;\n // Outputs (DACL = REG22, DACR = REG23)\n return [this.registers[22], this.registers[23]];\n }\n /**\n * Executes a single instruction at the current PC.\n * @returns The next PC address.\n */\n stepInstruction() {\n if (this.pc >= this.progSize)\n return this.pc;\n const inst = this.program[this.pc];\n const opcode = inst & 0x1F;\n const preOpAcc = this.acc;\n // Reset per-instruction trace state\n this.traceDelayAddr = -1;\n this.traceDelayOffset = -1;\n this.traceDelayOp = '';\n this.traceDelayValue = 0;\n this.traceInstructionPC = this.pc;\n const skip = this.executeInstruction(inst);\n // Trace log AFTER instruction executes so ACC reflects the result\n if (this.traceEnabled) {\n this.logTrace(this.traceInstructionPC, opcode, inst, preOpAcc);\n }\n if (opcode !== 0x11) { // Not SKP\n this.pacc = preOpAcc;\n }\n this.pc += 1 + skip;\n return this.pc;\n }\n executeInstruction(inst) {\n const opcode = inst & 0x1F; // Bottom 5 bits for opcode\n let skip = 0;\n switch (opcode) {\n case 0x00: // RDA (Read Delay Accumulate)\n this.opRDA(inst);\n break;\n case 0x01: // RMPA (Read Memory Pointer Accumulate)\n this.opRMPA(inst);\n break;\n case 0x02: // WRA (Write Delay Accumulate)\n this.opWRA(inst);\n break;\n case 0x03: // WRAP (Write Delay Accumulate & Pointer)\n this.opWRAP(inst);\n break;\n case 0x04: // RDAX (Read Register Accumulate)\n this.opRDAX(inst);\n break;\n case 0x05: // RDFX (Read Register Filter)\n this.opRDFX(inst);\n break;\n case 0x06: // WRAX (Write Register Accumulate)\n this.opWRAX(inst);\n break;\n case 0x07: // WRHX (Write Register High)\n this.opWRHX(inst);\n break;\n case 0x08: // WRLX (Write Register Low)\n this.opWRLX(inst);\n break;\n case 0x09: // MAXX\n this.opMAXX(inst);\n break;\n case 0x0A: // MULX\n this.opMULX(inst);\n break;\n case 0x0B: // LOG\n this.opLOG(inst);\n break;\n case 0x0C: // EXP\n this.opEXP(inst);\n break;\n case 0x0D: // SOF\n this.opSOF(inst);\n break;\n case 0x0E: // AND\n this.opAND(inst);\n break;\n case 0x0F: // OR\n this.opOR(inst);\n break;\n case 0x10: // XOR\n this.opXOR(inst);\n break;\n case 0x11: // SKP\n skip = this.opSKP(inst);\n break;\n case 0x12: // WLDS / WLDR\n // Check bit 30 to distinguish WLDS (0) and WLDR (1)\n if ((inst >>> 30) & 1) {\n this.opWLDR(inst);\n }\n else {\n this.opWLDS(inst);\n }\n break;\n case 0x13: // JAM\n this.opJAM(inst);\n break;\n case 0x14: // CHO\n this.opCHO(inst);\n break;\n default:\n // console.warn(`Unknown opcode: ${opcode.toString(16)}`);\n break;\n }\n return skip;\n }\n // --- Opcode Implementations ---\n opRDA(inst) {\n // ... (existing comments)\n const addr = (inst >>> 5) & 0x7FFF;\n const coeff = this.decodeS1_9((inst >>> 21) & 0x7FF);\n // Address is relative to current delay pointer in circular buffer\n const readAddr = (this.delayPointer + addr) & this.delayMask;\n const val = this.delayRam[readAddr];\n this.traceDelayAddr = readAddr;\n this.traceDelayOffset = addr;\n this.traceDelayOp = 'R';\n this.traceDelayValue = val;\n this.currentReadOffsets.add(addr);\n this.lr = val;\n this.acc += val * coeff;\n this.acc = this.saturate(this.acc);\n }\n opWRA(inst) {\n // WRA addr, coeff\n // Delay[addr] = ACC; ACC = ACC * coeff\n // Encoding: CCCCCCCCCCCAAAAAAAAAAAAAAAA00010\n const addr = (inst >>> 5) & 0x7FFF;\n const coeff = this.decodeS1_9((inst >>> 21) & 0x7FF);\n const writeAddr = (this.delayPointer + addr) & this.delayMask;\n this.traceDelayAddr = writeAddr;\n this.traceDelayOffset = addr;\n this.traceDelayOp = 'W';\n this.traceDelayValue = this.acc;\n this.delayRam[writeAddr] = this.acc;\n this.acc *= coeff;\n this.acc = this.saturate(this.acc);\n }\n opWRAP(inst) {\n // WRAP addr, coeff\n // Delay[addr] = ACC; ACC = ACC * coeff + LR\n // Note: Pointer decrement happens at end of step, not here.\n // Encoding: CCCCCCCCCCCAAAAAAAAAAAAAAAA00011\n const addr = (inst >>> 5) & 0x7FFF;\n const coeff = this.decodeS1_9((inst >>> 21) & 0x7FF);\n const writeAddr = (this.delayPointer + addr) & this.delayMask;\n this.traceDelayAddr = writeAddr;\n this.traceDelayOffset = addr;\n this.traceDelayOp = 'W';\n this.traceDelayValue = this.acc;\n this.delayRam[writeAddr] = this.acc;\n // ACC = ACC * coeff + LR\n this.acc = this.acc * coeff + this.lr;\n this.acc = this.saturate(this.acc);\n }\n opRDAX(inst) {\n // RDAX reg, coeff\n // ACC = ACC + (Reg[reg] * coeff)\n // Encoding: CCCCCCCCCCCCCCCC00000AAAAAA00100\n const reg = (inst >>> 5) & 0x3F;\n const coeff = this.decodeS1_14((inst >>> 16) & 0xFFFF);\n const val = this.registers[reg];\n this.acc += val * coeff;\n this.acc = this.saturate(this.acc);\n }\n opWRAX(inst) {\n // WRAX reg, coeff\n // Reg[reg] = ACC; ACC = ACC * coeff\n // Encoding: CCCCCCCCCCCCCCCC00000AAAAAA00110\n const reg = (inst >>> 5) & 0x3F;\n const coeff = this.decodeS1_14((inst >>> 16) & 0xFFFF);\n this.registers[reg] = this.acc;\n this.acc *= coeff;\n this.acc = this.saturate(this.acc);\n }\n opSOF(inst) {\n // SOF c, d\n // ACC = ACC * c + d\n // Encoding: CCCCCCCCCCCCCCCCDDDDDDDDDDD01101\n const d = this.decodeS_10((inst >>> 5) & 0x7FF);\n const c = this.decodeS1_14((inst >>> 16) & 0xFFFF);\n this.acc = this.acc * c + d;\n this.acc = this.saturate(this.acc);\n }\n opRMPA(inst) {\n // RMPA coeff\n // Read memory pointer. ADDR_PTR is mapped to REG24.\n // Encoding: CCCCCCCCCCC000000000001100000001 (or similar, coeff is top)\n const coeff = this.decodeS1_9((inst >>> 21) & 0x7FF);\n // Hardware truncates toward zero when converting the S.23 ADDR_PTR\n // to an integer offset. Math.floor would round tiny negative values\n // (~1e-20) to -1 and produce a parasitic read at delayPointer - 1,\n // which on this FV-1 architecture coincides with the chorus block's\n // simple_audio_output write from ~67 ms ago — creating a near-unity-\n // gain loop that takes hundreds of seconds to decay.\n const ptr = Math.trunc(this.registers[24] * this.delaySize);\n const readAddr = (this.delayPointer + ptr) & this.delayMask;\n const val = this.delayRam[readAddr];\n this.traceDelayAddr = readAddr;\n this.traceDelayOffset = ptr;\n this.traceDelayOp = 'R';\n this.traceDelayValue = val;\n this.currentReadOffsets.add(ptr);\n this.lr = val;\n this.acc += val * coeff;\n this.acc = this.saturate(this.acc);\n }\n opMULX(inst) {\n // Encoding: 000000000000000000000AAAAAA01010\n const reg = (inst >>> 5) & 0x3F;\n this.acc = this.acc * this.registers[reg];\n this.acc = this.saturate(this.acc);\n }\n opLOG(inst) {\n // ACC = log2(|ACC|) * coeff + d\n // Encoding: CCCCCCCCCCCCCCCCDDDDDDDDDDD01011\n const d = this.decodeS4_6((inst >>> 5) & 0x7FF);\n const coeff = this.decodeS1_14((inst >>> 16) & 0xFFFF);\n const val = Math.abs(this.acc);\n let logVal;\n if (val > 1.52587890625e-5) { // 2^-16, approx 96dB limit\n logVal = Math.log2(val);\n }\n else {\n logVal = -16.0;\n }\n // Result is in S4.19 format, so we divide by 16 to keep it in our S.23 float space\n this.acc = (logVal * coeff + d) / 16.0;\n this.acc = this.saturate(this.acc);\n }\n opEXP(inst) {\n // ACC = 2^ACC\n // Encoding: CCCCCCCCCCCCCCCCDDDDDDDDDDD01100\n const d = this.decodeS_10((inst >>> 5) & 0x7FF);\n const coeff = this.decodeS1_14((inst >>> 16) & 0xFFFF);\n const valS419 = this.acc * 16.0;\n // Result is linear S.23, which naturally fits our -1..1 float range\n this.acc = Math.pow(2, valS419) * coeff + d;\n this.acc = this.saturate(this.acc);\n }\n opRDFX(inst) {\n // RDFX reg, coeff\n // ACC = (REG[reg] - ACC) * coeff + REG[reg]\n // Encoding: CCCCCCCCCCCCCCCC00000AAAAAA00101\n const reg = (inst >>> 5) & 0x3F;\n const coeff = this.decodeS1_14((inst >>> 16) & 0xFFFF);\n const rx = this.registers[reg];\n this.acc = (this.acc - rx) * coeff + rx;\n this.acc = this.saturate(this.acc);\n }\n opMAXX(inst) {\n // Encoding: CCCCCCCCCCCCCCCC00000AAAAAA01001\n const reg = (inst >>> 5) & 0x3F;\n const coeff = this.decodeS1_14((inst >>> 16) & 0xFFFF);\n const a = Math.abs(this.acc);\n const b = Math.abs(this.registers[reg] * coeff);\n // MAXX result is always the magnitude (absolute value)\n this.acc = Math.max(a, b);\n this.acc = this.saturate(this.acc);\n }\n opSKP(inst) {\n // SKP condition, n\n // Encoding: CCCCCNNNNNN000000000000000010001\n const n = (inst >>> 21) & 0x3F;\n const flags = inst & 0xF8000000;\n let conditionMet = false;\n // Flags: RUN=0x80000000, ZRC=0x40000000, ZRO=0x20000000, GEZ=0x10000000, NEG=0x08000000\n if ((flags & 0x08000000) && this.acc < 0)\n conditionMet = true; // NEG\n if ((flags & 0x10000000) && this.acc >= 0)\n conditionMet = true; // GEZ\n if ((flags & 0x20000000) && this.acc === 0)\n conditionMet = true; // ZRO\n // ZRC (Zero Crossing) requires previous acc\n if ((flags & 0x40000000) && (this.acc * this.pacc < 0))\n conditionMet = true;\n // RUN flag: Skip if NOT first run\n if ((flags & 0x80000000) && !this.firstRun)\n conditionMet = true;\n return conditionMet ? n : 0;\n }\n opWRLX(inst) {\n // WRLX reg, coeff\n // Reg[reg] = ACC; ACC = (PACC - ACC) * coeff + PACC\n // Encoding: CCCCCCCCCCCCCCCC00000AAAAAA01000\n const reg = (inst >>> 5) & 0x3F;\n const coeff = this.decodeS1_14((inst >>> 16) & 0xFFFF);\n this.registers[reg] = this.acc;\n this.acc = (this.pacc - this.acc) * coeff + this.pacc;\n this.acc = this.saturate(this.acc);\n }\n opWRHX(inst) {\n // WRHX reg, coeff\n // Reg[reg] = ACC; ACC = PACC + ACC * coeff\n // Encoding: CCCCCCCCCCCCCCCC00000AAAAAA00111\n const reg = (inst >>> 5) & 0x3F;\n const coeff = this.decodeS1_14((inst >>> 16) & 0xFFFF);\n this.registers[reg] = this.acc;\n this.acc = this.pacc + this.acc * coeff;\n this.acc = this.saturate(this.acc);\n }\n opAND(inst) {\n // AND mask\n // Encoding: MMMMMMMMMMMMMMMMMMMMMMMM00001110\n const mask = (inst >>> 8) & 0xFFFFFF;\n // Convert ACC to 24-bit int, apply mask, convert back\n let iAcc = Math.floor(this.acc * 8388608.0); // 2^23\n iAcc &= mask;\n this.acc = iAcc / 8388608.0;\n }\n opOR(inst) {\n // OR mask\n // Encoding: MMMMMMMMMMMMMMMMMMMMMMMM00001111\n const mask = (inst >>> 8) & 0xFFFFFF;\n let iAcc = Math.floor(this.acc * 8388608.0);\n iAcc |= mask;\n this.acc = iAcc / 8388608.0;\n }\n opXOR(inst) {\n // XOR mask\n // Encoding: MMMMMMMMMMMMMMMMMMMMMMMM00010000\n const mask = (inst >>> 8) & 0xFFFFFF;\n let iAcc = Math.floor(this.acc * 8388608.0);\n iAcc ^= mask;\n this.acc = iAcc / 8388608.0;\n }\n opJAM(inst) {\n // JAM lfo\n // Encoding: 0000000000000000000000001N010011\n const lfo = (inst >>> 6) & 0x3; // 0=RMP0, 1=RMP1\n if (lfo === 0)\n this.rmp0 = 0;\n else if (lfo === 1)\n this.rmp1 = 0;\n }\n opWLDS(inst) {\n // WLDS lfo, freq, amp\n const lfoSelect = (inst >>> 29) & 0x1;\n const freqRaw = (inst >>> 20) & 0x1FF;\n const ampRaw = (inst >>> 5) & 0x7FFF;\n // Freq is an unsigned 9-bit value (0 to 511), amp is unsigned 15-bit (0 to 32767).\n // The FV-1 hardware uses power-of-2 fixed-point arithmetic (bit shifts),\n // so amplitude is divided by 2^15=32768, not 32767. Using 32767 causes the\n // computed delay address range to slightly exceed memory block boundaries.\n const f = freqRaw / 512.0;\n const a = ampRaw / 32768.0;\n if (lfoSelect === 0) {\n this.sin0_rate = f;\n this.sin0_range = a;\n this.registers[0] = f; // SIN0_RATE (reg0)\n this.registers[1] = a; // SIN0_RANGE (reg1)\n this.cos0 = -1.0;\n this.sin0 = 0.0;\n }\n else {\n this.sin1_rate = f;\n this.sin1_range = a;\n this.registers[2] = f; // SIN1_RATE (reg2)\n this.registers[3] = a; // SIN1_RANGE (reg3)\n this.cos1 = -1.0;\n this.sin1 = 0.0;\n }\n }\n opWLDR(inst) {\n // WLDR lfo, freq, amp\n // Encoding: 01NFFFFFFFFFFFFFFFF000000AA10010\n const lfoSelect = (inst >>> 29) & 0x1; // 0=RMP0, 1=RMP1\n // Freq is signed 16-bit\n let freq = (inst >>> 13) & 0xFFFF;\n if (freq & 0x8000)\n freq -= 65536;\n // Amp is a 2-bit code\n const ampCode = (inst >>> 5) & 0x3;\n const amp = 4096 >> ampCode; // 0->4096, 1->2048, 2->1024, 3->512\n // C logic: rate = f/16384.0, range = a/8192.0\n const f_val = freq / 16384.0;\n const a_val = amp / 8192.0;\n if (lfoSelect === 0) {\n this.rmp0_rate = f_val;\n this.rmp0_range = a_val;\n this.registers[4] = f_val; // RMP0_RATE (reg4)\n this.registers[5] = a_val; // RMP0_RANGE (reg5)\n this.rmp0 = 0.0;\n }\n else {\n this.rmp1_rate = f_val;\n this.rmp1_range = a_val;\n this.registers[6] = f_val; // RMP1_RATE (reg6)\n this.registers[7] = a_val; // RMP1_RANGE (reg7)\n this.rmp1 = 0.0;\n }\n }\n getLfoVal(flags, lfoSelect) {\n if (lfoSelect === 0) {\n return (flags & 1) ? this.cos0 : this.sin0;\n }\n else if (lfoSelect === 1) {\n return (flags & 1) ? this.cos1 : this.sin1;\n }\n else if (lfoSelect === 2) {\n return this.rmp0;\n }\n else {\n return this.rmp1;\n }\n }\n getLfoRange(lfoSelect) {\n if (lfoSelect === 0)\n return this.sin0_range;\n if (lfoSelect === 1)\n return this.sin1_range;\n if (lfoSelect === 2)\n return this.rmp0_range;\n return this.rmp1_range;\n }\n opCHO(inst) {\n const mode = (inst >>> 30) & 0x3;\n if (mode === 0) {\n this.opCHO_RDA(inst);\n }\n else if (mode === 2) {\n this.opCHO_SOF(inst);\n }\n else if (mode === 3) {\n this.opCHO_RDAL(inst);\n }\n }\n opCHO_RDA(inst) {\n const flags = (inst >>> 24) & 0x3F;\n const lfoSelect = (inst >>> 21) & 0x3;\n const offset = (inst >>> 5) & 0x7FFF;\n const lfoIn = this.getLfoVal(flags, lfoSelect);\n let range = this.getLfoRange(lfoSelect);\n range *= 8192.0;\n if (flags & 2) { // cho_reg\n this.lfo = lfoIn;\n }\n let v = this.lfo;\n if (flags & 16) { // cho_rptr2\n v += 0.5;\n if (v >= 1.0)\n v -= 1.0;\n }\n if (flags & 8) { // cho_compa\n v = -v;\n }\n let index;\n let c;\n if (flags & 32) { // cho_na\n index = offset;\n c = Math.min(v, 1.0 - v);\n c = Math.max(0.0, Math.min(1.0, 4.0 * c - 0.5));\n }\n else {\n // Match the FV-1 / reference C: combine v*range with offset BEFORE\n // flooring. Separating them (e.g. trunc(v*range) + offset) gives the\n // wrong integer index when v*range is negative, because Math.trunc\n // rounds toward zero. Linear interpolation needs floor semantics.\n const addr = v * range + offset;\n index = Math.floor(addr);\n c = addr - index;\n }\n const readAddr = (this.delayPointer + index) & this.delayMask;\n this.lr = this.delayRam[readAddr];\n this.traceDelayAddr = readAddr;\n this.traceDelayOffset = index;\n this.traceDelayOp = 'R';\n this.traceDelayValue = this.lr;\n this.currentReadOffsets.add(index);\n if (flags & 4) { // cho_compc\n c = 1.0 - c;\n }\n this.acc += this.lr * c;\n this.acc = this.saturate(this.acc);\n }\n opCHO_SOF(inst) {\n const flags = (inst >>> 24) & 0x3F;\n const lfoSelect = (inst >>> 21) & 0x3;\n const coeffRaw = (inst >>> 5) & 0xFFFF;\n const coeff = this.decodeS_15(coeffRaw);\n const lfoIn = this.getLfoVal(flags, lfoSelect);\n const range = this.getLfoRange(lfoSelect);\n if (flags & 2) { // cho_reg\n this.lfo = lfoIn;\n }\n let v = this.lfo;\n if (flags & 32) { // cho_na\n v = Math.min(v, 1.0 - v);\n v = Math.max(0.0, Math.min(1.0, 4.0 * v - 0.5));\n }\n else {\n v *= range;\n }\n if (flags & 4) { // cho_compc\n v = 1.0 - v;\n }\n this.acc = v * this.acc + coeff;\n this.acc = this.saturate(this.acc);\n }\n opCHO_RDAL(inst) {\n const flags = (inst >>> 24) & 0x3F;\n const lfoSelect = (inst >>> 21) & 0x3;\n const lfoIn = this.getLfoVal(flags, lfoSelect);\n this.acc = lfoIn;\n this.acc = this.saturate(this.acc);\n }\n // --- Debugging / State Access ---\n getPC() {\n return this.pc;\n }\n getProgSize() {\n return this.progSize;\n }\n setPC(pc) {\n this.pc = Math.max(0, Math.min(this.progSize - 1, pc));\n }\n setAcc(val) {\n this.acc = this.saturate(val);\n }\n setPacc(val) {\n this.pacc = this.saturate(val);\n }\n /**\n * Sets a register value with hardware-accurate saturation and quantization.\n * @param idx Register index (0-63)\n * @param val Raw value (float)\n */\n setRegister(idx, val) {\n if (idx < 0 || idx >= (32 + this.regCount))\n return;\n // POT registers (16, 17, 18) are 10-bit quantized 0..1\n if (idx >= 16 && idx <= 18) {\n val = Math.floor(Math.max(0, Math.min(0.9999999, val)) * 1024) / 1024;\n }\n else {\n // Other registers (ADC, DAC, User) are S.23 saturated\n val = this.saturate(val);\n }\n this.registers[idx] = val;\n }\n /**\n * Evaluates a string expression (register name, symbol, memory suffix).\n * @returns { result: string, value: number } or null\n */\n evaluateExpression(expr) {\n let expression = expr.trim().toUpperCase();\n // Handle suffixes ^ and #\n let suffix = \"\";\n if (expression.endsWith(\"^\")) {\n suffix = \"^\";\n expression = expression.slice(0, -1);\n }\n else if (expression.endsWith(\"#\")) {\n suffix = \"#\";\n expression = expression.slice(0, -1);\n }\n // 1. Check if it's a register name\n const state = this.getState();\n if (suffix === \"\" && state.registers[expression] !== undefined) {\n return { label: expression, value: state.registers[expression] };\n }\n // 2. Check if it's ACC/PACC\n if (suffix === \"\" && expression === \"ACC\") {\n return { label: \"ACC\", value: this.acc };\n }\n if (suffix === \"\" && expression === \"PACC\") {\n return { label: \"PACC\", value: this.pacc };\n }\n // 3. Check symbols (EQU)\n const sym = this.symbols.find(s => s.name.toUpperCase() === expression);\n if (sym && suffix === \"\") {\n const addr = parseInt(sym.value);\n if (!isNaN(addr) && addr >= 0 && addr <= 63) {\n return { label: `REG[${addr}] (${sym.name})`, value: this.registers[addr] };\n }\n }\n // 4. Check memories (MEM)\n const mem = this.memories.find(m => m.name.toUpperCase() === expression);\n if (mem && mem.start !== undefined) {\n let addr = mem.start;\n let typeLabel = \"\";\n if (suffix === \"^\") {\n addr = FV1Assembler.getMiddleAddr(mem.start, mem.size);\n typeLabel = \" (Middle)\";\n }\n else if (suffix === \"#\") {\n addr = FV1Assembler.getEndAddr(mem.start, mem.size, this.fv1AsmMemBug);\n typeLabel = \" (End)\";\n }\n if (addr >= 0 && addr < this.delaySize) {\n return { label: `MEM[${addr}] (${mem.name}${typeLabel})`, value: this.delayRam[addr] };\n }\n }\n // 5. Check DELAY[idx]\n if (suffix === \"\") {\n const delayMatch = expression.match(/^DELAY\\[(\\d+)\\]$/);\n if (delayMatch) {\n const idx = parseInt(delayMatch[1]);\n if (idx >= 0 && idx < this.delaySize) {\n return { label: `DELAY[${idx}]`, value: this.delayRam[idx] };\n }\n }\n }\n return null;\n }\n getState() {\n return {\n pc: this.pc,\n acc: this.acc,\n pacc: this.pacc,\n lr: this.lr,\n lfo: this.lfo,\n // Official Register Naming\n registers: Object.fromEntries(Array.from({ length: 32 + this.regCount }, (_, i) => {\n let name = `[${i}]`;\n if (i === 0)\n name = \"SIN0_RATE\";\n else if (i === 1)\n name = \"SIN0_RANGE\";\n else if (i === 2)\n name = \"SIN1_RATE\";\n else if (i === 3)\n name = \"SIN1_RANGE\";\n else if (i === 4)\n name = \"RMP0_RATE\";\n else if (i === 5)\n name = \"RMP0_RANGE\";\n else if (i === 6)\n name = \"RMP1_RATE\";\n else if (i === 7)\n name = \"RMP1_RANGE\";\n else if (i === 8)\n name = \"SIN0\";\n else if (i === 9)\n name = \"COS0\";\n else if (i === 10)\n name = \"SIN1\";\n else if (i === 11)\n name = \"COS1\";\n else if (i === 12)\n name = \"RMP0\";\n else if (i === 13)\n name = \"RMP1\";\n else if (i === 16)\n name = \"POT0\";\n else if (i === 17)\n name = \"POT1\";\n else if (i === 18)\n name = \"POT2\";\n else if (i === 20)\n name = \"ADCL\";\n else if (i === 21)\n name = \"ADCR\";\n else if (i === 22)\n name = \"DACL\";\n else if (i === 23)\n name = \"DACR\";\n else if (i === 24)\n name = \"ADDR_PTR\";\n else if (i >= 32 && i <= 63)\n name = `REG${i - 32}`;\n return [name, this.registers[i]];\n })),\n // Flags\n flags: {\n RUN: this.firstRun,\n ZRC: (this.acc * this.pacc < 0),\n ZRO: (this.acc === 0),\n GEZ: (this.acc >= 0),\n NEG: (this.acc < 0)\n },\n // LFO Internal positions\n lfoState: {\n sin0: this.sin0, cos0: this.cos0,\n sin1: this.sin1, cos1: this.cos1,\n rmp0: this.rmp0, rmp1: this.rmp1\n }\n };\n }\n getCycleCount() {\n return this.cycleCount;\n }\n getReadOffsets() {\n return Array.from(this.currentReadOffsets);\n }\n getRegisters() {\n return this.registers;\n }\n updateLFOs() {\n // Sync internal LFO modulations explicitly modified by WRAX or WRHX\n this.sin0_rate = this.registers[0];\n this.sin0_range = this.registers[1];\n this.sin1_rate = this.registers[2];\n this.sin1_range = this.registers[3];\n this.rmp0_rate = this.registers[4];\n this.rmp0_range = this.registers[5];\n this.rmp1_rate = this.registers[6];\n this.rmp1_range = this.registers[7];\n // C logic update_rmp0/1\n this.rmp0 -= this.rmp0_rate * (1.0 / 4096.0);\n while (this.rmp0 >= 1.0)\n this.rmp0 -= 1.0;\n while (this.rmp0 < 0.0)\n this.rmp0 += 1.0;\n this.rmp1 -= this.rmp1_rate * (1.0 / 4096.0);\n while (this.rmp1 >= 1.0)\n this.rmp1 -= 1.0;\n while (this.rmp1 < 0.0)\n this.rmp1 += 1.0;\n // SIN LFO update using coupled-form oscillator.\n // The FV-1 hardware updates cos first, then uses the updated cos for sin.\n // Clamp to [-1.0, MAX_ACC] to prevent float drift from exceeding the\n // FV-1's 24-bit fixed-point register range.\n const x0 = this.sin0_rate * (1.0 / 256.0);\n this.cos0 += x0 * this.sin0;\n this.sin0 -= x0 * this.cos0;\n this.sin0 = Math.max(FV1Simulator.MIN_ACC, Math.min(FV1Simulator.MAX_ACC, this.sin0));\n this.cos0 = Math.max(FV1Simulator.MIN_ACC, Math.min(FV1Simulator.MAX_ACC, this.cos0));\n const x1 = this.sin1_rate * (1.0 / 256.0);\n this.cos1 += x1 * this.sin1;\n this.sin1 -= x1 * this.cos1;\n this.sin1 = Math.max(FV1Simulator.MIN_ACC, Math.min(FV1Simulator.MAX_ACC, this.sin1));\n this.cos1 = Math.max(FV1Simulator.MIN_ACC, Math.min(FV1Simulator.MAX_ACC, this.cos1));\n }\n updateStateRegisters() {\n // ONLY update accumulators here! Rate/Range is dictated by the program loop!\n // Writing registers[0..7] here would explicitly overwrite mid-frame WRAX modulations!\n // LFO State Accumulators\n this.registers[8] = this.sin0;\n this.registers[9] = this.cos0;\n this.registers[10] = this.sin1;\n this.registers[11] = this.cos1;\n this.registers[12] = this.rmp0;\n this.registers[13] = this.rmp1;\n }\n getDelayRam() {\n return this.delayRam;\n }\n // --- Helpers ---\n decodeS1_14(raw) {\n // 16 bits: 1 sign, 1 integer, 14 fractional\n if (raw & 0x8000)\n return (raw - 0x10000) / 16384.0;\n return raw / 16384.0;\n }\n decodeS1_9(raw) {\n // 11 bits: 1 sign, 1 integer, 9 fractional\n if (raw & 0x400)\n return (raw - 0x800) / 512.0;\n return raw / 512.0;\n }\n decodeS_10(raw) {\n // 11 bits: 1 sign, 0 integer, 10 fractional\n if (raw & 0x400)\n return (raw - 0x800) / 1024.0;\n return raw / 1024.0;\n }\n decodeS4_6(raw) {\n // 11 bits: 1 sign, 4 integer, 6 fractional\n if (raw & 0x400)\n return (raw - 0x800) / 64.0;\n return raw / 64.0;\n }\n decodeS_15(raw) {\n // 16 bits: 1 sign, 0 integer, 15 fractional\n if (raw & 0x8000)\n return (raw - 0x10000) / 32768.0;\n return raw / 32768.0;\n }\n saturate(val) {\n if (val > FV1Simulator.MAX_ACC)\n return FV1Simulator.MAX_ACC;\n if (val < FV1Simulator.MIN_ACC)\n return FV1Simulator.MIN_ACC;\n return val;\n }\n /**\n * Enable trace logging with a streaming writer callback.\n * Each row is emitted immediately via the writer — nothing is stored in memory.\n * @param writer Callback that receives each CSV row (including header).\n * @param maxCycles Maximum number of sample cycles to log (0 = unlimited).\n * @param onComplete Optional callback when trace auto-completes.\n */\n enableTrace(writer, maxCycles = 0, onComplete) {\n this.traceEnabled = true;\n this.traceWriter = writer;\n this.traceMaxCycles = maxCycles;\n this.traceCycle = 0;\n this.traceRowCount = 0;\n this.traceOnComplete = onComplete || null;\n // Emit CSV Header immediately (Reduced set for delay debugging)\n writer(`cycle,pc,opcode,delay_op,delay_offset,delay_addr,delay_ptr`);\n console.log(`[FV1 Trace] Logging enabled (maxCycles=${maxCycles || 'unlimited'})`);\n }\n /**\n * Disable trace logging.\n */\n disableTrace() {\n this.traceEnabled = false;\n this.traceWriter = null;\n console.log(`[FV1 Trace] Logging disabled. ${this.traceRowCount} rows written.`);\n }\n /**\n * Returns whether trace logging is currently active.\n */\n isTraceEnabled() {\n return this.traceEnabled;\n }\n /**\n * Returns the number of trace rows emitted so far.\n */\n getTraceRowCount() {\n return this.traceRowCount;\n }\n /**\n * Called at end-of-frame to advance the trace cycle counter.\n * If maxCycles is reached, trace is automatically disabled.\n */\n advanceTraceCycle() {\n if (!this.traceEnabled)\n return;\n this.traceCycle++;\n if (this.traceMaxCycles > 0 && this.traceCycle >= this.traceMaxCycles) {\n const onComplete = this.traceOnComplete;\n this.disableTrace();\n if (onComplete)\n onComplete();\n }\n }\n logTrace(pc, opcode, inst, accBefore) {\n if (!this.traceWriter)\n return;\n // FILTER: Only log delay memory operations\n if (this.traceDelayOp === '')\n return;\n const opName = FV1Simulator.OPCODE_NAMES[opcode] || `?${opcode.toString(16)}`;\n // Resolve CHO sub-type\n let fullOpName = opName;\n if (opcode === 0x14) {\n const mode = (inst >>> 30) & 0x3;\n if (mode === 0)\n fullOpName = 'CHO_RDA';\n else if (mode === 2) {\n // CHO_SOF does not access delay RAM, so we filter it out\n return;\n }\n else if (mode === 3)\n fullOpName = 'CHO_RDAL';\n }\n else if (opcode === 0x12) {\n // WLDS/WLDR do not access delay RAM directly in a way we track here\n return;\n }\n const row = `${this.traceCycle},${pc},${fullOpName},` +\n `${this.traceDelayOp},${this.traceDelayOp !== '' ? this.traceDelayOffset : ''},${this.traceDelayAddr >= 0 ? this.traceDelayAddr : ''},${this.delayPointer}`;\n this.traceWriter(row);\n this.traceRowCount++;\n }\n}\nFV1Simulator.MAX_ACC = 1.0 - (1.0 / 8388608.0); // 24-bit S.23: 1 - 2^-23\nFV1Simulator.MIN_ACC = -FV1Simulator.MAX_ACC; // Symmetrically bound to prevent limits bias\n// --- Trace Logging System ---\nFV1Simulator.OPCODE_NAMES = {\n 0x00: 'RDA', 0x01: 'RMPA', 0x02: 'WRA', 0x03: 'WRAP',\n 0x04: 'RDAX', 0x05: 'RDFX', 0x06: 'WRAX', 0x07: 'WRHX',\n 0x08: 'WRLX', 0x09: 'MAXX', 0x0A: 'MULX', 0x0B: 'LOG',\n 0x0C: 'EXP', 0x0D: 'SOF', 0x0E: 'AND', 0x0F: 'OR',\n 0x10: 'XOR', 0x11: 'SKP', 0x12: 'WLDx', 0x13: 'JAM',\n 0x14: 'CHO'\n};\n//# sourceMappingURL=FV1Simulator.js.map","import { FV1Simulator } from '@audiofab-io/fv1-core'\n\ntype ChannelMode = 'mono' | 'stereo'\n\nclass FV1Processor extends AudioWorkletProcessor {\n private simulator = new FV1Simulator()\n private pot = [0.5, 0.5, 0.5]\n private bypassed = false\n /** Mono emulates the current Easy Spin hardware (only the left DAC is wired\n * to both jack tips). Stereo plays the FV-1's native left/right outputs. */\n private channelMode: ChannelMode = 'mono'\n\n /** EMA-smoothed time spent inside processBlock(), in microseconds. Updated\n * only when actually processing (not while bypassed), and posted to the\n * main thread on a slower cadence than the audio rate to keep React\n * re-renders cheap. */\n private blockTimeUsEma = 0\n private blocksSinceReport = 0\n private static readonly BLOCK_TIME_REPORT_INTERVAL = 24\n\n constructor() {\n super()\n this.port.onmessage = ({ data }) => {\n switch (data.type) {\n case 'loadProgram':\n this.simulator.loadProgram(new Uint32Array(data.machineCode))\n break\n case 'setPot':\n this.pot[data.index] = data.value\n break\n case 'bypass':\n this.bypassed = data.active\n break\n case 'setChannelMode':\n this.channelMode = data.mode === 'stereo' ? 'stereo' : 'mono'\n break\n }\n }\n }\n\n process(inputs: Float32Array[][], outputs: Float32Array[][]): boolean {\n const input = inputs[0]\n const output = outputs[0]\n if (!input?.length || !output?.length) return true\n\n const inL = input[0]\n const inR = input[1] ?? inL\n const outL = output[0]\n const outR = output[1] ?? outL\n\n if (this.bypassed) {\n outL.set(inL)\n if (output[1]) outR.set(inR)\n return true\n }\n\n const t0 = performance.now()\n this.simulator.processBlock(inL, inR, outL, outR,\n this.pot[0], this.pot[1], this.pot[2])\n const elapsedUs = (performance.now() - t0) * 1000\n\n // EMA on the *active* processing time only (skipped while bypassed). The\n // first sample seeds the EMA so the displayed value converges quickly\n // instead of crawling up from zero. α = 0.05 gives a ~20-block (~80 ms\n // at 32 kHz / 128-sample blocks) effective time constant — smooth\n // enough to read, responsive enough to see load swings.\n this.blockTimeUsEma = this.blockTimeUsEma === 0\n ? elapsedUs\n : this.blockTimeUsEma * 0.95 + elapsedUs * 0.05\n\n // Mono: mirror the left (FV-1 DACL) output to the right channel so the\n // simulator matches the current mono pedal, where only DACL drives the jack.\n if (this.channelMode === 'mono' && output[1]) {\n outR.set(outL)\n }\n\n if (++this.blocksSinceReport >= FV1Processor.BLOCK_TIME_REPORT_INTERVAL) {\n this.blocksSinceReport = 0\n this.port.postMessage({ type: 'blockTime', us: this.blockTimeUsEma })\n }\n return true\n }\n}\n\nregisterProcessor('fv1-processor', FV1Processor)\n"],"x_google_ignoreList":[0,1,2,3],"mappings":"YAAA,IAAa,EAAb,cAAiC,KAAM,CACnC,YAAY,EAAS,EAAM,EAAQ,CAC/B,MAAM,EAAQ,CACd,KAAK,KAAO,EACZ,KAAK,OAAS,EACd,KAAK,KAAO,gBAGT,GACV,SAAU,EAAW,CAClB,EAAU,EAAU,WAAgB,GAAK,aACzC,EAAU,EAAU,OAAY,GAAK,SACrC,EAAU,EAAU,SAAc,GAAK,WACvC,EAAU,EAAU,UAAe,GAAK,YACxC,EAAU,EAAU,SAAc,GAAK,WACvC,EAAU,EAAU,MAAW,GAAK,QACpC,EAAU,EAAU,MAAW,GAAK,QACpC,EAAU,EAAU,QAAa,GAAK,UACtC,EAAU,EAAU,IAAS,GAAK,MAClC,EAAU,EAAU,OAAY,GAAK,SACrC,EAAU,EAAU,OAAY,IAAM,WACvC,AAAc,IAAY,EAAE,CAAE,CACjC,IAAa,EAAb,KAAmB,CACf,YAAY,EAAQ,CAChB,KAAK,OAAS,EACd,KAAK,IAAM,EACX,KAAK,KAAO,EACZ,KAAK,OAAS,EAElB,MAAO,CACH,OAAO,KAAK,OAAO,KAAK,MAAQ,GAEpC,SAAU,CACN,IAAM,EAAO,KAAK,MAAM,CASxB,MARA,MAAK,MACD,IAAS;GACT,KAAK,OACL,KAAK,OAAS,GAGd,KAAK,SAEF,EAEX,UAAW,CACP,IAAM,EAAS,EAAE,CACjB,KAAO,KAAK,IAAM,KAAK,OAAO,QAAQ,CAClC,IAAM,EAAO,KAAK,MAAM,CACxB,GAAI,KAAK,KAAK,EAAK,EAAI,IAAS;EAC5B,KAAK,SAAS,SAET,IAAS,IAEd,KAAO,KAAK,MAAM,GAAK;GAAQ,KAAK,IAAM,KAAK,OAAO,QAClD,KAAK,SAAS,MAGb,IAAS;GACd,EAAO,KAAK,CAAE,KAAM,EAAU,QAAS,MAAO;EAAM,KAAM,KAAK,KAAM,OAAQ,KAAK,OAAQ,CAAC,CAC3F,KAAK,SAAS,EAET,IAAS,KACd,EAAO,KAAK,CAAE,KAAM,EAAU,MAAO,MAAO,IAAK,KAAM,KAAK,KAAM,OAAQ,KAAK,OAAQ,CAAC,CACxF,KAAK,SAAS,EAET,IAAS,KACd,EAAO,KAAK,CAAE,KAAM,EAAU,MAAO,MAAO,IAAK,KAAM,KAAK,KAAM,OAAQ,KAAK,OAAQ,CAAC,CACxF,KAAK,SAAS,EAET,IAAS,KACd,EAAO,KAAK,CAAE,KAAM,EAAU,OAAQ,MAAO,IAAK,KAAM,KAAK,KAAM,OAAQ,KAAK,OAAQ,CAAC,CACzF,KAAK,SAAS,EAET,IAAS,KACd,EAAO,KAAK,CAAE,KAAM,EAAU,OAAQ,MAAO,IAAK,KAAM,KAAK,KAAM,OAAQ,KAAK,OAAQ,CAAC,CACzF,KAAK,SAAS,EAET,YAAY,KAAK,EAAK,CAC3B,EAAO,KAAK,KAAK,gBAAgB,CAAC,CAE7B,SAAS,KAAK,EAAK,EAAI,IAAS,KAAO,IAAS,IACrD,EAAO,KAAK,KAAK,YAAY,CAAC,CAEzB,eAAe,KAAK,EAAK,CAC9B,EAAO,KAAK,CAAE,KAAM,EAAU,SAAU,MAAO,KAAK,SAAS,CAAE,KAAM,KAAK,KAAM,OAAQ,KAAK,OAAQ,CAAC,CAItG,KAAK,SAAS,CAItB,OADA,EAAO,KAAK,CAAE,KAAM,EAAU,IAAK,MAAO,GAAI,KAAM,KAAK,KAAM,OAAQ,KAAK,OAAQ,CAAC,CAC9E,EAEX,gBAAiB,CACb,IAAI,EAAQ,GACN,EAAY,KAAK,KACjB,EAAW,KAAK,OACtB,KAAO,kBAAkB,KAAK,KAAK,MAAM,CAAC,EACtC,GAAS,KAAK,SAAS,CAE3B,IAAM,EAAQ,EAAM,aAAa,CAMjC,MALI,CAAC,MAAO,MAAM,CAAC,SAAS,EAAM,CACvB,CAAE,KAAM,EAAU,UAAW,MAAO,EAAO,KAAM,EAAW,OAAQ,EAAU,CAIlF,CAAE,KAAM,EAAU,WAAY,MAAO,EAAO,KAAM,EAAW,OAAQ,EAAU,CAE1F,YAAa,CACT,IAAI,EAAQ,GACN,EAAY,KAAK,KACjB,EAAW,KAAK,OACtB,GAAI,KAAK,MAAM,GAAK,IAEhB,IADA,GAAS,KAAK,SAAS,CAChB,cAAc,KAAK,KAAK,MAAM,CAAC,EAClC,GAAS,KAAK,SAAS,SAEtB,KAAK,MAAM,GAAK,IAErB,IADA,GAAS,KAAK,SAAS,CAChB,QAAQ,KAAK,KAAK,MAAM,CAAC,EAC5B,GAAS,KAAK,SAAS,SAEtB,KAAK,MAAM,GAAK,MAAQ,KAAK,OAAO,KAAK,IAAM,IAAM,IAAI,aAAa,GAAK,IAGhF,IAFA,GAAS,KAAK,SAAS,CACvB,GAAS,KAAK,SAAS,CAChB,cAAc,KAAK,KAAK,MAAM,CAAC,EAClC,GAAS,KAAK,SAAS,MAG3B,KAAO,UAAU,KAAK,KAAK,MAAM,CAAC,EAC9B,GAAS,KAAK,SAAS,CAE/B,MAAO,CAAE,KAAM,EAAU,OAAQ,QAAO,KAAM,EAAW,OAAQ,EAAU,GAGtE,EAAb,KAAoB,CAChB,YAAY,EAAQ,CAChB,KAAK,IAAM,EACX,KAAK,OAAS,EAAO,QAAQ,EAAG,IAAM,EAAE,OAAS,EAAU,SAAW,KAAK,kBAAkB,EAAQ,EAAE,CAAC,CAE5G,kBAAkB,EAAQ,EAAO,CAE7B,IAAK,IAAI,EAAI,EAAQ,EAAG,EAAI,EAAO,OAAQ,IACvC,GAAI,EAAO,GAAG,OAAS,EAAU,QAC7B,OAAO,EAAO,GAAG,OAAS,EAAU,IAG5C,MAAO,GAEX,MAAO,CACH,OAAO,KAAK,OAAO,KAAK,MAAQ,CAAE,KAAM,EAAU,IAAK,MAAO,GAAI,KAAM,GAAI,OAAQ,GAAI,CAE5F,SAAU,CACN,OAAO,KAAK,OAAO,KAAK,OAE5B,MAAM,EAAM,CAGR,OAFI,KAAK,MAAM,CAAC,OAAS,EACd,KAAK,SAAS,CAClB,KAEX,OAAQ,CACJ,IAAM,EAAQ,EAAE,CAChB,KAAO,KAAK,MAAM,CAAC,OAAS,EAAU,KAAK,CACvC,IAAM,EAAO,KAAK,gBAAgB,CAIlC,IAHI,GACA,EAAM,KAAK,EAAK,CAEb,KAAK,MAAM,EAAU,QAAQ,IAGxC,OAAO,EAEX,gBAAiB,CACb,IAAM,EAAQ,KAAK,MAAM,CACzB,GAAI,EAAM,OAAS,EAAU,WAAY,CACrC,IAAM,EAAO,KAAK,OAAO,KAAK,IAAM,GAEpC,GAAI,GAAQ,EAAK,OAAS,EAAU,MAAO,CACvC,IAAM,EAAQ,KAAK,SAAS,CAE5B,OADA,KAAK,SAAS,CACP,CAAE,KAAM,QAAS,KAAM,EAAM,MAAO,KAAM,EAAM,KAAM,CAGjE,GAAI,GAAQ,EAAK,OAAS,EAAU,UAAW,CAC3C,IAAM,EAAK,KAAK,SAAS,CACnB,EAAM,KAAK,SAAS,CACpB,EAAO,KAAK,iBAAiB,CACnC,MAAO,CAAE,KAAM,YAAa,KAAM,EAAI,MAAO,WAAY,EAAG,MAAO,WAAY,EAAM,KAAM,EAAI,KAAM,EAG7G,GAAI,EAAM,OAAS,EAAU,UAAW,CACpC,IAAM,EAAM,KAAK,SAAS,CACpB,EAAK,KAAK,MAAM,EAAU,WAAW,CAC3C,GAAI,CAAC,EACD,MAAM,IAAI,EAAY,6BAA6B,EAAI,QAAS,EAAI,KAAM,EAAI,OAAO,CACzF,IAAM,EAAO,KAAK,iBAAiB,CACnC,MAAO,CAAE,KAAM,YAAa,KAAM,EAAI,MAAO,WAAY,EAAG,MAAO,WAAY,EAAM,KAAM,EAAI,KAAM,CAEzG,GAAI,EAAM,OAAS,EAAU,WAAY,CACrC,IAAM,EAAW,KAAK,SAAS,CACzB,EAAW,EAAE,CACnB,GAAI,KAAK,MAAM,CAAC,OAAS,EAAU,SAAW,KAAK,MAAM,CAAC,OAAS,EAAU,IAEzE,IADA,EAAS,KAAK,KAAK,iBAAiB,CAAC,CAC9B,KAAK,MAAM,EAAU,MAAM,EAC9B,EAAS,KAAK,KAAK,iBAAiB,CAAC,CAG7C,MAAO,CAAE,KAAM,cAAe,SAAU,EAAS,MAAO,WAAU,KAAM,EAAS,KAAM,CAG3F,OADA,KAAK,SAAS,CACP,KAEX,iBAAkB,CACd,OAAO,KAAK,cAAc,CAE9B,cAAe,CACX,IAAI,EAAO,KAAK,YAAY,CAC5B,KAAO,KAAK,MAAM,CAAC,OAAS,EAAU,UAAa,CAAC,IAAK,IAAK,IAAI,CAAC,SAAS,KAAK,MAAM,CAAC,MAAM,EAAG,CAC7F,IAAM,EAAW,KAAK,SAAS,CAAC,MAC1B,EAAQ,KAAK,YAAY,CAC/B,EAAO,CAAE,KAAM,SAAU,OAAM,WAAU,QAAO,CAEpD,OAAO,EAEX,YAAa,CACT,IAAI,EAAO,KAAK,eAAe,CAC/B,KAAO,KAAK,MAAM,CAAC,OAAS,EAAU,UAAa,CAAC,IAAK,IAAI,CAAC,SAAS,KAAK,MAAM,CAAC,MAAM,EAAG,CACxF,IAAM,EAAW,KAAK,SAAS,CAAC,MAC1B,EAAQ,KAAK,eAAe,CAClC,EAAO,CAAE,KAAM,SAAU,OAAM,WAAU,QAAO,CAEpD,OAAO,EAEX,eAAgB,CACZ,IAAI,EAAO,KAAK,qBAAqB,CACrC,KAAO,KAAK,MAAM,CAAC,OAAS,EAAU,WAAa,KAAK,MAAM,CAAC,QAAU,KAAO,KAAK,MAAM,CAAC,QAAU,MAAM,CACxG,IAAM,EAAW,KAAK,SAAS,CAAC,MAC1B,EAAQ,KAAK,qBAAqB,CACxC,EAAO,CAAE,KAAM,SAAU,OAAM,WAAU,QAAO,CAEpD,OAAO,EAEX,qBAAsB,CAClB,IAAI,EAAO,KAAK,cAAc,CAC9B,KAAO,KAAK,MAAM,CAAC,OAAS,EAAU,WAAa,KAAK,MAAM,CAAC,QAAU,KAAO,KAAK,MAAM,CAAC,QAAU,MAAM,CACxG,IAAM,EAAW,KAAK,SAAS,CAAC,MAC1B,EAAQ,KAAK,cAAc,CACjC,EAAO,CAAE,KAAM,SAAU,OAAM,WAAU,QAAO,CAEpD,OAAO,EAEX,cAAe,CACX,IAAM,EAAQ,KAAK,MAAM,CACzB,GAAI,EAAM,OAAS,EAAU,OACzB,MAAO,CAAE,KAAM,SAAU,MAAO,KAAK,iBAAiB,KAAK,SAAS,CAAC,MAAM,CAAE,CAEjF,GAAI,EAAM,OAAS,EAAU,WACzB,MAAO,CAAE,KAAM,aAAc,KAAM,KAAK,SAAS,CAAC,MAAO,CAE7D,GAAI,EAAM,OAAS,EAAU,OAAQ,CACjC,KAAK,SAAS,CACd,IAAM,EAAO,KAAK,iBAAiB,CACnC,GAAI,CAAC,KAAK,MAAM,EAAU,OAAO,CAC7B,MAAM,IAAI,EAAY,aAAc,EAAM,KAAM,EAAM,OAAO,CACjE,OAAO,EAEX,GAAI,EAAM,OAAS,EAAU,WAAa,EAAM,QAAU,KAAO,EAAM,QAAU,KAAO,EAAM,QAAU,KAEpG,MAAO,CAAE,KAAM,QAAS,SADP,KAAK,SAAS,CAAC,MACE,WAAY,KAAK,cAAc,CAAE,CAEvE,MAAM,IAAI,EAAY,oBAAoB,EAAM,QAAS,EAAM,KAAM,EAAM,OAAO,CAEtF,iBAAiB,EAAK,CAClB,IAAM,EAAQ,EAAI,aAAa,CAO/B,OANI,EAAM,WAAW,IAAI,CACd,SAAS,EAAI,MAAM,EAAE,CAAE,GAAG,CACjC,EAAM,WAAW,KAAK,CACf,SAAS,EAAK,GAAG,CACxB,EAAM,WAAW,IAAI,CACd,SAAS,EAAI,MAAM,EAAE,CAAC,QAAQ,KAAM,GAAG,CAAE,EAAE,CAC/C,WAAW,EAAI,GCzRjB,EAAkB,CAE3B,IAAO,CACH,OAAQ,GAAS,OAAQ,CACrB,CAAE,KAAM,QAAS,KAAM,GAAI,OAAQ,GAAI,KAAM,QAAS,CACtD,CAAE,KAAM,IAAK,KAAM,GAAI,OAAQ,EAAG,KAAM,OAAQ,CAChD,CAAE,KAAM,KAAM,KAAM,EAAG,OAAQ,EAAG,MAAO,GAAS,CACrD,CACJ,CACD,IAAO,CACH,OAAQ,GAAS,OAAQ,CACrB,CAAE,KAAM,OAAQ,KAAM,GAAI,OAAQ,EAAG,KAAM,IAAK,CAChD,CAAE,KAAM,KAAM,KAAM,EAAG,OAAQ,EAAG,MAAO,GAAS,CACrD,CACJ,CACD,GAAM,CACF,OAAQ,GAAS,OAAQ,CACrB,CAAE,KAAM,OAAQ,KAAM,GAAI,OAAQ,EAAG,KAAM,IAAK,CAChD,CAAE,KAAM,KAAM,KAAM,EAAG,OAAQ,EAAG,MAAO,GAAS,CACrD,CACJ,CACD,IAAO,CACH,OAAQ,GAAS,OAAQ,CACrB,CAAE,KAAM,OAAQ,KAAM,GAAI,OAAQ,EAAG,KAAM,IAAK,CAChD,CAAE,KAAM,KAAM,KAAM,EAAG,OAAQ,EAAG,MAAO,GAAS,CACrD,CACJ,CACD,IAAO,CACH,OAAQ,GAAS,OAAQ,CACrB,CAAE,KAAM,QAAS,KAAM,GAAI,OAAQ,GAAI,KAAM,QAAS,CACtD,CAAE,KAAM,IAAK,KAAM,GAAI,OAAQ,EAAG,KAAM,OAAQ,CAChD,CAAE,KAAM,KAAM,KAAM,EAAG,OAAQ,EAAG,MAAO,GAAS,CACrD,CACJ,CACD,IAAO,CACH,OAAQ,GAAS,OAAQ,CACrB,CAAE,KAAM,QAAS,KAAM,GAAI,OAAQ,GAAI,KAAM,QAAS,CACtD,CAAE,KAAM,IAAK,KAAM,GAAI,OAAQ,EAAG,KAAM,OAAQ,CAChD,CAAE,KAAM,KAAM,KAAM,EAAG,OAAQ,EAAG,MAAO,GAAS,CACrD,CACJ,CACD,IAAO,CACH,OAAQ,GAAS,OAAQ,CACrB,CAAE,KAAM,QAAS,KAAM,EAAG,OAAQ,GAAI,KAAM,MAAO,CACnD,CAAE,KAAM,IAAK,KAAM,EAAG,OAAQ,GAAI,KAAM,IAAK,CAC7C,CAAE,KAAM,KAAM,KAAM,EAAG,OAAQ,EAAG,MAAO,GAAS,CACrD,CACJ,CACD,IAAO,CACH,OAAQ,GAAS,OAAQ,CACrB,CAAE,KAAM,QAAS,KAAM,EAAG,OAAQ,GAAI,MAAO,EAAG,CAChD,CAAE,KAAM,IAAK,KAAM,EAAG,OAAQ,GAAI,KAAM,IAAK,CAC7C,CAAE,KAAM,KAAM,KAAM,EAAG,OAAQ,EAAG,MAAO,GAAS,CACrD,CACJ,CACD,IAAO,CACH,OAAQ,GAAS,OAAQ,CACrB,CAAE,KAAM,QAAS,KAAM,EAAG,OAAQ,GAAI,MAAO,EAAG,CAChD,CAAE,KAAM,IAAK,KAAM,EAAG,OAAQ,GAAI,MAAO,EAAG,CAC5C,CAAE,KAAM,KAAM,KAAM,EAAG,OAAQ,EAAG,MAAO,GAAS,CACrD,CACJ,CAED,KAAQ,CACJ,OAAQ,EAAS,OAAQ,CACrB,CAAE,KAAM,OAAQ,KAAM,EAAG,OAAQ,EAAG,KAAM,MAAO,CACjD,CAAE,KAAM,QAAS,KAAM,GAAI,OAAQ,GAAI,KAAM,QAAS,CACtD,CAAE,KAAM,KAAM,KAAM,EAAG,OAAQ,EAAG,MAAO,EAAS,CACrD,CACJ,CACD,KAAQ,CACJ,OAAQ,EAAS,OAAQ,CACrB,CAAE,KAAM,OAAQ,KAAM,EAAG,OAAQ,EAAG,KAAM,MAAO,CACjD,CAAE,KAAM,QAAS,KAAM,GAAI,OAAQ,GAAI,KAAM,QAAS,CACtD,CAAE,KAAM,KAAM,KAAM,EAAG,OAAQ,EAAG,MAAO,EAAS,CACrD,CACJ,CACD,KAAQ,CACJ,OAAQ,EAAS,OAAQ,CACrB,CAAE,KAAM,OAAQ,KAAM,EAAG,OAAQ,EAAG,KAAM,MAAO,CACjD,CAAE,KAAM,QAAS,KAAM,GAAI,OAAQ,GAAI,KAAM,QAAS,CACtD,CAAE,KAAM,KAAM,KAAM,EAAG,OAAQ,EAAG,MAAO,EAAS,CACrD,CACJ,CACD,KAAQ,CACJ,OAAQ,GAAS,OAAQ,CACrB,CAAE,KAAM,OAAQ,KAAM,EAAG,OAAQ,EAAG,KAAM,MAAO,CACjD,CAAE,KAAM,KAAM,KAAM,EAAG,OAAQ,EAAG,MAAO,GAAS,CACrD,CACJ,CACD,KAAQ,CACJ,OAAQ,EAAS,OAAQ,CACrB,CAAE,KAAM,OAAQ,KAAM,EAAG,OAAQ,EAAG,KAAM,MAAO,CACjD,CAAE,KAAM,QAAS,KAAM,GAAI,OAAQ,GAAI,KAAM,QAAS,CACtD,CAAE,KAAM,KAAM,KAAM,EAAG,OAAQ,EAAG,MAAO,EAAS,CACrD,CACJ,CACD,KAAQ,CACJ,OAAQ,EAAS,OAAQ,CACrB,CAAE,KAAM,OAAQ,KAAM,EAAG,OAAQ,EAAG,KAAM,MAAO,CACjD,CAAE,KAAM,QAAS,KAAM,GAAI,OAAQ,GAAI,KAAM,QAAS,CACtD,CAAE,KAAM,KAAM,KAAM,EAAG,OAAQ,EAAG,MAAO,EAAS,CACrD,CACJ,CACD,KAAQ,CACJ,OAAQ,EAAS,OAAQ,CACrB,CAAE,KAAM,OAAQ,KAAM,EAAG,OAAQ,EAAG,KAAM,MAAO,CACjD,CAAE,KAAM,QAAS,KAAM,GAAI,OAAQ,GAAI,KAAM,QAAS,CACtD,CAAE,KAAM,KAAM,KAAM,EAAG,OAAQ,EAAG,MAAO,EAAS,CACrD,CACJ,CACD,KAAQ,CACJ,OAAQ,EAAS,OAAQ,CACrB,CAAE,KAAM,QAAS,KAAM,GAAI,OAAQ,GAAI,MAAO,EAAG,CACjD,CAAE,KAAM,OAAQ,KAAM,EAAG,OAAQ,EAAG,KAAM,MAAO,CACjD,CAAE,KAAM,KAAM,KAAM,EAAG,OAAQ,EAAG,MAAO,EAAS,CACrD,CACJ,CAED,IAAO,CACH,OAAQ,EAAS,OAAQ,CACrB,CAAE,KAAM,OAAQ,KAAM,GAAI,OAAQ,EAAG,KAAM,OAAQ,CACnD,CAAE,KAAM,QAAS,KAAM,GAAI,OAAQ,GAAI,KAAM,OAAQ,CACrD,CAAE,KAAM,KAAM,KAAM,EAAG,OAAQ,EAAG,MAAO,EAAS,CACrD,CACJ,CACD,KAAQ,CACJ,OAAQ,EAAS,OAAQ,CACrB,CAAE,KAAM,QAAS,KAAM,GAAI,OAAQ,GAAI,KAAM,OAAQ,CACrD,CAAE,KAAM,KAAM,KAAM,EAAG,OAAQ,EAAG,MAAO,EAAS,CACrD,CACJ,CACD,IAAO,CACH,OAAQ,EAAS,OAAQ,CACrB,CAAE,KAAM,OAAQ,KAAM,GAAI,OAAQ,EAAG,KAAM,OAAQ,CACnD,CAAE,KAAM,QAAS,KAAM,GAAI,OAAQ,GAAI,KAAM,OAAQ,CACrD,CAAE,KAAM,KAAM,KAAM,EAAG,OAAQ,EAAG,MAAO,EAAS,CACrD,CACJ,CACD,KAAQ,CACJ,OAAQ,EAAS,OAAQ,CACrB,CAAE,KAAM,OAAQ,KAAM,GAAI,OAAQ,EAAG,KAAM,OAAQ,CACnD,CAAE,KAAM,QAAS,KAAM,GAAI,OAAQ,GAAI,KAAM,OAAQ,CACrD,CAAE,KAAM,KAAM,KAAM,EAAG,OAAQ,EAAG,MAAO,EAAS,CACrD,CACJ,CAED,KAAQ,CACJ,OAAQ,GAAS,OAAQ,CACrB,CAAE,KAAM,SAAU,KAAM,EAAG,OAAQ,GAAI,KAAM,IAAK,CAClD,CAAE,KAAM,OAAQ,KAAM,EAAG,OAAQ,GAAI,KAAM,IAAK,CAChD,CAAE,KAAM,OAAQ,KAAM,GAAI,OAAQ,EAAG,KAAM,IAAK,CAChD,CAAE,KAAM,KAAM,KAAM,EAAG,OAAQ,EAAG,MAAO,GAAS,CACrD,CACJ,CACD,KAAQ,CACJ,OAAQ,GAAS,OAAQ,CACrB,CAAE,KAAM,OAAQ,KAAM,EAAG,OAAQ,GAAI,MAAO,EAAG,CAC/C,CAAE,KAAM,SAAU,KAAM,EAAG,OAAQ,GAAI,KAAM,IAAK,CAClD,CAAE,KAAM,OAAQ,KAAM,GAAI,OAAQ,GAAI,KAAM,IAAK,CACjD,CAAE,KAAM,OAAQ,KAAM,EAAG,OAAQ,EAAG,KAAM,IAAK,CAC/C,CAAE,KAAM,KAAM,KAAM,EAAG,OAAQ,EAAG,MAAO,GAAS,CACrD,CACJ,CACD,IAAO,CACH,OAAQ,GAAS,OAAQ,CACrB,CAAE,KAAM,SAAU,KAAM,EAAG,OAAQ,EAAG,KAAM,IAAK,CACjD,CAAE,KAAM,OAAQ,KAAM,EAAG,OAAQ,EAAG,MAAO,EAAG,CAC9C,CAAE,KAAM,KAAM,KAAM,EAAG,OAAQ,EAAG,MAAO,GAAS,CACrD,CACJ,CACD,IAAO,CACH,OAAQ,GAAS,OAAQ,CACrB,CAAE,KAAM,OAAQ,KAAM,EAAG,OAAQ,GAAI,KAAM,IAAK,CAChD,CAAE,KAAM,QAAS,KAAM,EAAG,OAAQ,GAAI,KAAM,IAAK,CACjD,CAAE,KAAM,IAAK,KAAM,EAAG,OAAQ,GAAI,KAAM,IAAK,CAC7C,CAAE,KAAM,QAAS,KAAM,GAAI,OAAQ,EAAG,KAAM,OAAQ,CACpD,CAAE,KAAM,KAAM,KAAM,EAAG,OAAQ,EAAG,MAAO,GAAS,CACrD,CACJ,CAED,IAAO,CAAE,OAAQ,GAAS,OAAQ,CAAC,CAAE,KAAM,MAAO,KAAM,GAAI,OAAQ,EAAG,MAAO,GAAS,CAAC,CAAE,CAC1F,IAAO,CAAE,OAAQ,GAAS,OAAQ,CAAC,CAAE,KAAM,MAAO,KAAM,GAAI,OAAQ,EAAG,MAAO,GAAS,CAAC,CAAE,CAC1F,KAAQ,CAAE,OAAQ,EAAS,OAAQ,CAAC,CAAE,KAAM,MAAO,KAAM,GAAI,OAAQ,EAAG,MAAO,EAAS,CAAC,CAAE,CAC9F,CACY,EAAb,KAAqB,CACjB,OAAO,OAAO,EAAQ,EAAO,CACzB,OAAQ,EAAR,CACI,IAAK,QAAS,OAAO,KAAK,aAAa,EAAO,EAAG,GAAI,EAAI,CACzD,IAAK,OAAQ,OAAO,KAAK,aAAa,EAAO,EAAG,GAAI,EAAI,CACxD,IAAK,OAAQ,OAAO,KAAK,aAAa,EAAO,EAAG,EAAG,EAAI,CACvD,IAAK,OAAQ,OAAO,KAAK,aAAa,EAAO,EAAG,GAAI,EAAI,CACxD,IAAK,OAAQ,OAAO,KAAK,aAAa,EAAO,EAAG,EAAG,GAAK,CAE5D,OAAO,EAEX,OAAO,aAAa,EAAO,EAAS,EAAU,EAAU,CACpD,IAAM,EAAM,GAAY,GAAK,GACvB,EAAM,CAAC,EACP,EAAM,EAAW,EAEnB,EAAU,KAAK,MADT,KAAK,IAAI,KAAK,IAAI,EAAO,EAAI,CAAE,EACb,EAAI,GAAK,GAAU,CACzC,EAAY,EAAI,EAAU,EAC1B,GAAQ,GAAK,GAAa,EAChC,OAAQ,EAAU,EAAM,GAAW,GAAK,GAAc,EAAO,EAAU,EAE3E,OAAO,oBAAoB,EAAU,EAAU,EAAQ,CACnD,IAAI,EAAS,EACT,EAAa,EACjB,IAAK,IAAM,KAAS,EAAO,OAAQ,CAC/B,IAAI,EAAM,EACN,EAAM,QAAU,IAAA,IAIhB,EAAM,EAAS,KACX,EAAM,OACN,EAAM,KAAK,OAAO,EAAM,KAAM,EAAI,GALtC,EAAM,EAAM,MAOhB,IAAM,EAAO,EAAM,OAAS,GAAK,YAAc,GAAK,EAAM,MAAQ,EAClE,IAAW,EAAM,IAAS,EAAM,OAEpC,OAAO,IAAW,IC5Nb,EAAb,KAA0B,CACtB,YAAY,EAAU,EAAE,CAAE,CACtB,KAAK,SAAW,EAAE,CAClB,KAAK,QAAU,IAAI,IACnB,KAAK,SAAW,EAAE,CAClB,KAAK,OAAS,IAAI,IAClB,KAAK,iBAAmB,IAAI,IAC5B,KAAK,cAAgB,IAAI,IACzB,KAAK,SAAW,IAAI,IACpB,KAAK,eAAiB,IAAI,IAC1B,KAAK,YAAc,IAAI,IACvB,KAAK,YAAc,IAAI,IACvB,KAAK,mBAAqB,CACtB,UAAa,EAAM,WAAc,EAAM,UAAa,EAAM,WAAc,EACxE,UAAa,EAAM,WAAc,EAAM,UAAa,EAAM,WAAc,EACxE,KAAQ,GAAM,KAAQ,GAAM,KAAQ,GAAM,KAAQ,GAAM,KAAQ,GAChE,KAAQ,GAAM,KAAQ,GAAM,SAAY,GACxC,KAAQ,EAAM,KAAQ,EAAM,KAAQ,EAAM,KAAQ,EAClD,KAAQ,EAAM,KAAQ,EACtB,IAAO,EAAM,IAAO,EAAM,KAAQ,EAClC,IAAO,EAAM,IAAO,EAAM,IAAO,EAAM,MAAS,EAChD,MAAS,EAAM,MAAS,GAAM,GAAM,GACpC,IAAO,GAAM,IAAO,EAAM,IAAO,EACjC,IAAO,EAAM,IAAO,EACvB,CACD,KAAK,gBAAkB,IAAI,IAC3B,KAAK,QAAU,CACX,aAAc,EAAQ,cAAgB,GACtC,WAAY,EAAQ,YAAc,GAClC,SAAU,EAAQ,UAAY,GAC9B,SAAU,EAAQ,UAAY,IAC9B,UAAW,EAAQ,WAAa,MACnC,CACD,KAAK,OAAO,CAEhB,OAAQ,CACJ,KAAK,SAAW,EAAE,CAClB,KAAK,QAAQ,OAAO,CACpB,KAAK,SAAW,EAAE,CAClB,KAAK,OAAO,OAAO,CACnB,KAAK,iBAAiB,OAAO,CAC7B,KAAK,cAAc,OAAO,CAC1B,KAAK,SAAS,OAAO,CACrB,KAAK,eAAe,OAAO,CAC3B,KAAK,YAAY,OAAO,CACxB,KAAK,YAAY,OAAO,CACxB,KAAK,aAAa,CAEtB,aAAc,CAEV,IAAK,GAAM,CAAC,EAAK,KAAQ,OAAO,QAAQ,KAAK,mBAAmB,CAC5D,KAAK,QAAQ,IAAI,EAAK,EAAI,CAC1B,KAAK,gBAAgB,IAAI,EAAI,CAGjC,IAAK,IAAI,EAAI,EAAG,EAAI,KAAK,QAAQ,SAAU,IACvC,KAAK,QAAQ,IAAI,MAAM,IAAK,GAAO,EAAE,CACrC,KAAK,gBAAgB,IAAI,MAAM,IAAI,CAG3C,SAAS,EAAQ,CACb,KAAK,OAAO,CACZ,GAAI,CAIA,IAAM,EAAM,IADO,EADJ,IADG,EAAM,EACJ,CAAC,UACW,CACd,CAAC,OAAO,CAI1B,OAHA,KAAK,wBAAwB,EAAI,CACjC,KAAK,oBAAoB,EAAI,CAEtB,CACH,YAFgB,KAAK,mBAAmB,EAE7B,CACX,SAAU,KAAK,SACf,OAAQ,KAAK,OACb,QAAS,MAAM,KAAK,KAAK,QAAQ,SAAS,CAAC,CACtC,QAAQ,CAAC,KAAU,KAAK,YAAY,IAAI,EAAK,CAAC,CAC9C,KAAK,CAAC,EAAM,MAAY,CAAE,OAAM,MAAO,EAAM,UAAU,CAAE,KAAM,KAAK,YAAY,IAAI,EAAK,CAAE,EAAE,CAClG,SAAU,KAAK,SACf,iBAAkB,KAAK,iBACvB,mBAAoB,KAAK,cAAc,KACvC,SAAU,MAAM,KAAK,KAAK,SAAS,CACtC,OAEE,EAAG,CACN,IAAM,EAAQ,aAAa,EAAe,EAAE,KAAO,EAEnD,OADA,KAAK,SAAS,KAAK,CAAE,QAAS,iBAAiB,aAAa,MAAQ,EAAE,QAAU,OAAO,EAAE,GAAI,QAAS,GAAM,OAAM,CAAC,CAC5G,CACH,YAAa,EAAE,CACf,SAAU,KAAK,SACf,OAAQ,IAAI,IACZ,QAAS,EAAE,CACX,SAAU,EAAE,CACZ,iBAAkB,IAAI,IACtB,mBAAoB,EACpB,SAAU,EAAE,CACf,EAGT,wBAAwB,EAAK,CACzB,IAAI,EAAgB,EACpB,IAAK,IAAM,KAAQ,EACf,GAAI,EAAK,OAAS,gBACV,EAAK,OAAS,MACd,GAAI,KAAK,gBAAgB,IAAI,EAAK,WAAW,CACzC,KAAK,SAAS,KAAK,CAAE,QAAS,oCAAoC,EAAK,WAAW,GAAI,QAAS,GAAM,KAAM,EAAK,KAAM,CAAC,SAElH,KAAK,YAAY,IAAI,EAAK,WAAW,CAC1C,KAAK,SAAS,KAAK,CAAE,QAAS,WAAW,EAAK,WAAW,+BAA+B,KAAK,YAAY,IAAI,EAAK,WAAW,GAAI,QAAS,GAAM,KAAM,EAAK,KAAM,CAAC,KAEjK,CACD,IAAM,EAAQ,KAAK,mBAAmB,EAAK,WAAY,EAAK,KAAK,CACjE,KAAK,QAAQ,IAAI,EAAK,WAAY,EAAM,CACxC,KAAK,YAAY,IAAI,EAAK,WAAW,CACrC,KAAK,YAAY,IAAI,EAAK,WAAY,EAAK,KAAK,SAG/C,EAAK,OAAS,MAAO,CAC1B,GAAI,KAAK,gBAAgB,IAAI,EAAK,WAAW,CAAE,CAC3C,KAAK,SAAS,KAAK,CAAE,QAAS,oCAAoC,EAAK,WAAW,GAAI,QAAS,GAAM,KAAM,EAAK,KAAM,CAAC,CACvH,SAEJ,IAAM,EAAO,KAAK,mBAAmB,EAAK,WAAY,EAAK,KAAK,CAC1D,EAAQ,EACR,EAAS,GAAS,EAAO,GAAK,EAAO,GAAK,EAAI,EAAI,EAAO,GACzD,EAAM,EAAQ,EAAO,EACrB,EAAW,GAAO,QAAK,QAAQ,aAC/B,EAAM,CAAE,KAAM,EAAK,WAAY,OAAM,QAAO,SAAQ,MAAK,KAAM,EAAK,KAAM,SAAU,GAAI,CAC9F,KAAK,SAAS,KAAK,EAAI,CAEvB,KAAK,QAAQ,IAAI,EAAK,WAAY,EAAM,CACxC,KAAK,QAAQ,IAAI,EAAK,WAAa,IAAK,EAAO,CAC/C,KAAK,QAAQ,IAAI,EAAK,WAAa,IAAK,EAAS,CACjD,EAAgB,EAAW,IAK3C,oBAAoB,EAAK,CACrB,IAAI,EAAK,EACT,IAAK,IAAM,KAAQ,EACX,EAAK,OAAS,QACd,KAAK,OAAO,IAAI,EAAK,KAAM,CAAE,KAAM,EAAK,KAAM,gBAAiB,EAAI,CAAC,CAE/D,EAAK,OAAS,eACnB,IAIZ,mBAAmB,EAAK,CACpB,IAAM,EAAO,EAAE,CACX,EAAK,EACT,IAAK,IAAM,KAAQ,EACf,GAAI,EAAK,OAAS,cAAe,CAC7B,IAAM,EAAS,EAAgB,EAAK,UACpC,GAAI,CAAC,EAAQ,CACT,KAAK,SAAS,KAAK,CAAE,QAAS,uBAAuB,EAAK,WAAY,QAAS,GAAM,KAAM,EAAK,KAAM,CAAC,CACvG,EAAK,KAAK,EAAE,CACZ,SAEJ,IAAI,EAAW,EAAK,SAAS,IAAI,GAEzB,EAAG,OAAS,cAAgB,KAAK,OAAO,IAAI,EAAG,KAAK,CAC7C,KAAK,OAAO,IAAI,EAAG,KAAK,CAAC,gBAAkB,EAAK,EAEpD,KAAK,mBAAmB,EAAI,EAAK,KAAK,CAC/C,CAGF,GAAI,EAAK,WAAa,QAAU,EAAK,WAAa,OAAQ,CACtD,IAAM,EAAS,EAAS,GAClB,EAAU,KAAK,WAAW,EAAO,CACnC,IACI,EAAK,WAAa,SACd,KAAK,eAAe,IAAI,EAAQ,EAChC,KAAK,SAAS,KAAK,CAAE,QAAS,OAAO,EAAQ,+BAAgC,QAAS,GAAM,KAAM,EAAK,KAAM,CAAC,CAElH,KAAK,eAAe,IAAI,EAAQ,EAEpC,KAAK,SAAS,IAAI,EAAQ,EAGlC,GAAI,EAAK,WAAa,MAAO,CACzB,IAAM,EAAO,EAAS,GAChB,EAAI,EAAS,GACb,EAAU,KAAK,QAAQ,IAAI,MAAM,CACjC,EAAU,KAAK,QAAQ,IAAI,MAAM,CAEvC,GAAI,IADa,KAAK,QAAQ,IAAI,OACb,CAEjB,EAAW,CAAC,EAAM,EAAM,EAAG,EAAE,SAExB,IAAS,GAAW,IAAS,EAAS,CAC3C,IAAM,EAAQ,EAAS,GACnB,EAAQ,EAAS,GACjB,IAAS,IACT,EAAQ,EAAQ,OAAO,QAAS,EAAM,EAE1C,EAAW,CAAC,EAAM,EAAO,EAAG,EAAM,UAGjC,EAAK,WAAa,OAAQ,CAE/B,IAAI,EAAO,EAAS,GACpB,OAAQ,EAAR,CACI,IAAK,KACD,EAAO,EACP,MACJ,IAAK,MACD,EAAO,EACP,MACJ,IAAK,MACD,EAAO,EACP,MACJ,IAAK,MACD,EAAO,EACP,MACJ,QACI,KAAK,SAAS,KAAK,CAAE,QAAS,qBAAqB,EAAK,WAAY,QAAS,GAAM,KAAM,EAAK,KAAM,CAAC,CAG7G,IAAI,EAAS,EAAS,GAClB,CAAC,EAAG,EAAE,CAAC,SAAS,EAAO,CACvB,EAAS,EACJ,CAAC,EAAG,EAAE,CAAC,SAAS,EAAO,GAC5B,EAAS,GACb,EAAW,CAAC,EAAQ,EAAS,GAAI,EAAK,SAEjC,EAAK,WAAa,MAAO,CAC9B,IAAI,EAAS,EAAS,GAClB,CAAC,EAAG,EAAE,CAAC,SAAS,EAAO,CACvB,EAAS,EACJ,CAAC,EAAG,EAAE,CAAC,SAAS,EAAO,GAC5B,EAAS,GACb,EAAW,CAAC,EAAO,CASvB,GANA,EAAO,OAAO,SAAS,EAAO,IAAM,CAC5B,EAAM,OAAS,OAAS,EAAS,KAAO,IAAA,IACxC,KAAK,cAAc,EAAS,GAAI,EAAK,KAAK,EAEhD,CAEE,EAAK,WAAa,QAAU,EAAK,WAAa,OAAQ,CACtD,IAAM,EAAS,EAAS,GAClB,EAAU,KAAK,uBAAuB,EAAO,CAC/C,GACA,KAAK,SAAS,IAAI,EAAQ,CAGlC,EAAK,KAAK,EAAQ,oBAAoB,EAAK,SAAU,EAAU,EAAO,CAAC,CACvE,KAAK,iBAAiB,IAAI,EAAI,EAAK,KAAK,CACxC,IAIR,KAAO,EAAK,OAAS,KAAK,QAAQ,UAC9B,EAAK,KAAK,GAAW,CACzB,OAAO,EAEX,cAAc,EAAM,EAAM,CACtB,GAAI,GAAQ,IAAQ,GAAQ,GAAM,CAC9B,IAAM,EAAS,EAAO,GAClB,GAAU,KAAK,QAAQ,UACvB,KAAK,SAAS,KAAK,CAAE,QAAS,eAAe,EAAO,iBAAiB,KAAK,QAAQ,WAAY,QAAS,GAAM,OAAM,CAAC,CAExH,KAAK,cAAc,IAAI,EAAO,EAGtC,WAAW,EAAO,CACd,OAAQ,EAAR,CACI,IAAK,GAAG,MAAO,OACf,IAAK,GAAG,MAAO,OACf,IAAK,GAAG,MAAO,OACf,IAAK,GAAG,MAAO,OACf,QAAS,OAAO,MAGxB,uBAAuB,EAAM,CAGzB,OAAQ,EAAR,CACI,IAAK,GACL,IAAK,GAAM,MAAO,OAClB,IAAK,GACL,IAAK,GAAM,MAAO,OAClB,IAAK,GACL,IAAK,GAAM,MAAO,OAClB,IAAK,GACL,IAAK,GAAM,MAAO,OAClB,QAAS,OAAO,MAGxB,mBAAmB,EAAM,EAAM,CAC3B,OAAQ,EAAK,KAAb,CACI,IAAK,SAAU,OAAO,EAAK,MAC3B,IAAK,aAID,OAHI,KAAK,QAAQ,IAAI,EAAK,KAAK,CACpB,KAAK,QAAQ,IAAI,EAAK,KAAK,EACtC,KAAK,SAAS,KAAK,CAAE,QAAS,oBAAoB,EAAK,OAAQ,QAAS,GAAM,OAAM,CAAC,CAC9E,GACX,IAAK,SACD,IAAM,EAAO,KAAK,mBAAmB,EAAK,KAAM,EAAK,CAC/C,EAAQ,KAAK,mBAAmB,EAAK,MAAO,EAAK,CACvD,OAAQ,EAAK,SAAb,CACI,IAAK,IAAK,OAAO,EAAO,EACxB,IAAK,IAAK,OAAO,EAAO,EACxB,IAAK,IAAK,OAAO,EAAO,EACxB,IAAK,IAAK,OAAO,EAAO,EACxB,IAAK,IAAK,OAAO,EAAO,EACxB,IAAK,IAAK,OAAO,EAAO,EACxB,IAAK,IAAK,OAAO,EAAO,EACxB,IAAK,IAAK,OAAQ,GAAQ,IAAW,EACrC,IAAK,IAAK,OAAQ,IAAS,EAC3B,QAAS,MAAO,GAExB,IAAK,QACD,IAAM,EAAM,KAAK,mBAAmB,EAAK,WAAY,EAAK,CAK1D,OAJI,EAAK,WAAa,IACX,CAAC,EACR,EAAK,WAAa,IACV,CAAC,KAAK,MAAM,EAAI,GAAM,EAC3B,GAGnB,OAAO,kBAAkB,EAAa,CAClC,OAAO,EAAY,KAAK,EAAM,IAAU,GAAG,EAAM,UAAU,CAAC,SAAS,EAAG,IAAI,CAAC,IAAI,EAAK,SAAS,GAAG,CAAC,aAAa,CAAC,SAAS,EAAG,IAAI,GAAG,CAAC,KAAK;EAAK,CAEnJ,OAAO,aAAa,EAAa,CAC7B,IAAM,EAAS,IAAI,YAAY,EAAY,OAAS,EAAE,CAChD,EAAO,IAAI,SAAS,EAAO,CAEjC,OADA,EAAY,SAAS,EAAK,IAAM,EAAK,UAAU,EAAI,EAAG,EAAK,GAAM,CAAC,CAC3D,IAAI,WAAW,EAAO,CAEjC,OAAO,cAAc,EAAO,EAAM,CAC9B,OAAO,GAAS,EAAO,GAAK,EAAO,GAAK,EAAI,EAAI,EAAO,GAE3D,OAAO,WAAW,EAAO,EAAM,EAAc,CACzC,OAAO,EAAQ,EAAO,GAAK,OC5UtB,EAAb,MAAa,CAAa,CAMtB,aAAc,CAGV,KAAK,UAAY,MACjB,KAAK,UAAY,MACjB,KAAK,SAAW,GAChB,KAAK,SAAW,IAEhB,KAAK,KAAO,EACZ,KAAK,KAAO,EACZ,KAAK,KAAO,EACZ,KAAK,KAAO,EACZ,KAAK,KAAO,EACZ,KAAK,KAAO,EACZ,KAAK,UAAY,EACjB,KAAK,WAAa,EAClB,KAAK,UAAY,EACjB,KAAK,WAAa,EAClB,KAAK,UAAY,EACjB,KAAK,WAAa,EAClB,KAAK,UAAY,EACjB,KAAK,WAAa,EAClB,KAAK,IAAM,EACX,KAAK,KAAO,EACZ,KAAK,GAAK,EACV,KAAK,IAAM,EACX,KAAK,aAAe,EACpB,KAAK,SAAW,GAChB,KAAK,GAAK,EACV,KAAK,YAAc,IAAI,IAEvB,KAAK,QAAU,EAAE,CACjB,KAAK,SAAW,EAAE,CAClB,KAAK,aAAe,GAEpB,KAAK,aAAe,GACpB,KAAK,YAAc,KACnB,KAAK,WAAa,EAClB,KAAK,WAAa,EAClB,KAAK,eAAiB,EACtB,KAAK,cAAgB,EACrB,KAAK,eAAiB,GACtB,KAAK,iBAAmB,GACxB,KAAK,aAAe,GACpB,KAAK,gBAAkB,EACvB,KAAK,mBAAqB,GAC1B,KAAK,mBAAqB,IAAI,IAC9B,KAAK,gBAAkB,KACvB,KAAK,SAAW,IAAI,aAAa,KAAK,UAAU,CAChD,KAAK,UAAY,IAAI,aAAa,GAAK,KAAK,SAAS,CACrD,KAAK,QAAU,IAAI,YAAY,KAAK,SAAS,CAKjD,gBAAgB,EAAW,EAAU,EAAU,CAC3C,KAAK,UAAY,EACjB,KAAK,UAAY,EAAY,EAC7B,KAAK,SAAW,EAChB,KAAK,SAAW,EAEhB,KAAK,SAAW,IAAI,aAAa,KAAK,UAAU,CAChD,KAAK,UAAY,IAAI,aAAa,GAAK,KAAK,SAAS,CACrD,KAAK,QAAU,IAAI,YAAY,KAAK,SAAS,CAC7C,KAAK,OAAO,CAEhB,iBAAkB,CACd,OAAO,KAAK,aAEhB,cAAe,CACX,OAAO,KAAK,UAMhB,YAAY,EAAM,CACV,EAAK,OAAS,KAAK,UACnB,QAAQ,KAAK,iBAAiB,EAAK,OAAO,sBAAsB,KAAK,SAAS,gBAAgB,CAElG,KAAK,QAAQ,KAAK,EAAE,CACpB,KAAK,QAAQ,IAAI,EAAK,MAAM,EAAG,KAAK,SAAS,CAAC,CAC9C,KAAK,OAAO,CAKhB,OAAQ,CACJ,KAAK,SAAS,KAAK,EAAE,CACrB,KAAK,UAAU,KAAK,EAAE,CACtB,KAAK,IAAM,EACX,KAAK,KAAO,EACZ,KAAK,GAAK,EACV,KAAK,IAAM,EACX,KAAK,GAAK,EACV,KAAK,aAAe,EACpB,KAAK,SAAW,GAChB,KAAK,KAAO,EACZ,KAAK,KAAO,EAIZ,KAAK,KAAO,GACZ,KAAK,KAAO,GACZ,KAAK,KAAO,EACZ,KAAK,KAAO,EACZ,KAAK,UAAY,EACjB,KAAK,WAAa,EAClB,KAAK,UAAY,EACjB,KAAK,WAAa,EAClB,KAAK,UAAY,EACjB,KAAK,WAAa,EAClB,KAAK,UAAY,EACjB,KAAK,WAAa,EAElB,KAAK,UAAU,IAAM,GACrB,KAAK,UAAU,IAAM,GACrB,KAAK,UAAU,IAAM,GAMzB,eAAe,EAAW,CACtB,KAAK,YAAc,EAKvB,WAAW,EAAS,EAAU,EAAe,GAAO,CAChD,KAAK,QAAU,EACf,KAAK,SAAW,EAChB,KAAK,aAAe,EAMxB,aAAa,EAAQ,EAAQ,EAAS,EAAS,EAAM,EAAM,EAAM,CAC7D,IAAM,EAAM,EAAO,OACnB,IAAK,IAAI,EAAI,EAAG,EAAI,EAAK,IAAK,CAC1B,GAAM,CAAC,EAAM,GAAQ,KAAK,KAAK,EAAO,GAAI,EAAO,GAAI,EAAM,EAAM,EAAK,CACtE,EAAQ,GAAK,EACb,EAAQ,GAAK,GASrB,KAAK,EAAK,EAAK,EAAM,EAAM,EAAM,EAAwB,GAAO,CAExD,KAAK,KAAO,GACZ,KAAK,WAAW,EAAK,EAAK,EAAM,EAAM,EAAK,CAE/C,IAAI,EAAmB,GACvB,KAAO,KAAK,GAAK,KAAK,UAAU,CAC5B,GAAI,KAAK,YAAY,IAAI,KAAK,GAAG,GACzB,CAAC,GAAoB,CAAC,GACtB,MAAO,CAAC,GAAG,KAAK,YAAY,CAAE,GAAK,CAG3C,KAAK,iBAAiB,CACtB,EAAmB,GAEvB,MAAO,CAAC,GAAG,KAAK,UAAU,CAAE,GAAM,CAEtC,YAAa,CACT,MAAO,CAAC,KAAK,UAAU,IAAK,KAAK,UAAU,IAAI,CAEnD,WAAW,EAAM,EAAG,EAAM,EAAG,EAAO,EAAG,EAAO,EAAG,EAAO,EAAG,CACvD,KAAK,aACL,KAAK,mBAAmB,OAAO,CAG/B,IAAM,EAAO,GAAM,KAAK,IAAI,GAAM,KAAK,IAAI,EAAa,QAAS,EAAE,CAAC,CAC9D,EAAU,GACM,KAAK,MAAM,KAAK,IAAI,EAAG,KAAK,IAAI,SAAW,EAAE,CAAC,CAAG,KAAK,CAAG,KAI/E,KAAK,IAAM,EACX,KAAK,GAAK,EACV,KAAK,KAAO,EACZ,KAAK,GAAK,EAEV,KAAK,UAAU,IAAM,EAAI,EAAI,CAC7B,KAAK,UAAU,IAAM,EAAI,EAAI,CAC7B,KAAK,UAAU,IAAM,EAAO,EAAK,CACjC,KAAK,UAAU,IAAM,EAAO,EAAK,CACjC,KAAK,UAAU,IAAM,EAAO,EAAK,CACjC,KAAK,sBAAsB,CAE/B,UAAW,CASP,MARA,MAAK,GAAK,EACV,KAAK,SAAW,GAChB,KAAK,YAAY,CACjB,KAAK,sBAAsB,CAC3B,KAAK,mBAAmB,CAExB,KAAK,cAAgB,KAAK,aAAe,EAAI,KAAK,WAAa,KAAK,UAE7D,CAAC,KAAK,UAAU,IAAK,KAAK,UAAU,IAAI,CAMnD,iBAAkB,CACd,GAAI,KAAK,IAAM,KAAK,SAChB,OAAO,KAAK,GAChB,IAAM,EAAO,KAAK,QAAQ,KAAK,IACzB,EAAS,EAAO,GAChB,EAAW,KAAK,IAEtB,KAAK,eAAiB,GACtB,KAAK,iBAAmB,GACxB,KAAK,aAAe,GACpB,KAAK,gBAAkB,EACvB,KAAK,mBAAqB,KAAK,GAC/B,IAAM,EAAO,KAAK,mBAAmB,EAAK,CAS1C,OAPI,KAAK,cACL,KAAK,SAAS,KAAK,mBAAoB,EAAQ,EAAM,EAAS,CAE9D,IAAW,KACX,KAAK,KAAO,GAEhB,KAAK,IAAM,EAAI,EACR,KAAK,GAEhB,mBAAmB,EAAM,CACrB,IAAM,EAAS,EAAO,GAClB,EAAO,EACX,OAAQ,EAAR,CACI,IAAK,GACD,KAAK,MAAM,EAAK,CAChB,MACJ,IAAK,GACD,KAAK,OAAO,EAAK,CACjB,MACJ,IAAK,GACD,KAAK,MAAM,EAAK,CAChB,MACJ,IAAK,GACD,KAAK,OAAO,EAAK,CACjB,MACJ,IAAK,GACD,KAAK,OAAO,EAAK,CACjB,MACJ,IAAK,GACD,KAAK,OAAO,EAAK,CACjB,MACJ,IAAK,GACD,KAAK,OAAO,EAAK,CACjB,MACJ,IAAK,GACD,KAAK,OAAO,EAAK,CACjB,MACJ,IAAK,GACD,KAAK,OAAO,EAAK,CACjB,MACJ,IAAK,GACD,KAAK,OAAO,EAAK,CACjB,MACJ,IAAK,IACD,KAAK,OAAO,EAAK,CACjB,MACJ,IAAK,IACD,KAAK,MAAM,EAAK,CAChB,MACJ,IAAK,IACD,KAAK,MAAM,EAAK,CAChB,MACJ,IAAK,IACD,KAAK,MAAM,EAAK,CAChB,MACJ,IAAK,IACD,KAAK,MAAM,EAAK,CAChB,MACJ,IAAK,IACD,KAAK,KAAK,EAAK,CACf,MACJ,IAAK,IACD,KAAK,MAAM,EAAK,CAChB,MACJ,IAAK,IACD,EAAO,KAAK,MAAM,EAAK,CACvB,MACJ,IAAK,IAEI,IAAS,GAAM,EAChB,KAAK,OAAO,EAAK,CAGjB,KAAK,OAAO,EAAK,CAErB,MACJ,IAAK,IACD,KAAK,MAAM,EAAK,CAChB,MACJ,IAAK,IACD,KAAK,MAAM,EAAK,CAChB,MACJ,QAEI,MAER,OAAO,EAGX,MAAM,EAAM,CAER,IAAM,EAAQ,IAAS,EAAK,MACtB,EAAQ,KAAK,WAAY,IAAS,GAAM,KAAM,CAE9C,EAAY,KAAK,aAAe,EAAQ,KAAK,UAC7C,EAAM,KAAK,SAAS,GAC1B,KAAK,eAAiB,EACtB,KAAK,iBAAmB,EACxB,KAAK,aAAe,IACpB,KAAK,gBAAkB,EACvB,KAAK,mBAAmB,IAAI,EAAK,CACjC,KAAK,GAAK,EACV,KAAK,KAAO,EAAM,EAClB,KAAK,IAAM,KAAK,SAAS,KAAK,IAAI,CAEtC,MAAM,EAAM,CAIR,IAAM,EAAQ,IAAS,EAAK,MACtB,EAAQ,KAAK,WAAY,IAAS,GAAM,KAAM,CAC9C,EAAa,KAAK,aAAe,EAAQ,KAAK,UACpD,KAAK,eAAiB,EACtB,KAAK,iBAAmB,EACxB,KAAK,aAAe,IACpB,KAAK,gBAAkB,KAAK,IAC5B,KAAK,SAAS,GAAa,KAAK,IAChC,KAAK,KAAO,EACZ,KAAK,IAAM,KAAK,SAAS,KAAK,IAAI,CAEtC,OAAO,EAAM,CAKT,IAAM,EAAQ,IAAS,EAAK,MACtB,EAAQ,KAAK,WAAY,IAAS,GAAM,KAAM,CAC9C,EAAa,KAAK,aAAe,EAAQ,KAAK,UACpD,KAAK,eAAiB,EACtB,KAAK,iBAAmB,EACxB,KAAK,aAAe,IACpB,KAAK,gBAAkB,KAAK,IAC5B,KAAK,SAAS,GAAa,KAAK,IAEhC,KAAK,IAAM,KAAK,IAAM,EAAQ,KAAK,GACnC,KAAK,IAAM,KAAK,SAAS,KAAK,IAAI,CAEtC,OAAO,EAAM,CAIT,IAAM,EAAO,IAAS,EAAK,GACrB,EAAQ,KAAK,YAAa,IAAS,GAAM,MAAO,CAChD,EAAM,KAAK,UAAU,GAC3B,KAAK,KAAO,EAAM,EAClB,KAAK,IAAM,KAAK,SAAS,KAAK,IAAI,CAEtC,OAAO,EAAM,CAIT,IAAM,EAAO,IAAS,EAAK,GACrB,EAAQ,KAAK,YAAa,IAAS,GAAM,MAAO,CACtD,KAAK,UAAU,GAAO,KAAK,IAC3B,KAAK,KAAO,EACZ,KAAK,IAAM,KAAK,SAAS,KAAK,IAAI,CAEtC,MAAM,EAAM,CAIR,IAAM,EAAI,KAAK,WAAY,IAAS,EAAK,KAAM,CACzC,EAAI,KAAK,YAAa,IAAS,GAAM,MAAO,CAClD,KAAK,IAAM,KAAK,IAAM,EAAI,EAC1B,KAAK,IAAM,KAAK,SAAS,KAAK,IAAI,CAEtC,OAAO,EAAM,CAIT,IAAM,EAAQ,KAAK,WAAY,IAAS,GAAM,KAAM,CAO9C,EAAM,KAAK,MAAM,KAAK,UAAU,IAAM,KAAK,UAAU,CACrD,EAAY,KAAK,aAAe,EAAO,KAAK,UAC5C,EAAM,KAAK,SAAS,GAC1B,KAAK,eAAiB,EACtB,KAAK,iBAAmB,EACxB,KAAK,aAAe,IACpB,KAAK,gBAAkB,EACvB,KAAK,mBAAmB,IAAI,EAAI,CAChC,KAAK,GAAK,EACV,KAAK,KAAO,EAAM,EAClB,KAAK,IAAM,KAAK,SAAS,KAAK,IAAI,CAEtC,OAAO,EAAM,CAET,IAAM,EAAO,IAAS,EAAK,GAC3B,KAAK,KAAiB,KAAK,UAAU,GACrC,KAAK,IAAM,KAAK,SAAS,KAAK,IAAI,CAEtC,MAAM,EAAM,CAGR,IAAM,EAAI,KAAK,WAAY,IAAS,EAAK,KAAM,CACzC,EAAQ,KAAK,YAAa,IAAS,GAAM,MAAO,CAChD,EAAM,KAAK,IAAI,KAAK,IAAI,CAC1B,EACJ,AAII,EAJA,EAAM,iBACG,KAAK,KAAK,EAAI,CAGd,IAGb,KAAK,KAAO,EAAS,EAAQ,GAAK,GAClC,KAAK,IAAM,KAAK,SAAS,KAAK,IAAI,CAEtC,MAAM,EAAM,CAGR,IAAM,EAAI,KAAK,WAAY,IAAS,EAAK,KAAM,CACzC,EAAQ,KAAK,YAAa,IAAS,GAAM,MAAO,CAChD,EAAU,KAAK,IAAM,GAE3B,KAAK,IAAe,GAAG,EAAW,EAAQ,EAC1C,KAAK,IAAM,KAAK,SAAS,KAAK,IAAI,CAEtC,OAAO,EAAM,CAIT,IAAM,EAAO,IAAS,EAAK,GACrB,EAAQ,KAAK,YAAa,IAAS,GAAM,MAAO,CAChD,EAAK,KAAK,UAAU,GAC1B,KAAK,KAAO,KAAK,IAAM,GAAM,EAAQ,EACrC,KAAK,IAAM,KAAK,SAAS,KAAK,IAAI,CAEtC,OAAO,EAAM,CAET,IAAM,EAAO,IAAS,EAAK,GACrB,EAAQ,KAAK,YAAa,IAAS,GAAM,MAAO,CAChD,EAAI,KAAK,IAAI,KAAK,IAAI,CACtB,EAAI,KAAK,IAAI,KAAK,UAAU,GAAO,EAAM,CAE/C,KAAK,IAAM,KAAK,IAAI,EAAG,EAAE,CACzB,KAAK,IAAM,KAAK,SAAS,KAAK,IAAI,CAEtC,MAAM,EAAM,CAGR,IAAM,EAAK,IAAS,GAAM,GACpB,EAAQ,EAAO,WACjB,EAAe,GAcnB,OAZK,EAAQ,WAAe,KAAK,IAAM,IACnC,EAAe,IACd,EAAQ,WAAe,KAAK,KAAO,IACpC,EAAe,IACd,EAAQ,WAAe,KAAK,MAAQ,IACrC,EAAe,IAEd,EAAQ,YAAgB,KAAK,IAAM,KAAK,KAAO,IAChD,EAAe,IAEd,EAAQ,YAAe,CAAC,KAAK,WAC9B,EAAe,IACZ,EAAe,EAAI,EAE9B,OAAO,EAAM,CAIT,IAAM,EAAO,IAAS,EAAK,GACrB,EAAQ,KAAK,YAAa,IAAS,GAAM,MAAO,CACtD,KAAK,UAAU,GAAO,KAAK,IAC3B,KAAK,KAAO,KAAK,KAAO,KAAK,KAAO,EAAQ,KAAK,KACjD,KAAK,IAAM,KAAK,SAAS,KAAK,IAAI,CAEtC,OAAO,EAAM,CAIT,IAAM,EAAO,IAAS,EAAK,GACrB,EAAQ,KAAK,YAAa,IAAS,GAAM,MAAO,CACtD,KAAK,UAAU,GAAO,KAAK,IAC3B,KAAK,IAAM,KAAK,KAAO,KAAK,IAAM,EAClC,KAAK,IAAM,KAAK,SAAS,KAAK,IAAI,CAEtC,MAAM,EAAM,CAGR,IAAM,EAAQ,IAAS,EAAK,SAExB,EAAO,KAAK,MAAM,KAAK,IAAM,QAAU,CAC3C,GAAQ,EACR,KAAK,IAAM,EAAO,QAEtB,KAAK,EAAM,CAGP,IAAM,EAAQ,IAAS,EAAK,SACxB,EAAO,KAAK,MAAM,KAAK,IAAM,QAAU,CAC3C,GAAQ,EACR,KAAK,IAAM,EAAO,QAEtB,MAAM,EAAM,CAGR,IAAM,EAAQ,IAAS,EAAK,SACxB,EAAO,KAAK,MAAM,KAAK,IAAM,QAAU,CAC3C,GAAQ,EACR,KAAK,IAAM,EAAO,QAEtB,MAAM,EAAM,CAGR,IAAM,EAAO,IAAS,EAAK,EACvB,IAAQ,EACR,KAAK,KAAO,EACP,IAAQ,IACb,KAAK,KAAO,GAEpB,OAAO,EAAM,CAET,IAAM,EAAa,IAAS,GAAM,EAC5B,EAAW,IAAS,GAAM,IAC1B,EAAU,IAAS,EAAK,MAKxB,EAAI,EAAU,IACd,EAAI,EAAS,MACf,IAAc,GACd,KAAK,UAAY,EACjB,KAAK,WAAa,EAClB,KAAK,UAAU,GAAK,EACpB,KAAK,UAAU,GAAK,EACpB,KAAK,KAAO,GACZ,KAAK,KAAO,IAGZ,KAAK,UAAY,EACjB,KAAK,WAAa,EAClB,KAAK,UAAU,GAAK,EACpB,KAAK,UAAU,GAAK,EACpB,KAAK,KAAO,GACZ,KAAK,KAAO,GAGpB,OAAO,EAAM,CAGT,IAAM,EAAa,IAAS,GAAM,EAE9B,EAAQ,IAAS,GAAM,MACvB,EAAO,QACP,GAAQ,OAGZ,IAAM,EAAM,OADK,IAAS,EAAK,GAGzB,EAAQ,EAAO,MACf,EAAQ,EAAM,KAChB,IAAc,GACd,KAAK,UAAY,EACjB,KAAK,WAAa,EAClB,KAAK,UAAU,GAAK,EACpB,KAAK,UAAU,GAAK,EACpB,KAAK,KAAO,IAGZ,KAAK,UAAY,EACjB,KAAK,WAAa,EAClB,KAAK,UAAU,GAAK,EACpB,KAAK,UAAU,GAAK,EACpB,KAAK,KAAO,GAGpB,UAAU,EAAO,EAAW,CAWpB,OAVA,IAAc,EACN,EAAQ,EAAK,KAAK,KAAO,KAAK,KAEjC,IAAc,EACX,EAAQ,EAAK,KAAK,KAAO,KAAK,KAEjC,IAAc,EACZ,KAAK,KAGL,KAAK,KAGpB,YAAY,EAAW,CAOnB,OANI,IAAc,EACP,KAAK,WACZ,IAAc,EACP,KAAK,WACZ,IAAc,EACP,KAAK,WACT,KAAK,WAEhB,MAAM,EAAM,CACR,IAAM,EAAQ,IAAS,GAAM,EACzB,IAAS,EACT,KAAK,UAAU,EAAK,CAEf,IAAS,EACd,KAAK,UAAU,EAAK,CAEf,IAAS,GACd,KAAK,WAAW,EAAK,CAG7B,UAAU,EAAM,CACZ,IAAM,EAAS,IAAS,GAAM,GACxB,EAAa,IAAS,GAAM,EAC5B,EAAU,IAAS,EAAK,MACxB,EAAQ,KAAK,UAAU,EAAO,EAAU,CAC1C,EAAQ,KAAK,YAAY,EAAU,CACvC,GAAS,KACL,EAAQ,IACR,KAAK,IAAM,GAEf,IAAI,EAAI,KAAK,IACT,EAAQ,KACR,GAAK,GACD,GAAK,GACL,KAEJ,EAAQ,IACR,EAAI,CAAC,GAET,IAAI,EACA,EACJ,GAAI,EAAQ,GACR,EAAQ,EACR,EAAI,KAAK,IAAI,EAAG,EAAM,EAAE,CACxB,EAAI,KAAK,IAAI,EAAK,KAAK,IAAI,EAAK,EAAM,EAAI,GAAI,CAAC,KAE9C,CAKD,IAAM,EAAO,EAAI,EAAQ,EACzB,EAAQ,KAAK,MAAM,EAAK,CACxB,EAAI,EAAO,EAEf,IAAM,EAAY,KAAK,aAAe,EAAS,KAAK,UACpD,KAAK,GAAK,KAAK,SAAS,GACxB,KAAK,eAAiB,EACtB,KAAK,iBAAmB,EACxB,KAAK,aAAe,IACpB,KAAK,gBAAkB,KAAK,GAC5B,KAAK,mBAAmB,IAAI,EAAM,CAC9B,EAAQ,IACR,EAAI,EAAM,GAEd,KAAK,KAAO,KAAK,GAAK,EACtB,KAAK,IAAM,KAAK,SAAS,KAAK,IAAI,CAEtC,UAAU,EAAM,CACZ,IAAM,EAAS,IAAS,GAAM,GACxB,EAAa,IAAS,GAAM,EAC5B,EAAY,IAAS,EAAK,MAC1B,EAAQ,KAAK,WAAW,EAAS,CACjC,EAAQ,KAAK,UAAU,EAAO,EAAU,CACxC,EAAQ,KAAK,YAAY,EAAU,CACrC,EAAQ,IACR,KAAK,IAAM,GAEf,IAAI,EAAI,KAAK,IACT,EAAQ,IACR,EAAI,KAAK,IAAI,EAAG,EAAM,EAAE,CACxB,EAAI,KAAK,IAAI,EAAK,KAAK,IAAI,EAAK,EAAM,EAAI,GAAI,CAAC,EAG/C,GAAK,EAEL,EAAQ,IACR,EAAI,EAAM,GAEd,KAAK,IAAM,EAAI,KAAK,IAAM,EAC1B,KAAK,IAAM,KAAK,SAAS,KAAK,IAAI,CAEtC,WAAW,EAAM,CACb,IAAM,EAAS,IAAS,GAAM,GACxB,EAAa,IAAS,GAAM,EAC5B,EAAQ,KAAK,UAAU,EAAO,EAAU,CAC9C,KAAK,IAAM,EACX,KAAK,IAAM,KAAK,SAAS,KAAK,IAAI,CAGtC,OAAQ,CACJ,OAAO,KAAK,GAEhB,aAAc,CACV,OAAO,KAAK,SAEhB,MAAM,EAAI,CACN,KAAK,GAAK,KAAK,IAAI,EAAG,KAAK,IAAI,KAAK,SAAW,EAAG,EAAG,CAAC,CAE1D,OAAO,EAAK,CACR,KAAK,IAAM,KAAK,SAAS,EAAI,CAEjC,QAAQ,EAAK,CACT,KAAK,KAAO,KAAK,SAAS,EAAI,CAOlC,YAAY,EAAK,EAAK,CACd,EAAM,GAAK,GAAQ,GAAK,KAAK,WAGjC,AAKI,EALA,GAAO,IAAM,GAAO,GACd,KAAK,MAAM,KAAK,IAAI,EAAG,KAAK,IAAI,SAAW,EAAI,CAAC,CAAG,KAAK,CAAG,KAI3D,KAAK,SAAS,EAAI,CAE5B,KAAK,UAAU,GAAO,GAM1B,mBAAmB,EAAM,CACrB,IAAI,EAAa,EAAK,MAAM,CAAC,aAAa,CAEtC,EAAS,GACT,EAAW,SAAS,IAAI,EACxB,EAAS,IACT,EAAa,EAAW,MAAM,EAAG,GAAG,EAE/B,EAAW,SAAS,IAAI,GAC7B,EAAS,IACT,EAAa,EAAW,MAAM,EAAG,GAAG,EAGxC,IAAM,EAAQ,KAAK,UAAU,CAC7B,GAAI,IAAW,IAAM,EAAM,UAAU,KAAgB,IAAA,GACjD,MAAO,CAAE,MAAO,EAAY,MAAO,EAAM,UAAU,GAAa,CAGpE,GAAI,IAAW,IAAM,IAAe,MAChC,MAAO,CAAE,MAAO,MAAO,MAAO,KAAK,IAAK,CAE5C,GAAI,IAAW,IAAM,IAAe,OAChC,MAAO,CAAE,MAAO,OAAQ,MAAO,KAAK,KAAM,CAG9C,IAAM,EAAM,KAAK,QAAQ,KAAK,GAAK,EAAE,KAAK,aAAa,GAAK,EAAW,CACvE,GAAI,GAAO,IAAW,GAAI,CACtB,IAAM,EAAO,SAAS,EAAI,MAAM,CAChC,GAAI,CAAC,MAAM,EAAK,EAAI,GAAQ,GAAK,GAAQ,GACrC,MAAO,CAAE,MAAO,OAAO,EAAK,KAAK,EAAI,KAAK,GAAI,MAAO,KAAK,UAAU,GAAO,CAInF,IAAM,EAAM,KAAK,SAAS,KAAK,GAAK,EAAE,KAAK,aAAa,GAAK,EAAW,CACxE,GAAI,GAAO,EAAI,QAAU,IAAA,GAAW,CAChC,IAAI,EAAO,EAAI,MACX,EAAY,GAShB,GARI,IAAW,KACX,EAAO,EAAa,cAAc,EAAI,MAAO,EAAI,KAAK,CACtD,EAAY,aAEP,IAAW,MAChB,EAAO,EAAa,WAAW,EAAI,MAAO,EAAI,KAAM,KAAK,aAAa,CACtE,EAAY,UAEZ,GAAQ,GAAK,EAAO,KAAK,UACzB,MAAO,CAAE,MAAO,OAAO,EAAK,KAAK,EAAI,OAAO,EAAU,GAAI,MAAO,KAAK,SAAS,GAAO,CAI9F,GAAI,IAAW,GAAI,CACf,IAAM,EAAa,EAAW,MAAM,mBAAmB,CACvD,GAAI,EAAY,CACZ,IAAM,EAAM,SAAS,EAAW,GAAG,CACnC,GAAI,GAAO,GAAK,EAAM,KAAK,UACvB,MAAO,CAAE,MAAO,SAAS,EAAI,GAAI,MAAO,KAAK,SAAS,GAAM,EAIxE,OAAO,KAEX,UAAW,CACP,MAAO,CACH,GAAI,KAAK,GACT,IAAK,KAAK,IACV,KAAM,KAAK,KACX,GAAI,KAAK,GACT,IAAK,KAAK,IAEV,UAAW,OAAO,YAAY,MAAM,KAAK,CAAE,OAAQ,GAAK,KAAK,SAAU,EAAG,EAAG,IAAM,CAC/E,IAAI,EAAO,IAAI,EAAE,GA+CjB,OA9CI,IAAM,EACN,EAAO,YACF,IAAM,EACX,EAAO,aACF,IAAM,EACX,EAAO,YACF,IAAM,EACX,EAAO,aACF,IAAM,EACX,EAAO,YACF,IAAM,EACX,EAAO,aACF,IAAM,EACX,EAAO,YACF,IAAM,EACX,EAAO,aACF,IAAM,EACX,EAAO,OACF,IAAM,EACX,EAAO,OACF,IAAM,GACX,EAAO,OACF,IAAM,GACX,EAAO,OACF,IAAM,GACX,EAAO,OACF,IAAM,GACX,EAAO,OACF,IAAM,GACX,EAAO,OACF,IAAM,GACX,EAAO,OACF,IAAM,GACX,EAAO,OACF,IAAM,GACX,EAAO,OACF,IAAM,GACX,EAAO,OACF,IAAM,GACX,EAAO,OACF,IAAM,GACX,EAAO,OACF,IAAM,GACX,EAAO,WACF,GAAK,IAAM,GAAK,KACrB,EAAO,MAAM,EAAI,MACd,CAAC,EAAM,KAAK,UAAU,GAAG,EAClC,CAAC,CAEH,MAAO,CACH,IAAK,KAAK,SACV,IAAM,KAAK,IAAM,KAAK,KAAO,EAC7B,IAAM,KAAK,MAAQ,EACnB,IAAM,KAAK,KAAO,EAClB,IAAM,KAAK,IAAM,EACpB,CAED,SAAU,CACN,KAAM,KAAK,KAAM,KAAM,KAAK,KAC5B,KAAM,KAAK,KAAM,KAAM,KAAK,KAC5B,KAAM,KAAK,KAAM,KAAM,KAAK,KAC/B,CACJ,CAEL,eAAgB,CACZ,OAAO,KAAK,WAEhB,gBAAiB,CACb,OAAO,MAAM,KAAK,KAAK,mBAAmB,CAE9C,cAAe,CACX,OAAO,KAAK,UAEhB,YAAa,CAYT,IAVA,KAAK,UAAY,KAAK,UAAU,GAChC,KAAK,WAAa,KAAK,UAAU,GACjC,KAAK,UAAY,KAAK,UAAU,GAChC,KAAK,WAAa,KAAK,UAAU,GACjC,KAAK,UAAY,KAAK,UAAU,GAChC,KAAK,WAAa,KAAK,UAAU,GACjC,KAAK,UAAY,KAAK,UAAU,GAChC,KAAK,WAAa,KAAK,UAAU,GAEjC,KAAK,MAAQ,KAAK,WAAa,EAAM,MAC9B,KAAK,MAAQ,GAChB,OAAK,KACT,KAAO,KAAK,KAAO,GACf,KAAK,MAAQ,EAEjB,IADA,KAAK,MAAQ,KAAK,WAAa,EAAM,MAC9B,KAAK,MAAQ,GAChB,OAAK,KACT,KAAO,KAAK,KAAO,GACf,KAAK,MAAQ,EAKjB,IAAM,EAAK,KAAK,WAAa,EAAM,KACnC,KAAK,MAAQ,EAAK,KAAK,KACvB,KAAK,MAAQ,EAAK,KAAK,KACvB,KAAK,KAAO,KAAK,IAAI,EAAa,QAAS,KAAK,IAAI,EAAa,QAAS,KAAK,KAAK,CAAC,CACrF,KAAK,KAAO,KAAK,IAAI,EAAa,QAAS,KAAK,IAAI,EAAa,QAAS,KAAK,KAAK,CAAC,CACrF,IAAM,EAAK,KAAK,WAAa,EAAM,KACnC,KAAK,MAAQ,EAAK,KAAK,KACvB,KAAK,MAAQ,EAAK,KAAK,KACvB,KAAK,KAAO,KAAK,IAAI,EAAa,QAAS,KAAK,IAAI,EAAa,QAAS,KAAK,KAAK,CAAC,CACrF,KAAK,KAAO,KAAK,IAAI,EAAa,QAAS,KAAK,IAAI,EAAa,QAAS,KAAK,KAAK,CAAC,CAEzF,sBAAuB,CAInB,KAAK,UAAU,GAAK,KAAK,KACzB,KAAK,UAAU,GAAK,KAAK,KACzB,KAAK,UAAU,IAAM,KAAK,KAC1B,KAAK,UAAU,IAAM,KAAK,KAC1B,KAAK,UAAU,IAAM,KAAK,KAC1B,KAAK,UAAU,IAAM,KAAK,KAE9B,aAAc,CACV,OAAO,KAAK,SAGhB,YAAY,EAAK,CAIb,OAFI,EAAM,OACE,EAAM,OAAW,MACtB,EAAM,MAEjB,WAAW,EAAK,CAIZ,OAFI,EAAM,MACE,EAAM,MAAS,IACpB,EAAM,IAEjB,WAAW,EAAK,CAIZ,OAFI,EAAM,MACE,EAAM,MAAS,KACpB,EAAM,KAEjB,WAAW,EAAK,CAIZ,OAFI,EAAM,MACE,EAAM,MAAS,GACpB,EAAM,GAEjB,WAAW,EAAK,CAIZ,OAFI,EAAM,OACE,EAAM,OAAW,MACtB,EAAM,MAEjB,SAAS,EAAK,CAKV,OAJI,EAAM,EAAa,QACZ,EAAa,QACpB,EAAM,EAAa,QACZ,EAAa,QACjB,EASX,YAAY,EAAQ,EAAY,EAAG,EAAY,CAC3C,KAAK,aAAe,GACpB,KAAK,YAAc,EACnB,KAAK,eAAiB,EACtB,KAAK,WAAa,EAClB,KAAK,cAAgB,EACrB,KAAK,gBAAkB,GAAc,KAErC,EAAO,6DAA6D,CACpE,QAAQ,IAAI,0CAA0C,GAAa,YAAY,GAAG,CAKtF,cAAe,CACX,KAAK,aAAe,GACpB,KAAK,YAAc,KACnB,QAAQ,IAAI,iCAAiC,KAAK,cAAc,gBAAgB,CAKpF,gBAAiB,CACb,OAAO,KAAK,aAKhB,kBAAmB,CACf,OAAO,KAAK,cAMhB,mBAAoB,CACX,QAAK,eAEV,KAAK,aACD,KAAK,eAAiB,GAAK,KAAK,YAAc,KAAK,gBAAgB,CACnE,IAAM,EAAa,KAAK,gBACxB,KAAK,cAAc,CACf,GACA,GAAY,EAGxB,SAAS,EAAI,EAAQ,EAAM,EAAW,CAIlC,GAHI,CAAC,KAAK,aAGN,KAAK,eAAiB,GACtB,OAGJ,IAAI,EAFW,EAAa,aAAa,IAAW,IAAI,EAAO,SAAS,GAAG,GAG3E,GAAI,IAAW,GAAM,CACjB,IAAM,EAAQ,IAAS,GAAM,EAC7B,GAAI,IAAS,EACT,EAAa,kBACR,IAAS,EAEd,YAEK,IAAS,IACd,EAAa,oBAEZ,IAAW,GAEhB,OAEJ,IAAM,EAAM,GAAG,KAAK,WAAW,GAAG,EAAG,GAAG,EAAW,GAC5C,KAAK,aAAa,GAAG,KAAK,eAAiB,GAA6B,GAAxB,KAAK,iBAAsB,GAAG,KAAK,gBAAkB,EAAI,KAAK,eAAiB,GAAG,GAAG,KAAK,eACjJ,KAAK,YAAY,EAAI,CACrB,KAAK,kBAGb,EAAa,QAAU,EAAO,EAAM,QACpC,EAAa,QAAU,CAAC,EAAa,QAErC,EAAa,aAAe,CACxB,EAAM,MAAO,EAAM,OAAQ,EAAM,MAAO,EAAM,OAC9C,EAAM,OAAQ,EAAM,OAAQ,EAAM,OAAQ,EAAM,OAChD,EAAM,OAAQ,EAAM,OAAQ,GAAM,OAAQ,GAAM,MAChD,GAAM,MAAO,GAAM,MAAO,GAAM,MAAO,GAAM,KAC7C,GAAM,MAAO,GAAM,MAAO,GAAM,OAAQ,GAAM,MAC9C,GAAM,MACT,CC5jCD,IAAM,EAAN,MAAM,UAAqB,qBAAsB,CAC/C,UAAoB,IAAI,EACxB,IAAc,CAAC,GAAK,GAAK,GAAI,CAC7B,SAAmB,GAGnB,YAAmC,OAMnC,eAAyB,EACzB,kBAA4B,EAC5B,OAAwB,2BAA6B,GAErD,aAAc,CACZ,OAAO,CACP,KAAK,KAAK,WAAa,CAAE,UAAW,CAClC,OAAQ,EAAK,KAAb,CACE,IAAK,cACH,KAAK,UAAU,YAAY,IAAI,YAAY,EAAK,YAAY,CAAC,CAC7D,MACF,IAAK,SACH,KAAK,IAAI,EAAK,OAAS,EAAK,MAC5B,MACF,IAAK,SACH,KAAK,SAAW,EAAK,OACrB,MACF,IAAK,iBACH,KAAK,YAAc,EAAK,OAAS,SAAW,SAAW,OACvD,QAKR,QAAQ,EAA0B,EAAoC,CACpE,IAAM,EAAQ,EAAO,GACf,EAAS,EAAQ,GACvB,GAAI,CAAC,GAAO,QAAU,CAAC,GAAQ,OAAQ,MAAO,GAE9C,IAAM,EAAM,EAAM,GACZ,EAAM,EAAM,IAAM,EAClB,EAAO,EAAO,GACd,EAAO,EAAO,IAAM,EAE1B,GAAI,KAAK,SAGP,OAFA,EAAK,IAAI,EAAI,CACT,EAAO,IAAI,EAAK,IAAI,EAAI,CACrB,GAGT,IAAM,EAAK,YAAY,KAAK,CAC5B,KAAK,UAAU,aAAa,EAAK,EAAK,EAAM,EAC1C,KAAK,IAAI,GAAI,KAAK,IAAI,GAAI,KAAK,IAAI,GAAG,CACxC,IAAM,GAAa,YAAY,KAAK,CAAG,GAAM,IAqB7C,MAdA,MAAK,eAAiB,KAAK,iBAAmB,EAC1C,EACA,KAAK,eAAiB,IAAO,EAAY,IAIzC,KAAK,cAAgB,QAAU,EAAO,IACxC,EAAK,IAAI,EAAK,CAGZ,EAAE,KAAK,mBAAqB,EAAa,6BAC3C,KAAK,kBAAoB,EACzB,KAAK,KAAK,YAAY,CAAE,KAAM,YAAa,GAAI,KAAK,eAAgB,CAAC,EAEhE,KAIX,kBAAkB,gBAAiB,EAAa"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@audiofab-io/easy-spin-ui",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.5",
|
|
4
4
|
"description": "Shared React components and FV-1 simulation runtime for Audiofab's Easy Spin pedal — used by the Easy Spin web tool and the FV-1 VS Code extension.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|