{"version":3,"file":"Passage-BH3rIDg7.js","names":["#buffer","#channelBuffers","#convolver","#wetGain","#preTapGain","#loaded","#host","#phase","#context","#toneName","#exitPassageCallback","#scheduledClickOscs","#completeTimer","#phase","#direction","#snapshot","#listeners","#audioContext","#ownsContext","#ensureAudioContext","#currentBeatIndex","#sporadiciser","#nextBeatTime","#setState","#schedulerTimer","#schedule","#tapTimes","#tapResetTimer","#DROP_RAMP_S","#RETURN_RAMP_S","#SWELL_LEAD_S","#REVERB_FADE_IN_S","#REVERB_FADE_OUT_S","#MIN_SILENCE_S","#MAX_SILENCE_S","#MIN_AUDIBLE_S","#MAX_AUDIBLE_S","#MIN_DROP_BEATS","#MAX_DROP_BEATS","#host","#isMuted","#hasLastPlayhead","#lastPlayheadTime","#hasPendingDrop","#pendingDropAt","#setMuteGate","#unmuteAt","#nextCheck","#sporadiciser","#scheduleDrop","#gLL","#gRL","#gLR","#gRR","#ctx","#gLL","#gRL","#gLR","#gRR","#ctx","SignalsmithStretch","#workletUrl","#snapshot","#countIn","#makeCountInHost","#sporadic","#makeSporadiciserHost","#audioContext","#muteGateNode","#reverbFill","#trackBeats","#requireContext","#stretch","#stretchLatencySeconds","#setState","#listeners","#notify","#disposeNodes","#workletLoaded","#file","#initializeNodes","#applyPhaseVocoder","#stopInternal","#eqBandNodes","#analyserNode","#stereoFocusNode","#karaokeNode","#isDraggingSection","#requireStretch","#setupSignalChain","#startPlayback","#playheadAnchor","#eqBandGains","#applyEQ","#stereoFocus","#karaoke","#updatePlayheadAnchor"],"sources":["../../../node_modules/zustand/esm/vanilla/shallow.mjs","../../../node_modules/zustand/esm/react/shallow.mjs","../../../app/frontend/src/hooks/useCurrentTranscription.ts","../../../packages/audio-engine/src/PlayheadCalculator.ts","../../../packages/audio-engine/src/beatDetection.ts","../../../packages/audio-engine/src/AudioFile.ts","../../../packages/audio-engine/src/ReverbFill.ts","../../../packages/audio-engine/src/countInGrid.ts","../../../packages/audio-engine/src/attackSnap.ts","../../../packages/audio-engine/src/clickScheduler.ts","../../../packages/audio-engine/src/CountInController.ts","../../../packages/audio-engine/src/MetronomeEngine.ts","../../../packages/audio-engine/src/SporadiciserController.ts","../../../packages/audio-engine/src/StereoFocusNode.ts","../../../packages/audio-engine/src/KaraokeNode.ts","../../../packages/audio-engine/src/vendor/SignalsmithStretch.mjs","../../../packages/audio-engine/src/AudioEngine.ts","../../../app/frontend/src/hooks/useAudioEngine.ts","../../../app/frontend/src/hooks/usePassages.ts","../../../app/frontend/src/models/Passage.ts"],"sourcesContent":["const isIterable = (obj) => Symbol.iterator in obj;\nconst hasIterableEntries = (value) => (\n // HACK: avoid checking entries type\n \"entries\" in value\n);\nconst compareEntries = (valueA, valueB) => {\n const mapA = valueA instanceof Map ? valueA : new Map(valueA.entries());\n const mapB = valueB instanceof Map ? valueB : new Map(valueB.entries());\n if (mapA.size !== mapB.size) {\n return false;\n }\n for (const [key, value] of mapA) {\n if (!mapB.has(key) || !Object.is(value, mapB.get(key))) {\n return false;\n }\n }\n return true;\n};\nconst compareIterables = (valueA, valueB) => {\n const iteratorA = valueA[Symbol.iterator]();\n const iteratorB = valueB[Symbol.iterator]();\n let nextA = iteratorA.next();\n let nextB = iteratorB.next();\n while (!nextA.done && !nextB.done) {\n if (!Object.is(nextA.value, nextB.value)) {\n return false;\n }\n nextA = iteratorA.next();\n nextB = iteratorB.next();\n }\n return !!nextA.done && !!nextB.done;\n};\nfunction shallow(valueA, valueB) {\n if (Object.is(valueA, valueB)) {\n return true;\n }\n if (typeof valueA !== \"object\" || valueA === null || typeof valueB !== \"object\" || valueB === null) {\n return false;\n }\n if (Object.getPrototypeOf(valueA) !== Object.getPrototypeOf(valueB)) {\n return false;\n }\n if (isIterable(valueA) && isIterable(valueB)) {\n if (hasIterableEntries(valueA) && hasIterableEntries(valueB)) {\n return compareEntries(valueA, valueB);\n }\n return compareIterables(valueA, valueB);\n }\n return compareEntries(\n { entries: () => Object.entries(valueA) },\n { entries: () => Object.entries(valueB) }\n );\n}\n\nexport { shallow };\n","import React from 'react';\nimport { shallow } from 'zustand/vanilla/shallow';\n\nfunction useShallow(selector) {\n const prev = React.useRef(void 0);\n return (state) => {\n const next = selector(state);\n return shallow(prev.current, next) ? prev.current : prev.current = next;\n };\n}\n\nexport { useShallow };\n","import { create } from \"zustand\";\nimport { useShallow } from \"zustand/react/shallow\";\nimport type { BeatType } from \"@passages/audio-engine\";\n\ntype PassageData = {\n id: string;\n name: string | null;\n start: number;\n end: number;\n countInEnabled?: boolean;\n countInEmphasis?: BeatType[];\n locked?: boolean;\n};\n\nexport type LoadingPhase = \"downloading\" | \"decoding\" | \"initializing\" | null;\n\ntype PlaybackMode = \"full\" | \"passage\";\n\ntype CurrentTranscriptionState = {\n transcriptionId: string | null;\n title: string | null;\n artist: string | null;\n filename: string | null;\n initialPassages: PassageData[];\n loadingPhase: LoadingPhase;\n downloadProgress: number;\n isLoading: boolean;\n error: string | null;\n playbackMode: PlaybackMode;\n activePassageId: string | null;\n activePassageName: string | null;\n passageStartTime: number | null;\n passageEndTime: number | null;\n\n loadTranscription: (\n transcriptionId: string,\n title: string | null,\n artist: string | null,\n filename: string,\n passages: PassageData[],\n ) => void;\n loadPassage: (\n transcriptionId: string,\n title: string | null,\n artist: string | null,\n passage: {\n id: string;\n name: string | null;\n startTime: number;\n endTime: number;\n },\n ) => void;\n setLoadingPhase: (phase: LoadingPhase) => void;\n setDownloadProgress: (progress: number) => void;\n setIsLoading: (isLoading: boolean) => void;\n setError: (error: string | null) => void;\n clear: () => void;\n};\n\nexport const useCurrentTranscriptionStore = create(\n (set) => ({\n transcriptionId: null,\n title: null,\n artist: null,\n filename: null,\n initialPassages: [],\n loadingPhase: null,\n downloadProgress: 0,\n isLoading: false,\n error: null,\n playbackMode: \"full\",\n activePassageId: null,\n activePassageName: null,\n passageStartTime: null,\n passageEndTime: null,\n\n loadTranscription: (transcriptionId, title, artist, filename, passages) =>\n set({\n transcriptionId,\n title,\n artist,\n filename,\n initialPassages: passages,\n loadingPhase: \"downloading\",\n downloadProgress: 0,\n isLoading: true,\n error: null,\n playbackMode: \"full\",\n activePassageId: null,\n activePassageName: null,\n passageStartTime: null,\n passageEndTime: null,\n }),\n\n loadPassage: (transcriptionId, title, artist, passage) =>\n set({\n transcriptionId,\n title,\n artist,\n initialPassages: [],\n loadingPhase: \"downloading\",\n downloadProgress: 0,\n isLoading: true,\n error: null,\n playbackMode: \"passage\",\n activePassageId: passage.id,\n activePassageName: passage.name,\n passageStartTime: passage.startTime,\n passageEndTime: passage.endTime,\n }),\n\n setLoadingPhase: (loadingPhase) =>\n set({\n loadingPhase,\n isLoading: loadingPhase !== null,\n }),\n\n setDownloadProgress: (downloadProgress) => set({ downloadProgress }),\n\n setIsLoading: (isLoading) =>\n set({\n isLoading,\n loadingPhase: isLoading ? \"downloading\" : null,\n }),\n\n setError: (error) => set({ error }),\n clear: () =>\n set({\n transcriptionId: null,\n title: null,\n artist: null,\n filename: null,\n initialPassages: [],\n loadingPhase: null,\n downloadProgress: 0,\n isLoading: false,\n error: null,\n playbackMode: \"full\",\n activePassageId: null,\n activePassageName: null,\n passageStartTime: null,\n passageEndTime: null,\n }),\n }),\n);\n\nexport const useCurrentTranscription = () => {\n return useCurrentTranscriptionStore(\n useShallow(\n ({\n transcriptionId,\n title,\n artist,\n filename,\n initialPassages,\n isLoading,\n loadingPhase,\n downloadProgress,\n error,\n playbackMode,\n activePassageId,\n activePassageName,\n passageStartTime,\n passageEndTime,\n loadTranscription,\n loadPassage,\n setIsLoading,\n setLoadingPhase,\n setDownloadProgress,\n setError,\n clear,\n }) => ({\n transcriptionId,\n title,\n artist,\n filename,\n initialPassages,\n isLoading,\n loadingPhase,\n downloadProgress,\n error,\n playbackMode,\n activePassageId,\n activePassageName,\n passageStartTime,\n passageEndTime,\n loadTranscription,\n loadPassage,\n setIsLoading,\n setLoadingPhase,\n setDownloadProgress,\n setError,\n clear,\n }),\n ),\n );\n};\n","/**\n * PlayheadCalculator - Pure functions for playhead timing calculations\n *\n * All functions are pure (no side effects, no Web Audio dependencies).\n * This makes them trivially testable without mocking.\n *\n * Note: With stretch.inputTime as source of truth, most timing logic is handled\n * by the worklet. These functions primarily support boundary collision detection.\n */\n\n/**\n * Check if the playhead has reached or passed the end boundary\n *\n * @param playheadTime - Current absolute playhead position\n * @param endAt - End boundary\n * @returns True if playhead has reached or passed the end\n */\nexport function hasReachedEnd(playheadTime: number, endAt: number): boolean {\n return playheadTime >= endAt;\n}\n\n/**\n * Determine what action to take when playhead reaches the end boundary\n *\n * @param isLooping - Whether looping is enabled\n * @returns Action to take: \"loop\" or \"stop\"\n */\nexport function determineEndBehavior(isLooping: boolean): \"loop\" | \"stop\" {\n return isLooping ? \"loop\" : \"stop\";\n}\n\n/**\n * Detect if the start boundary was dragged past the playhead (collision)\n *\n * @param newStartAt - New start boundary\n * @param absolutePlayhead - Current absolute playhead position\n * @returns True if start boundary crossed the playhead\n */\nexport function detectStartBoundaryCollision(\n newStartAt: number,\n absolutePlayhead: number,\n): boolean {\n return newStartAt > absolutePlayhead;\n}\n\n/**\n * Detect if the end boundary was dragged before the playhead (collision)\n *\n * @param newEndAt - New end boundary\n * @param absolutePlayhead - Current absolute playhead position\n * @returns True if end boundary crossed the playhead\n */\nexport function detectEndBoundaryCollision(\n newEndAt: number,\n absolutePlayhead: number,\n): boolean {\n return newEndAt <= absolutePlayhead;\n}\n\n/**\n * Determine action to take when boundaries are updated during playback\n *\n * @param newStartAt - New start boundary\n * @param newEndAt - New end boundary\n * @param absolutePlayhead - Current absolute playhead position\n * @param isLooping - Whether looping is enabled\n * @returns Action descriptor with collision status\n */\nexport function determineBoundaryUpdateAction(\n newStartAt: number,\n newEndAt: number,\n absolutePlayhead: number,\n isLooping: boolean,\n): {\n action: \"restart\" | \"loop\" | \"stop\" | \"no_collision\";\n collision: boolean;\n} {\n // Check for start boundary collision\n if (detectStartBoundaryCollision(newStartAt, absolutePlayhead)) {\n return {\n action: \"restart\",\n collision: true,\n };\n }\n\n // Check for end boundary collision\n if (detectEndBoundaryCollision(newEndAt, absolutePlayhead)) {\n if (isLooping) {\n return {\n action: \"loop\",\n collision: true,\n };\n } else {\n return {\n action: \"stop\",\n collision: true,\n };\n }\n }\n\n // No collision - stretch.inputTime maintains playhead position automatically\n return {\n action: \"no_collision\",\n collision: false,\n };\n}\n\n/**\n * Calculate the duration of a section\n *\n * @param startAt - Start boundary\n * @param endAt - End boundary\n * @returns Duration in seconds\n */\nexport function calculateSectionDuration(\n startAt: number,\n endAt: number,\n): number {\n return Math.max(0, endAt - startAt);\n}\n\n/**\n * Check if a position is within section boundaries\n *\n * @param position - Position to check\n * @param startAt - Start boundary\n * @param endAt - End boundary\n * @returns True if position is within [startAt, endAt)\n */\nexport function isWithinBoundaries(\n position: number,\n startAt: number,\n endAt: number,\n): boolean {\n return position >= startAt && position < endAt;\n}\n\n/**\n * Clamp a position to section boundaries\n *\n * @param position - Position to clamp\n * @param startAt - Start boundary\n * @param endAt - End boundary\n * @returns Clamped position\n */\nexport function clampToBoundaries(\n position: number,\n startAt: number,\n endAt: number,\n): number {\n return Math.max(startAt, Math.min(endAt, position));\n}\n","/**\n * Beat Detection with Tempo-Varying Tracking\n *\n * This module implements a dynamic beat tracker that can follow tempo changes\n * in audio files, making it suitable for non-quantized, live, or variable-tempo music.\n *\n * Algorithm Overview:\n * 1. Compute onset strength function via spectral flux\n * 2. Extract onset candidates via peak picking\n * 3. Use dynamic programming to find optimal beat path allowing tempo variation\n */\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface BeatDetectionResult {\n transcriptionId?: string;\n detectedAt?: string;\n model?: string;\n beats: number[]; // beat timestamps in seconds\n downbeats: number[]; // downbeat timestamps in seconds\n onsets?: number[]; // all original detections (server-side processed)\n measures?: number[]; // measure/bar markers (server-side processed)\n metadata: {\n averageBPM?: number;\n bpm?: number; // more accurate BPM from processed beats\n timeSignature?: [number, number]; // [beats per measure, note value]\n confidence?: number;\n beatCount: number;\n downbeatCount: number;\n beatInterval?: number; // samples between beats (client-side only)\n beatOrigin?: number; // first beat sample (client-side only)\n };\n}\n\nexport interface OnsetCandidate {\n sample: number;\n strength: number;\n}\n\n// ============================================================================\n// Configuration\n// ============================================================================\n\nconst CONFIG = {\n // Envelope parameters (much faster than FFT)\n hopSize: 256, // Smaller hop for better time resolution\n envelopeWindowSize: 1024, // Smaller window for sharper onset detection\n\n // Onset detection - more sensitive for attack snapping\n onsetThreshold: 0.02, // relative to max strength\n minOnsetSpacing: 0.03, // seconds between onsets\n\n // Beat tracking\n minBPM: 60,\n maxBPM: 180,\n targetBPM: 120, // prior/preference for ambiguous cases\n\n // Dynamic programming\n tempoChangeWeight: 0.3, // cost for tempo variation\n onsetWeight: 0.7, // reward for hitting strong onsets\n};\n\n// ============================================================================\n// Utilities\n// ============================================================================\n\nexport function mixToMono(channels: Float32Array[]): Float32Array {\n const mono = new Float32Array(channels[0].length);\n const numChannels = channels.length;\n\n for (let i = 0; i < mono.length; i++) {\n let sum = 0;\n for (let ch = 0; ch < numChannels; ch++) {\n sum += channels[ch][i];\n }\n mono[i] = sum / numChannels;\n }\n\n return mono;\n}\n\n/**\n * Compute peak amplitude in a window (better for transient detection than RMS)\n */\nexport function computePeakAmplitude(\n signal: Float32Array,\n offset: number,\n size: number,\n): number {\n let peak = 0;\n for (let i = 0; i < size; i++) {\n const idx = offset + i;\n if (idx < signal.length) {\n const amplitude = Math.abs(signal[idx]);\n if (amplitude > peak) {\n peak = amplitude;\n }\n }\n }\n return peak;\n}\n\n// ============================================================================\n// Onset Detection\n// ============================================================================\n\n/**\n * Compute onset strength by detecting sudden amplitude increases (attack detection)\n */\nexport function computeOnsetStrength(\n mono: Float32Array,\n sampleRate: number,\n): Float32Array {\n const windowSize = CONFIG.envelopeWindowSize;\n const hopSize = CONFIG.hopSize;\n const numFrames = Math.floor((mono.length - windowSize) / hopSize);\n\n // First pass: compute amplitude envelope\n const envelope = new Float32Array(numFrames);\n for (let frame = 0; frame < numFrames; frame++) {\n const offset = frame * hopSize;\n envelope[frame] = computePeakAmplitude(mono, offset, windowSize);\n }\n\n // Second pass: compute derivative (rate of change)\n const derivative = new Float32Array(numFrames);\n for (let frame = 1; frame < numFrames; frame++) {\n const diff = envelope[frame] - envelope[frame - 1];\n derivative[frame] = Math.max(0, diff); // Only positive changes (attacks)\n }\n\n // Third pass: find local maxima of derivative (onset points)\n // This finds where the attack is steepest, which corresponds to the transient start\n const onsetStrength = new Float32Array(numFrames);\n for (let frame = 2; frame < numFrames - 2; frame++) {\n const current = derivative[frame];\n const prev = derivative[frame - 1];\n const next = derivative[frame + 1];\n\n // Local maximum in derivative = onset point\n if (current > prev && current >= next) {\n onsetStrength[frame] = current;\n }\n }\n\n // Normalize\n const maxStrength = Math.max(...Array.from(onsetStrength));\n if (maxStrength > 0) {\n for (let i = 0; i < onsetStrength.length; i++) {\n onsetStrength[i] /= maxStrength;\n }\n }\n\n return onsetStrength;\n}\n\n/**\n * Extract onset candidates via peak picking\n */\nexport function extractOnsetCandidates(\n onsetStrength: Float32Array,\n sampleRate: number,\n hopSize: number,\n): OnsetCandidate[] {\n const candidates: OnsetCandidate[] = [];\n const threshold = CONFIG.onsetThreshold;\n const minSpacingSamples = CONFIG.minOnsetSpacing * sampleRate;\n\n let lastOnsetSample = -minSpacingSamples;\n\n for (let i = 1; i < onsetStrength.length - 1; i++) {\n const strength = onsetStrength[i];\n\n // Peak detection: local maximum above threshold\n if (\n strength > threshold &&\n strength > onsetStrength[i - 1] &&\n strength > onsetStrength[i + 1]\n ) {\n const sample = i * hopSize;\n\n // Enforce minimum spacing\n if (sample - lastOnsetSample >= minSpacingSamples) {\n candidates.push({ sample, strength });\n lastOnsetSample = sample;\n }\n }\n }\n\n return candidates;\n}\n\n// ============================================================================\n// Dynamic Beat Tracking\n// ============================================================================\n\n/**\n * Estimate global tempo from onset candidates using autocorrelation\n */\nexport function estimateTempo(\n candidates: OnsetCandidate[],\n sampleRate: number,\n): number {\n if (candidates.length < 2) return CONFIG.targetBPM;\n\n const minInterval = (60 / CONFIG.maxBPM) * sampleRate;\n const maxInterval = (60 / CONFIG.minBPM) * sampleRate;\n\n // Build histogram of inter-onset intervals\n const histogramSize = Math.ceil(maxInterval - minInterval);\n const histogram = new Float32Array(histogramSize);\n\n for (let i = 1; i < candidates.length; i++) {\n const interval = candidates[i].sample - candidates[i - 1].sample;\n if (interval >= minInterval && interval <= maxInterval) {\n const binIdx = Math.floor(interval - minInterval);\n histogram[binIdx] += candidates[i].strength * candidates[i - 1].strength;\n }\n }\n\n // Find peak in histogram\n let maxBin = 0;\n let maxValue = 0;\n for (let i = 0; i < histogramSize; i++) {\n if (histogram[i] > maxValue) {\n maxValue = histogram[i];\n maxBin = i;\n }\n }\n\n const beatInterval = minInterval + maxBin;\n const bpm = (60 * sampleRate) / beatInterval;\n\n return bpm;\n}\n\n/**\n * Generate beat grid with tempo tracking\n */\nexport function generateBeatGrid(\n candidates: OnsetCandidate[],\n sampleRate: number,\n totalSamples: number,\n): number[] {\n if (candidates.length === 0) return [];\n\n // Estimate global tempo\n const globalBPM = estimateTempo(candidates, sampleRate);\n const globalInterval = (60 / globalBPM) * sampleRate;\n\n // Find the best phase by testing different starting points\n // This ensures the grid aligns with actual beats\n const phaseSearchWindow = Math.min(10, candidates.length);\n let bestPhase = candidates[0].sample;\n let bestPhaseScore = 0;\n\n for (let i = 0; i < phaseSearchWindow; i++) {\n const testPhase = candidates[i].sample;\n let score = 0;\n\n // Score this phase by checking how many strong onsets align with the grid\n for (const candidate of candidates) {\n const beatsSincePhase = (candidate.sample - testPhase) / globalInterval;\n const nearestBeat = Math.round(beatsSincePhase);\n const distance = Math.abs(beatsSincePhase - nearestBeat);\n\n // If this onset is close to a grid position, add its strength to the score\n if (distance < 0.15 && nearestBeat >= 0) {\n score += candidate.strength;\n }\n }\n\n if (score > bestPhaseScore) {\n bestPhaseScore = score;\n bestPhase = testPhase;\n }\n }\n\n const firstBeat = bestPhase;\n\n // Generate initial regular grid\n const beats: number[] = [];\n let currentInterval = globalInterval;\n let currentSample = firstBeat;\n\n while (currentSample < totalSamples) {\n beats.push(Math.round(currentSample));\n\n // Find nearby onsets to adjust tempo slightly\n const windowStart = currentSample + globalInterval * 0.7;\n const windowEnd = currentSample + globalInterval * 1.3;\n\n let bestCandidate: OnsetCandidate | null = null;\n let bestScore = 0;\n\n for (const candidate of candidates) {\n if (candidate.sample >= windowStart && candidate.sample <= windowEnd) {\n // Score based on strength and proximity to expected position\n const expectedNext = currentSample + currentInterval;\n const distance = Math.abs(candidate.sample - expectedNext);\n const proximityScore = 1 - distance / (globalInterval * 0.3);\n const score = candidate.strength * Math.max(0, proximityScore);\n\n if (score > bestScore) {\n bestScore = score;\n bestCandidate = candidate;\n }\n }\n }\n\n // Update interval based on best match (with damping to prevent wild swings)\n if (bestCandidate && bestScore > 0.3) {\n const measuredInterval = bestCandidate.sample - currentSample;\n currentInterval = currentInterval * 0.85 + measuredInterval * 0.15; // Heavy damping\n currentSample = bestCandidate.sample;\n } else {\n // No good match, continue with current interval\n currentSample += currentInterval;\n }\n }\n\n // Refinement pass: snap each beat to nearest strong onset within a small window\n const refinedBeats = beats.map((beat) => {\n const snapWindow = globalInterval * 0.15; // 15% window for snapping\n let bestSnap = beat;\n let bestScore = 0;\n\n for (const candidate of candidates) {\n const distance = Math.abs(candidate.sample - beat);\n if (distance < snapWindow) {\n // Score favors strong onsets that are close to expected position\n const proximityBonus = 1 - distance / snapWindow;\n const score = candidate.strength * (0.5 + 0.5 * proximityBonus);\n if (score > bestScore) {\n bestScore = score;\n bestSnap = candidate.sample;\n }\n }\n }\n\n return bestSnap;\n });\n\n return refinedBeats;\n}\n\n/**\n * Reduce beat grid to every Nth beat (for less dense grids)\n */\nexport function reduceBeatGrid(\n beatSamples: number[],\n divisor: number,\n): number[] {\n if (divisor <= 1) return beatSamples;\n return beatSamples.filter((_, index) => index % divisor === 0);\n}\n\n// ============================================================================\n// Main Detection Function\n// ============================================================================\n\n/**\n * Detect beats in audio with tempo-varying tracking\n */\nexport async function detectBeats(\n channels: Float32Array[],\n sampleRate: number,\n): Promise {\n // Step 1: Mix to mono\n const mono = mixToMono(channels);\n\n // Step 2: Compute onset strength function\n const onsetStrength = computeOnsetStrength(mono, sampleRate);\n\n // Step 3: Extract onset candidates\n let candidates = extractOnsetCandidates(\n onsetStrength,\n sampleRate,\n CONFIG.hopSize,\n );\n\n // Performance: limit candidates if too many (keep strongest)\n if (candidates.length > 2000) {\n candidates.sort((a, b) => b.strength - a.strength);\n candidates = candidates.slice(0, 2000);\n candidates.sort((a, b) => a.sample - b.sample); // Re-sort by time\n }\n\n // Step 4: Use all detected onsets as beats\n const beatSamples = candidates\n .map((candidate) => candidate.sample)\n .sort((a, b) => a - b);\n\n // Step 5: Calculate average BPM\n let averageBPM = CONFIG.targetBPM;\n if (beatSamples.length > 1) {\n const totalDuration =\n (beatSamples[beatSamples.length - 1] - beatSamples[0]) / sampleRate;\n const numIntervals = beatSamples.length - 1;\n averageBPM = (numIntervals / totalDuration) * 60;\n }\n\n // Step 6: Estimate confidence (based on how many candidates became beats)\n const confidence = beatSamples.length / Math.max(1, candidates.length);\n\n // Calculate beat interval\n const beatInterval =\n beatSamples.length > 1\n ? (beatSamples[beatSamples.length - 1] - beatSamples[0]) /\n (beatSamples.length - 1)\n : sampleRate; // fallback to 1 second\n\n const beatOrigin = beatSamples.length > 0 ? beatSamples[0] : 0;\n\n // Convert samples to seconds\n const beats = beatSamples.map((sample) => sample / sampleRate);\n\n // For client-side detection, we don't distinguish downbeats\n const downbeats: number[] = [];\n\n return {\n beats,\n downbeats,\n metadata: {\n averageBPM,\n confidence,\n beatCount: beats.length,\n downbeatCount: downbeats.length,\n beatInterval,\n beatOrigin,\n },\n };\n}\n","export class AudioFile {\n #buffer: AudioBuffer;\n #channelBuffers: Float32Array[] = [];\n\n constructor(buffer: AudioBuffer) {\n this.#buffer = buffer;\n }\n\n get duration() {\n return this.#buffer.duration;\n }\n\n get length() {\n return this.buffers[0].length;\n }\n\n get numberOfChannels() {\n return this.#buffer.numberOfChannels;\n }\n\n get buffers(): Float32Array[] {\n if (this.#channelBuffers.length == 0) {\n for (let c = 0; c < this.#buffer.numberOfChannels; ++c) {\n const channelData = new Float32Array(\n Math.round(this.#buffer.sampleRate * this.#buffer.duration),\n );\n this.#buffer.copyFromChannel(channelData, c, 0);\n\n this.#channelBuffers.push(channelData);\n }\n }\n\n return this.#channelBuffers;\n }\n\n sampleAsPercentage(samples: number) {\n return samples / this.length;\n }\n}\n","// ============================================================================\n// ReverbFill — Convolution reverb that fills sporadic dropout gaps\n//\n// Self-contained module: all reverb nodes and logic live here.\n// AudioEngine integration is minimal (4-5 marked touchpoints).\n// To remove this feature, delete this file and grep for \"// ReverbFill\".\n// ============================================================================\n\nconst REVERB_VOLUME_LEVEL = 0.1;\nconst REVERB_SWELL_LEVEL = 0.6;\nconst PRE_TAP_DRIVE = 2.0;\nconst PRE_TAP_CLOSE_S = 0.06;\n\nexport class ReverbFill {\n #convolver: ConvolverNode | null = null;\n #wetGain: GainNode | null = null;\n // Pre-gate tap into the convolver. Normally silent; opens briefly before an\n // unmute so the convolver has fresh signal to reverberate during the swell.\n #preTapGain: GainNode | null = null;\n #loaded = false;\n\n /**\n * Initialize the convolver with an impulse response.\n * Fails silently — reverb is a nice-to-have, not critical.\n */\n async init(ctx: AudioContext, irUrl: string): Promise {\n try {\n const response = await fetch(irUrl);\n if (!response.ok) return;\n\n const arrayBuffer = await response.arrayBuffer();\n const audioBuffer = await ctx.decodeAudioData(arrayBuffer);\n\n this.#convolver = ctx.createConvolver();\n this.#convolver.buffer = audioBuffer;\n\n this.#wetGain = ctx.createGain();\n this.#wetGain.gain.value = 0; // Silent until a dropout happens\n\n this.#preTapGain = ctx.createGain();\n this.#preTapGain.gain.value = 0; // Silent except during the pre-unmute swell\n\n this.#loaded = true;\n } catch {\n // IR load failed — reverb simply won't be available\n this.#convolver = null;\n this.#wetGain = null;\n this.#preTapGain = null;\n this.#loaded = false;\n }\n }\n\n /**\n * Wire the parallel reverb path. Two taps feed the same convolver:\n * - postGateSource: post-mute-gate, normal path (drop-out trail effect)\n * - preGateSource: pre-mute-gate, gated by #preTapGain (pre-unmute swell)\n * Both sum into the convolver, then through #wetGain to destination.\n */\n connect(\n postGateSource: AudioNode,\n preGateSource: AudioNode,\n destination: AudioNode,\n ): void {\n if (\n !this.#loaded ||\n !this.#convolver ||\n !this.#wetGain ||\n !this.#preTapGain\n )\n return;\n\n this.#convolver.disconnect();\n this.#wetGain.disconnect();\n this.#preTapGain.disconnect();\n\n postGateSource.connect(this.#convolver);\n preGateSource.connect(this.#preTapGain);\n this.#preTapGain.connect(this.#convolver);\n this.#convolver.connect(this.#wetGain);\n this.#wetGain.connect(destination);\n }\n\n /**\n * Tear down reverb connections (called before reconnecting the chain).\n */\n disconnect(): void {\n this.#convolver?.disconnect();\n this.#wetGain?.disconnect();\n this.#preTapGain?.disconnect();\n }\n\n /**\n * Fade reverb in — called when the dry signal drops out.\n */\n fadeIn(ctx: AudioContext, rampSeconds: number): void {\n if (!this.#wetGain) return;\n\n const now = ctx.currentTime;\n this.#wetGain.gain.cancelScheduledValues(now);\n this.#wetGain.gain.setValueAtTime(this.#wetGain.gain.value, now);\n this.#wetGain.gain.linearRampToValueAtTime(\n REVERB_VOLUME_LEVEL,\n now + rampSeconds,\n );\n }\n\n /**\n * Fade reverb out — called when the dry signal returns.\n * Uses a slightly longer ramp for a smoother tail decay.\n */\n fadeOut(ctx: AudioContext, rampSeconds: number): void {\n if (!this.#wetGain) return;\n\n const now = ctx.currentTime;\n this.#wetGain.gain.cancelScheduledValues(now);\n this.#wetGain.gain.setValueAtTime(this.#wetGain.gain.value, now);\n this.#wetGain.gain.linearRampToValueAtTime(0, now + rampSeconds);\n }\n\n /**\n * Pre-unmute swell. Opens the pre-gate tap so the convolver gets fresh\n * signal, ramps wetGain up to a brief peak over `swellLeadSec`, then decays\n * over `fadeOutSec`. Pre-tap closes once dry takes over via the post-tap.\n */\n swell(ctx: AudioContext, swellLeadSec: number, fadeOutSec: number): void {\n if (!this.#wetGain || !this.#preTapGain) return;\n\n const now = ctx.currentTime;\n const peakAt = now + swellLeadSec;\n\n this.#preTapGain.gain.cancelScheduledValues(now);\n this.#preTapGain.gain.setValueAtTime(PRE_TAP_DRIVE, now);\n this.#preTapGain.gain.setValueAtTime(PRE_TAP_DRIVE, peakAt);\n this.#preTapGain.gain.linearRampToValueAtTime(0, peakAt + PRE_TAP_CLOSE_S);\n\n this.#wetGain.gain.cancelScheduledValues(now);\n this.#wetGain.gain.setValueAtTime(this.#wetGain.gain.value, now);\n this.#wetGain.gain.linearRampToValueAtTime(REVERB_SWELL_LEVEL, peakAt);\n this.#wetGain.gain.linearRampToValueAtTime(0, peakAt + fadeOutSec);\n }\n\n /**\n * Full cleanup.\n */\n dispose(): void {\n this.disconnect();\n this.#convolver = null;\n this.#wetGain = null;\n this.#preTapGain = null;\n this.#loaded = false;\n }\n\n get isLoaded(): boolean {\n return this.#loaded;\n }\n}\n","// ============================================================================\n// countInGrid — pure grid computation for the passage count-in feature\n//\n// Given a passage's [start, end] and the track's madmom beats/downbeats,\n// derive a metronomic click grid extrapolated backward from the first beat\n// inside the passage (the \"anchor\"). The last click lands one beatInterval\n// before the anchor; audio starts at passageStart (which sits between the\n// last click and the anchor).\n// ============================================================================\n\nimport type { BeatType } from \"./MetronomeEngine\";\n\nexport type { BeatType };\n\nexport type CountInPlan = {\n clicks: { offsetFromAnchor: number; type: BeatType }[];\n anchorTime: number;\n beatInterval: number;\n beatsPerBar: number;\n anchorBeatInBar: number;\n};\n\nexport type CountInInputs = {\n passageStart: number;\n passageEnd: number;\n trackBeats: readonly number[];\n trackDownbeats: readonly number[];\n // A non-empty emphasis array is a user override; its length is the beat\n // count. An empty array (or omitted) means \"use the derived default\".\n userOverride?: { emphasis: BeatType[] };\n};\n\nconst TEMPO_SAMPLE_COUNT = 5;\nconst MIN_BEATS_PER_BAR = 2;\nconst MAX_BEATS_PER_BAR = 12;\n\nexport function computeCountIn(inputs: CountInInputs): CountInPlan | null {\n const { passageStart, passageEnd, trackBeats, trackDownbeats, userOverride } =\n inputs;\n\n const insideBeats: number[] = [];\n for (const t of trackBeats) {\n if (t >= passageStart && t <= passageEnd) insideBeats.push(t);\n }\n if (insideBeats.length < 2) return null;\n\n const insideDownbeats: number[] = [];\n for (const t of trackDownbeats) {\n if (t >= passageStart && t <= passageEnd) insideDownbeats.push(t);\n }\n\n const anchor = insideBeats[0];\n\n // Tempo: mean of the first N gaps\n const gapCount = Math.min(TEMPO_SAMPLE_COUNT, insideBeats.length - 1);\n let gapSum = 0;\n for (let i = 0; i < gapCount; i++) {\n gapSum += insideBeats[i + 1] - insideBeats[i];\n }\n const beatInterval = gapSum / gapCount;\n if (!Number.isFinite(beatInterval) || beatInterval <= 0) return null;\n\n // Beats per bar\n let beatsPerBar = 4;\n if (insideDownbeats.length >= 2) {\n const downbeatGap = insideDownbeats[1] - insideDownbeats[0];\n const estimated = Math.round(downbeatGap / beatInterval);\n beatsPerBar = Math.max(\n MIN_BEATS_PER_BAR,\n Math.min(MAX_BEATS_PER_BAR, estimated),\n );\n }\n\n // Anchor's beat position in bar (0-indexed).\n // insideDownbeats[0] is the first downbeat at-or-after the anchor, so\n // n = beats from anchor to that downbeat. Anchor sits n beats before a\n // downbeat, i.e., at position (beatsPerBar - n) mod beatsPerBar.\n let anchorBeatInBar = 0;\n if (insideDownbeats.length >= 1) {\n const firstDb = insideDownbeats[0];\n const n = Math.round((firstDb - anchor) / beatInterval);\n anchorBeatInBar = ((beatsPerBar - n) % beatsPerBar + beatsPerBar) % beatsPerBar;\n }\n\n // Resolve click count and emphasis. A non-empty user override takes\n // precedence; otherwise derive the default grid from the passage data.\n // (See countInOverride.ts for the [] === \"use default\" invariant.)\n const hasOverride =\n userOverride !== undefined && userOverride.emphasis.length > 0;\n const count = hasOverride\n ? userOverride!.emphasis.length\n : beatsPerBar + anchorBeatInBar;\n const emphasis: BeatType[] = hasOverride\n ? userOverride!.emphasis.slice()\n : defaultEmphasis(count, beatsPerBar, anchorBeatInBar);\n\n const clicks = new Array(count);\n for (let i = 0; i < count; i++) {\n clicks[i] = {\n offsetFromAnchor: -(count - i) * beatInterval,\n type: emphasis[i],\n };\n }\n\n return { clicks, anchorTime: anchor, beatInterval, beatsPerBar, anchorBeatInBar };\n}\n\n// ============================================================================\n// Count-in schedule (ctx-time)\n//\n// Given a plan, playback rate, ctx \"now\", and the passage start, compute\n// when each click fires in AudioContext time and when audio output should\n// begin. This is the pure half of AudioEngine's `#scheduleCountInCycle`.\n// ============================================================================\n\nexport type CountInScheduledClick = {\n time: number; // AudioContext time\n isAccent: boolean;\n};\n\nexport type CountInSchedule = {\n clicks: CountInScheduledClick[];\n /**\n * AudioContext time at which the first sample of audio should be audible.\n * This is NOT \"now + stretchLatency\" — the count-in path schedules far\n * enough in the future that no latency padding is needed.\n */\n audioOutputTime: number;\n msUntilAudio: number;\n};\n\n/**\n * Schedule lead: small delay from \"now\" to the first click so the lookahead\n * scheduler has room to queue oscillators without underruns.\n */\nexport const COUNT_IN_SCHEDULE_LEAD_S = 0.05;\n\nexport function computeCountInSchedule(args: {\n plan: CountInPlan;\n rate: number;\n now: number;\n withSilenceGap: boolean;\n passageStart: number;\n scheduleLeadSeconds?: number;\n}): CountInSchedule {\n const {\n plan,\n rate,\n now,\n withSilenceGap,\n passageStart,\n scheduleLeadSeconds = COUNT_IN_SCHEDULE_LEAD_S,\n } = args;\n\n const effectiveInterval = plan.beatInterval / rate;\n const gap = withSilenceGap ? effectiveInterval : 0;\n const firstClickTime = now + scheduleLeadSeconds + gap;\n\n const clicks: CountInScheduledClick[] = [];\n for (let i = 0; i < plan.clicks.length; i++) {\n const click = plan.clicks[i];\n if (click.type === \"silent\") continue;\n // offsetFromAnchor + beatInterval * count simplifies to i * beatInterval,\n // i.e. click i fires i effective-intervals after the first click.\n const time =\n firstClickTime +\n (click.offsetFromAnchor + plan.beatInterval * plan.clicks.length) / rate;\n clicks.push({ time, isAccent: click.type === \"accent\" });\n }\n\n // Last click lands beatInterval before the anchor in ctx time. Audio is\n // delayed so that audio's track-time `anchor` plays at\n // lastClickCtxTime + beatInterval/rate.\n const lastClickCtxTime =\n firstClickTime + ((plan.clicks.length - 1) * plan.beatInterval) / rate;\n const anchorCtxTime = lastClickCtxTime + effectiveInterval;\n const audioOutputTime =\n anchorCtxTime - (plan.anchorTime - passageStart) / rate;\n\n const msUntilAudio = Math.max(0, (audioOutputTime - now) * 1000);\n\n return { clicks, audioOutputTime, msUntilAudio };\n}\n\n// The last click sits one beatInterval before the anchor, so its position\n// within the bar is (anchorBeatInBar - 1) mod beatsPerBar. Downbeats walk\n// back from that index in steps of beatsPerBar.\nexport function defaultEmphasis(\n count: number,\n beatsPerBar: number,\n anchorBeatInBar: number,\n): BeatType[] {\n const lastClickBarPos =\n ((anchorBeatInBar - 1) % beatsPerBar + beatsPerBar) % beatsPerBar;\n const emphasis: BeatType[] = new Array(count);\n for (let i = 0; i < count; i++) {\n const distanceFromLast = count - 1 - i;\n const barPos =\n ((lastClickBarPos - distanceFromLast) % beatsPerBar + beatsPerBar) %\n beatsPerBar;\n emphasis[i] = barPos === 0 ? \"accent\" : \"normal\";\n }\n return emphasis;\n}\n","// ============================================================================\n// Attack-peak snap\n//\n// Madmom beats land on the rising edge of a transient, but human perception\n// locks onto the amplitude peak a few ms later. For soft-attack instruments\n// this offset is audible when a metronomic click grid is laid on top of the\n// music. Shift the anchor toward the nearest local amplitude peak so the\n// last count-in click lines up with the *perceived* beat, not the onset.\n// ============================================================================\n\nimport { computePeakAmplitude } from \"./beatDetection\";\n\n// Attack-peak snap: search window and frame size defaults, plus the\n// stand-out ratio that decides when a peak is real vs. noise.\nconst ATTACK_SNAP_DEFAULT_PRE_MS = 10;\nconst ATTACK_SNAP_DEFAULT_POST_MS = 60;\nconst ATTACK_SNAP_DEFAULT_FRAME_MS = 4;\nconst ATTACK_SNAP_STANDOUT_RATIO = 1.2;\n\n/**\n * Return the time (in seconds) of the local amplitude peak near `targetTime`.\n * Scans [targetTime - preMs/1000, targetTime + postMs/1000], sliding a\n * `frameMs`-wide window to find the frame with the largest\n * `computePeakAmplitude`, then returns the actual peak sample's time within\n * that frame. If no frame's peak is meaningfully above the window mean,\n * returns `targetTime` unchanged.\n */\nexport function snapToAttackPeak(\n mono: Float32Array,\n sampleRate: number,\n targetTime: number,\n preMs = ATTACK_SNAP_DEFAULT_PRE_MS,\n postMs = ATTACK_SNAP_DEFAULT_POST_MS,\n frameMs = ATTACK_SNAP_DEFAULT_FRAME_MS,\n): number {\n if (mono.length === 0 || sampleRate <= 0) return targetTime;\n\n const frameSize = Math.max(1, Math.floor((frameMs / 1000) * sampleRate));\n const startSample = Math.max(\n 0,\n Math.floor((targetTime - preMs / 1000) * sampleRate),\n );\n // endSample is exclusive: the scanned range is [startSample, endSample).\n const endSample = Math.min(\n mono.length,\n Math.ceil((targetTime + postMs / 1000) * sampleRate),\n );\n if (endSample - startSample < frameSize) return targetTime;\n\n let bestOffset = -1;\n let bestPeak = 0;\n let peakSum = 0;\n let peakCount = 0;\n\n for (let offset = startSample; offset + frameSize <= endSample; offset += 1) {\n const peak = computePeakAmplitude(mono, offset, frameSize);\n peakSum += peak;\n peakCount += 1;\n if (peak > bestPeak) {\n bestPeak = peak;\n bestOffset = offset;\n }\n }\n\n if (bestOffset < 0 || peakCount === 0) return targetTime;\n\n const meanPeak = peakSum / peakCount;\n // Require the winning frame to stand out from the window mean, otherwise\n // we're in a quiet region with no real attack to latch onto.\n if (bestPeak < meanPeak * ATTACK_SNAP_STANDOUT_RATIO) return targetTime;\n\n // Find the actual peak sample inside the winning frame. This is more\n // accurate than the frame center and matches the docstring.\n let peakSample = bestOffset;\n let peakAmplitude = Math.abs(mono[bestOffset]);\n for (let i = bestOffset + 1; i < bestOffset + frameSize; i += 1) {\n const amplitude = Math.abs(mono[i]);\n if (amplitude > peakAmplitude) {\n peakAmplitude = amplitude;\n peakSample = i;\n }\n }\n return peakSample / sampleRate;\n}\n","// ============================================================================\n// clickScheduler — shared Web Audio click primitive\n//\n// Used by MetronomeEngine (for its rolling scheduler) and AudioEngine (for\n// count-in click sequences). Returns the created OscillatorNode so callers\n// can track and cancel in-flight schedules.\n// ============================================================================\n\nexport interface ToneDefinition {\n accent: number;\n normal: number;\n wave: OscillatorType;\n decay: number;\n}\n\nexport const TONES: Record = {\n \"Wood Block\": { accent: 880, normal: 660, wave: \"triangle\", decay: 0.04 },\n Click: { accent: 1200, normal: 900, wave: \"sine\", decay: 0.02 },\n Cowbell: { accent: 560, normal: 460, wave: \"square\", decay: 0.08 },\n \"Hi-Hat\": { accent: 6000, normal: 4500, wave: \"sawtooth\", decay: 0.015 },\n};\n\nexport const TONE_NAMES = Object.keys(TONES);\n\nexport interface ScheduleClickOptions {\n ctx: AudioContext;\n destination: AudioNode;\n time: number;\n freq: number;\n wave: OscillatorType;\n decay: number;\n volume: number;\n}\n\n/**\n * Schedule a single click at the given AudioContext time. Returns the\n * OscillatorNode so the caller can `osc.stop(0)` to cancel a pending click.\n */\nexport function scheduleClick(opts: ScheduleClickOptions): OscillatorNode {\n const { ctx, destination, time, freq, wave, decay, volume } = opts;\n const osc = ctx.createOscillator();\n const gain = ctx.createGain();\n\n osc.type = wave;\n osc.frequency.value = freq;\n gain.gain.setValueAtTime(volume, time);\n gain.gain.exponentialRampToValueAtTime(0.001, time + decay + 0.05);\n\n osc.connect(gain);\n gain.connect(destination);\n\n osc.start(time);\n osc.stop(time + decay + 0.06);\n\n return osc;\n}\n","// ============================================================================\n// CountInController\n//\n// Owns all count-in state and scheduling. AudioEngine delegates to this\n// controller for: accepting context updates, deciding whether count-in\n// should fire, scheduling a count-in cycle (initial or loop), cleaning up\n// pending oscillators, and handling the audio-end loop branch.\n//\n// The controller depends on a narrow `CountInHost` interface rather than on\n// AudioEngine directly, so the coupling is explicit.\n// ============================================================================\n\nimport type { BeatType } from \"./MetronomeEngine\";\nimport type { CountInPlan } from \"./countInGrid\";\nimport { computeCountIn, computeCountInSchedule } from \"./countInGrid\";\nimport { snapToAttackPeak } from \"./attackSnap\";\nimport { scheduleClick, TONES } from \"./clickScheduler\";\n\nexport type CountInPhase = \"idle\" | \"countIn\" | \"audio\" | \"loopSilence\";\n\ntype CountInContext = {\n enabled: boolean;\n passageStart: number;\n passageEnd: number;\n plan: CountInPlan | null;\n};\n\nexport type CountInContextOptions = {\n enabled: boolean;\n passageStart: number;\n passageEnd: number;\n trackBeats: readonly number[];\n trackDownbeats: readonly number[];\n userOverride?: { emphasis: BeatType[] };\n attackSnap?: {\n mono: Float32Array;\n sampleRate: number;\n };\n};\n\n// Tolerance used when deciding whether a play started at passageStart\n// (fires count-in) vs. mid-passage (skips it).\nexport const COUNT_IN_START_TOLERANCE_S = 0.02;\n// Short ramp applied when the mute gate closes at the end of an audio\n// segment, so the cutoff isn't a hard click.\nexport const COUNT_IN_GATE_FADE_S = 0.005;\n\n/**\n * Narrow host interface the controller needs from AudioEngine. Implementing\n * this on AudioEngine keeps the controller self-contained and testable.\n */\nexport interface CountInHost {\n readonly ctx: AudioContext;\n readonly muteGate: GainNode | null;\n readonly snapshot: {\n playbackRate: number;\n semitonePitch: number;\n startAt: number;\n isLooping: boolean;\n };\n /**\n * Start the stretch engine.\n *\n * INVARIANT: for count-in audio starts (`usesLatencyPad: false`), the\n * caller passes an absolute `output` ctx-time that is already far enough\n * in the future that the worklet has time to prepare — do NOT add the\n * stretch latency. For immediate starts (normal play/seek,\n * `usesLatencyPad: true`), the host adds `stretchLatencySeconds` itself.\n */\n startStretch(opts: {\n output: number;\n input: number;\n usesLatencyPad: boolean;\n }): void;\n /** Stop the stretch engine (used at audio-end in the loop). */\n stopStretch(): void;\n /** Update AudioEngine snapshot (playheadTime, isPlaying). */\n setPlaybackState(partial: {\n isPlaying?: boolean;\n playheadTime?: number;\n }): void;\n /**\n * Fired at the start of a new loop iteration (before clicks re-fire), so\n * dependent subsystems (passage sporadiciser) can reset playhead-time-\n * indexed state. The stretch engine's loop bypasses this path entirely;\n * the count-in path bypasses AudioEngine.play(), so neither subsystem has\n * a natural reset hook without this callback.\n */\n onLoopRestart?(): void;\n}\n\nexport class CountInController {\n #host: CountInHost;\n #context: CountInContext | null = null;\n #phase: CountInPhase = \"idle\";\n #toneName = \"Wood Block\";\n #scheduledClickOscs: OscillatorNode[] = [];\n #completeTimer: ReturnType | null = null;\n #exitPassageCallback: (() => void) | null = null;\n\n constructor(host: CountInHost) {\n this.#host = host;\n }\n\n get phase(): CountInPhase {\n return this.#phase;\n }\n\n get context(): CountInContext | null {\n return this.#context;\n }\n\n setContext(opts: CountInContextOptions | null): void {\n if (!opts) {\n this.#context = null;\n return;\n }\n const plan = computeCountIn({\n passageStart: opts.passageStart,\n passageEnd: opts.passageEnd,\n trackBeats: opts.trackBeats,\n trackDownbeats: opts.trackDownbeats,\n userOverride: opts.userOverride,\n });\n if (plan && opts.attackSnap) {\n plan.anchorTime = snapToAttackPeak(\n opts.attackSnap.mono,\n opts.attackSnap.sampleRate,\n plan.anchorTime,\n );\n }\n this.#context = {\n enabled: opts.enabled,\n passageStart: opts.passageStart,\n passageEnd: opts.passageEnd,\n plan,\n };\n }\n\n /** Allow the host to mutate the live passage bounds without re-computing. */\n updateBounds(passageStart: number, passageEnd: number): void {\n if (!this.#context) return;\n this.#context.passageStart = passageStart;\n this.#context.passageEnd = passageEnd;\n }\n\n setTone(tone: string): void {\n if (tone in TONES) {\n this.#toneName = tone;\n }\n }\n\n onExitPassage(cb: (() => void) | null): void {\n this.#exitPassageCallback = cb;\n }\n\n triggerExitPassage(): void {\n this.#exitPassageCallback?.();\n }\n\n setPhase(phase: CountInPhase): void {\n this.#phase = phase;\n }\n\n /**\n * True iff a play originating at `startPosition` (very near passageStart)\n * should fire the count-in click grid.\n */\n shouldCountIn(startPosition: number): boolean {\n const ctx = this.#context;\n if (!ctx || !ctx.enabled || !ctx.plan) return false;\n return Math.abs(startPosition - ctx.passageStart) < COUNT_IN_START_TOLERANCE_S;\n }\n\n /**\n * Schedule a count-in cycle (initial play or loop iteration). On the loop\n * path, `withSilenceGap` shifts the first click by one effective interval\n * so there's a beat of silence between audio end and the next click.\n */\n scheduleCycle(passageStart: number, withSilenceGap: boolean): void {\n const countInCtx = this.#context;\n if (!countInCtx || !countInCtx.plan) return;\n\n const plan = countInCtx.plan;\n const rate = this.#host.snapshot.playbackRate;\n const ctx = this.#host.ctx;\n\n const schedule = computeCountInSchedule({\n plan,\n rate,\n now: ctx.currentTime,\n withSilenceGap,\n passageStart,\n });\n\n const toneConfig = TONES[this.#toneName] ?? TONES[\"Wood Block\"];\n // Clicks go direct to destination. The stretch output is routed through\n // the mute gate (closed below) so no audio leaks under the clicks even\n // if the worklet starts emitting before audioOutputTime.\n for (const click of schedule.clicks) {\n const osc = scheduleClick({\n ctx,\n destination: ctx.destination,\n time: click.time,\n freq: click.isAccent ? toneConfig.accent : toneConfig.normal,\n wave: toneConfig.wave,\n decay: toneConfig.decay,\n volume: click.isAccent ? 0.35 : 0.19,\n });\n this.#scheduledClickOscs.push(osc);\n }\n\n // Keep the mute gate closed through the count-in and open it exactly at\n // audioOutputTime, so any early stretch emission is inaudible.\n const gate = this.#host.muteGate;\n if (gate) {\n gate.gain.cancelScheduledValues(ctx.currentTime);\n gate.gain.setValueAtTime(0, ctx.currentTime);\n gate.gain.setValueAtTime(\n 1,\n Math.max(ctx.currentTime, schedule.audioOutputTime),\n );\n }\n\n // Count-in stretch start uses no latency pad — see CountInHost.startStretch.\n this.#host.startStretch({\n output: schedule.audioOutputTime,\n input: passageStart,\n usesLatencyPad: false,\n });\n\n this.#phase = \"countIn\";\n this.#host.setPlaybackState({ isPlaying: true, playheadTime: passageStart });\n\n if (this.#completeTimer) clearTimeout(this.#completeTimer);\n this.#completeTimer = setTimeout(() => {\n this.#completeTimer = null;\n if (this.#phase !== \"countIn\" && this.#phase !== \"loopSilence\") return;\n this.#phase = \"audio\";\n }, schedule.msUntilAudio);\n }\n\n /**\n * Called by AudioEngine when the count-in audio segment hits the passage\n * end. Either stops (non-looping) or schedules the next count-in cycle.\n */\n handleAudioEnd(): void {\n const ctx = this.#host.ctx;\n if (this.#phase !== \"audio\") return;\n\n const countInCtx = this.#context;\n if (!countInCtx || !countInCtx.enabled) {\n // Count-in was disabled mid-play; fall back to normal stop/loop.\n return;\n }\n\n // Silence audio before clicks re-fire.\n const gate = this.#host.muteGate;\n if (gate) {\n const now = ctx.currentTime;\n gate.gain.cancelScheduledValues(now);\n gate.gain.setValueAtTime(gate.gain.value, now);\n gate.gain.linearRampToValueAtTime(0, now + COUNT_IN_GATE_FADE_S);\n }\n try {\n this.#host.stopStretch();\n } catch {\n // ignore\n }\n\n if (!this.#host.snapshot.isLooping) {\n this.cancelCycle();\n this.#phase = \"idle\";\n this.#host.setPlaybackState({\n isPlaying: false,\n playheadTime: countInCtx.passageStart,\n });\n return;\n }\n\n // Loop: one-beat silence, then new count-in cycle.\n this.#phase = \"loopSilence\";\n this.#host.onLoopRestart?.();\n this.scheduleCycle(countInCtx.passageStart, true);\n }\n\n /** Cancel pending click oscillators and the complete timer. */\n cancelCycle(): void {\n if (this.#completeTimer) {\n clearTimeout(this.#completeTimer);\n this.#completeTimer = null;\n }\n for (const osc of this.#scheduledClickOscs) {\n try {\n osc.stop(0);\n } catch {\n // ignore\n }\n }\n this.#scheduledClickOscs = [];\n }\n\n /** Full reset — drop context, cancel cycle, reset phase. */\n reset(): void {\n this.cancelCycle();\n this.#phase = \"idle\";\n this.#context = null;\n }\n\n dispose(): void {\n this.reset();\n this.#exitPassageCallback = null;\n }\n}\n","// ============================================================================\n// MetronomeEngine — Web Audio clock-scheduled metronome\n//\n// Uses a lookahead scheduler pattern: a timer checks frequently (~25ms) and\n// pre-schedules clicks using AudioContext.currentTime for jitter-free timing.\n// ============================================================================\n\nimport { scheduleClick, TONES, TONE_NAMES } from \"./clickScheduler\";\nimport type { ToneDefinition } from \"./clickScheduler\";\n\ntype Listener = () => void;\n\nexport { TONES, TONE_NAMES };\nexport type { ToneDefinition };\n\n// ============================================================================\n// Beat types\n// ============================================================================\n\nexport type BeatType = \"accent\" | \"normal\" | \"silent\";\n\nexport function cycleBeatType(current: BeatType): BeatType {\n if (current === \"accent\") return \"normal\";\n if (current === \"normal\") return \"silent\";\n return \"accent\";\n}\n\n// ============================================================================\n// State\n// ============================================================================\n\nexport interface MetronomeState {\n bpm: number;\n beats: BeatType[];\n tone: string;\n sporadicism: number;\n isPlaying: boolean;\n activeBeatIndex: number;\n lastDropped: boolean;\n}\n\nexport const DEFAULT_METRONOME_STATE: MetronomeState = {\n bpm: 120,\n beats: [\"accent\", \"normal\", \"normal\", \"normal\"],\n tone: \"Wood Block\",\n sporadicism: 0,\n isPlaying: false,\n activeBeatIndex: -1,\n lastDropped: false,\n};\n\n// ============================================================================\n// Sporadiciser\n// ============================================================================\n\nexport class Sporadiciser {\n #phase = 0;\n #direction = 1;\n\n reset(): void {\n this.#phase = 0;\n this.#direction = 1;\n }\n\n /** Advance the phase and return whether this beat should be dropped. */\n shouldDrop(sporadicism: number): boolean {\n if (sporadicism <= 0) return false;\n\n // Oscillate phase: drifts 0→1→0 with random step sizes\n this.#phase += (0.003 + Math.random() * 0.015) * this.#direction;\n if (this.#phase >= 1) {\n this.#phase = 1;\n this.#direction = -1;\n }\n if (this.#phase <= 0) {\n this.#phase = 0;\n this.#direction = 1;\n }\n\n const dropProbability = sporadicism * this.#phase;\n return Math.random() < dropProbability;\n }\n}\n\n// ============================================================================\n// MetronomeEngine\n// ============================================================================\n\nconst LOOKAHEAD_MS = 25; // How often the scheduler fires (ms)\nconst SCHEDULE_AHEAD_S = 0.1; // How far ahead to schedule (seconds)\n\nexport class MetronomeEngine {\n #listeners = new Set();\n #snapshot: MetronomeState;\n\n // Audio\n #audioContext: AudioContext | null = null;\n #ownsContext = false;\n\n // Scheduler\n #schedulerTimer: ReturnType | null = null;\n #nextBeatTime = 0; // AudioContext time of the next beat\n #currentBeatIndex = 0;\n\n // Sporadiciser\n #sporadiciser = new Sporadiciser();\n\n // Tap tempo\n #tapTimes: number[] = [];\n #tapResetTimer: ReturnType | null = null;\n\n constructor() {\n this.#snapshot = { ...DEFAULT_METRONOME_STATE };\n }\n\n // ==========================================================================\n // Observable\n // ==========================================================================\n\n subscribe(listener: Listener): () => void {\n this.#listeners.add(listener);\n return () => {\n this.#listeners.delete(listener);\n };\n }\n\n getSnapshot(): MetronomeState {\n return this.#snapshot;\n }\n\n #setState(partial: Partial): void {\n let changed = false;\n for (const key of Object.keys(partial) as (keyof MetronomeState)[]) {\n if (key === \"beats\") {\n const oldBeats = this.#snapshot.beats;\n const newBeats = partial.beats!;\n if (\n oldBeats.length !== newBeats.length ||\n oldBeats.some((b, i) => b !== newBeats[i])\n ) {\n changed = true;\n }\n } else if (this.#snapshot[key] !== partial[key]) {\n changed = true;\n }\n }\n if (!changed) return;\n\n this.#snapshot = { ...this.#snapshot, ...partial };\n for (const listener of this.#listeners) {\n listener();\n }\n }\n\n // ==========================================================================\n // AudioContext management\n // ==========================================================================\n\n /** Use an external AudioContext (shared with AudioEngine). */\n setAudioContext(ctx: AudioContext): void {\n if (this.#audioContext && this.#ownsContext) {\n this.#audioContext.close().catch(() => {});\n }\n this.#audioContext = ctx;\n this.#ownsContext = false;\n }\n\n #ensureAudioContext(): AudioContext {\n if (!this.#audioContext) {\n this.#audioContext = new AudioContext();\n this.#ownsContext = true;\n }\n return this.#audioContext;\n }\n\n // ==========================================================================\n // Transport\n // ==========================================================================\n\n start(): void {\n const ctx = this.#ensureAudioContext();\n if (ctx.state === \"suspended\") {\n ctx.resume();\n }\n\n // Reset scheduler state\n this.#currentBeatIndex = 0;\n this.#sporadiciser.reset();\n this.#nextBeatTime = ctx.currentTime + 0.05; // Small delay to avoid immediate scheduling issues\n\n this.#setState({\n isPlaying: true,\n activeBeatIndex: -1,\n lastDropped: false,\n });\n\n // Start the lookahead scheduler\n this.#schedulerTimer = setInterval(() => this.#schedule(), LOOKAHEAD_MS);\n }\n\n stop(): void {\n if (this.#schedulerTimer) {\n clearInterval(this.#schedulerTimer);\n this.#schedulerTimer = null;\n }\n\n this.#setState({\n isPlaying: false,\n activeBeatIndex: -1,\n lastDropped: false,\n });\n }\n\n // ==========================================================================\n // Setters\n // ==========================================================================\n\n setBpm(bpm: number): void {\n const clamped = Math.max(20, Math.min(300, Math.round(bpm)));\n this.#setState({ bpm: clamped });\n }\n\n setBeats(beats: BeatType[]): void {\n if (beats.length < 1 || beats.length > 12) return;\n this.#setState({ beats: [...beats] });\n }\n\n setTone(tone: string): void {\n if (!(tone in TONES)) return;\n this.#setState({ tone });\n }\n\n setSporadicism(value: number): void {\n this.#setState({ sporadicism: Math.max(0, Math.min(1, value)) });\n }\n\n addBeat(): void {\n const { beats } = this.#snapshot;\n if (beats.length >= 12) return;\n this.setBeats([...beats, \"normal\"]);\n }\n\n removeBeat(): void {\n const { beats } = this.#snapshot;\n if (beats.length <= 1) return;\n this.setBeats(beats.slice(0, -1));\n }\n\n cycleBeat(index: number): void {\n const { beats } = this.#snapshot;\n if (index < 0 || index >= beats.length) return;\n const next = [...beats];\n next[index] = cycleBeatType(next[index]);\n this.setBeats(next);\n }\n\n // ==========================================================================\n // Tap Tempo\n // ==========================================================================\n\n tapTempo(): void {\n const now = Date.now();\n this.#tapTimes.push(now);\n\n // Keep last 5 taps\n if (this.#tapTimes.length > 5) this.#tapTimes.shift();\n\n if (this.#tapTimes.length >= 2) {\n const intervals: number[] = [];\n for (let i = 1; i < this.#tapTimes.length; i++) {\n intervals.push(this.#tapTimes[i] - this.#tapTimes[i - 1]);\n }\n const avg = intervals.reduce((a, b) => a + b, 0) / intervals.length;\n const newBpm = Math.round(60000 / avg);\n if (newBpm >= 20 && newBpm <= 300) {\n this.setBpm(newBpm);\n }\n }\n\n // Reset after 2s of no taps\n if (this.#tapResetTimer) clearTimeout(this.#tapResetTimer);\n this.#tapResetTimer = setTimeout(() => {\n this.#tapTimes = [];\n }, 2000);\n }\n\n // ==========================================================================\n // Serialization (for persistence)\n // ==========================================================================\n\n toJSON(): Record {\n const { bpm, beats, tone, sporadicism } = this.#snapshot;\n return { bpm, beats, tone, sporadicism };\n }\n\n loadFromJSON(data: unknown): void {\n if (!data || typeof data !== \"object\") return;\n const d = data as Record;\n\n if (typeof d.bpm === \"number\" && d.bpm >= 20 && d.bpm <= 300) {\n this.setBpm(d.bpm);\n }\n if (\n Array.isArray(d.beats) &&\n d.beats.length >= 1 &&\n d.beats.length <= 12 &&\n d.beats.every(\n (b: unknown) => b === \"accent\" || b === \"normal\" || b === \"silent\",\n )\n ) {\n this.setBeats(d.beats as BeatType[]);\n }\n if (typeof d.tone === \"string\" && d.tone in TONES) {\n this.setTone(d.tone);\n }\n if (typeof d.sporadicism === \"number\") {\n this.setSporadicism(d.sporadicism);\n }\n }\n\n // ==========================================================================\n // Cleanup\n // ==========================================================================\n\n dispose(): void {\n this.stop();\n if (this.#tapResetTimer) clearTimeout(this.#tapResetTimer);\n if (this.#audioContext && this.#ownsContext) {\n this.#audioContext.close().catch(() => {});\n }\n this.#audioContext = null;\n }\n\n // ==========================================================================\n // Private: Lookahead scheduler\n // ==========================================================================\n\n #schedule(): void {\n const ctx = this.#audioContext;\n if (!ctx) return;\n\n const { bpm, beats, tone, sporadicism } = this.#snapshot;\n const beatDuration = 60 / bpm;\n const toneConfig = TONES[tone] || TONES[\"Wood Block\"];\n\n // Schedule all beats that fall within the lookahead window\n while (this.#nextBeatTime < ctx.currentTime + SCHEDULE_AHEAD_S) {\n const beatIndex = this.#currentBeatIndex % beats.length;\n const beatType = beats[beatIndex];\n\n const shouldDrop = this.#sporadiciser.shouldDrop(sporadicism);\n\n if (beatType !== \"silent\" && !shouldDrop) {\n const isAccent = beatType === \"accent\";\n scheduleClick({\n ctx,\n destination: ctx.destination,\n time: this.#nextBeatTime,\n freq: isAccent ? toneConfig.accent : toneConfig.normal,\n wave: toneConfig.wave,\n decay: toneConfig.decay,\n volume: isAccent ? 0.35 : 0.19,\n });\n }\n\n // Schedule a UI update at the beat time\n const beatTime = this.#nextBeatTime;\n const updateBeatIndex = beatIndex;\n const updateDropped = shouldDrop;\n const delay = Math.max(0, (beatTime - ctx.currentTime) * 1000);\n setTimeout(() => {\n this.#setState({\n activeBeatIndex: updateBeatIndex,\n lastDropped: updateDropped,\n });\n }, delay);\n\n this.#nextBeatTime += beatDuration;\n this.#currentBeatIndex++;\n }\n }\n\n}\n","// ============================================================================\n// SporadiciserController\n//\n// Owns passage-sporadiciser state for AudioEngine: the oscillating-probability\n// model, the mute-gate choreography (paired with ReverbFill crossfade), and\n// the loop-back reset that keeps timing coherent when the playhead jumps.\n//\n// Patterned on CountInController: a narrow host interface (no direct reach\n// into engine privates), synchronous driver methods, no callbacks back.\n// ============================================================================\n\nimport { Sporadiciser } from \"./MetronomeEngine\";\nimport type { ReverbFill } from \"./ReverbFill\";\n\n// If the playhead moves backward by more than this between ticks, we treat it\n// as a loop-around (not worklet jitter). Loop jumps are typically many seconds;\n// jitter is sub-millisecond.\nconst LOOP_BACK_EPS_S = 0.1;\n\nexport interface SporadiciserHost {\n /** AudioContext — null during teardown. */\n readonly ctx: AudioContext | null;\n /** Mute gate node — signal path dry-fade target. */\n readonly muteGate: GainNode | null;\n /** Reverb tail — crossfade partner for dropouts. */\n readonly reverbFill: ReverbFill;\n /** Current sporadicism value (0..1), read live from engine snapshot. */\n readonly sporadicism: number;\n /**\n * Track-wide madmom beat times in seconds (sorted ascending). When null\n * or too short to span a drop, the controller falls back to time-based\n * dropouts.\n */\n readonly trackBeats: readonly number[] | null;\n}\n\nexport class SporadiciserController {\n static readonly #DROP_RAMP_S = 0.08; // 80ms dry-fade-out\n static readonly #RETURN_RAMP_S = 0.05; // 50ms dry-fade-in (faster than drop)\n static readonly #SWELL_LEAD_S = 0.25; // 250ms reverb pre-swell before dry returns\n static readonly #REVERB_FADE_IN_S = 0.08; // matches drop ramp on the way in\n static readonly #REVERB_FADE_OUT_S = 0.2; // longer post-swell decay so tail lingers under dry\n static readonly #MIN_SILENCE_S = 1.0;\n static readonly #MAX_SILENCE_S = 3.5;\n static readonly #MIN_AUDIBLE_S = 0.3;\n static readonly #MAX_AUDIBLE_S = 2.0;\n static readonly #MIN_DROP_BEATS = 1;\n static readonly #MAX_DROP_BEATS = 8;\n\n #host: SporadiciserHost;\n #sporadiciser = new Sporadiciser();\n #isMuted = false;\n #nextCheck = 0; // playhead time of next drop/undrop decision\n #unmuteAt = 0; // playhead time to unmute (when muted)\n #pendingDropAt = 0; // beat-snapped playhead time at which to engage the mute\n #hasPendingDrop = false;\n #lastPlayheadTime = 0;\n #hasLastPlayhead = false;\n\n constructor(host: SporadiciserHost) {\n this.#host = host;\n }\n\n get isMuted(): boolean {\n return this.#isMuted;\n }\n\n /**\n * Per-tick update. Detects loop-back (playhead regression) and resets\n * timing state so dropout decisions keep firing after a loop iteration.\n */\n updateState(playheadTime: number): void {\n if (\n this.#hasLastPlayhead &&\n playheadTime + LOOP_BACK_EPS_S < this.#lastPlayheadTime\n ) {\n this.handleLoopBack();\n }\n this.#lastPlayheadTime = playheadTime;\n this.#hasLastPlayhead = true;\n\n const sporadicism = this.#host.sporadicism;\n if (sporadicism <= 0) return;\n\n if (this.#hasPendingDrop) {\n if (playheadTime >= this.#pendingDropAt) {\n this.#setMuteGate(true);\n this.#hasPendingDrop = false;\n }\n return;\n }\n\n if (this.#isMuted) {\n if (playheadTime >= this.#unmuteAt) {\n this.#setMuteGate(false);\n const audibleDuration =\n SporadiciserController.#MIN_AUDIBLE_S +\n Math.random() *\n (SporadiciserController.#MAX_AUDIBLE_S -\n SporadiciserController.#MIN_AUDIBLE_S);\n this.#nextCheck = playheadTime + audibleDuration;\n }\n } else {\n if (playheadTime >= this.#nextCheck) {\n if (this.#sporadiciser.shouldDrop(sporadicism)) {\n this.#scheduleDrop(playheadTime, sporadicism);\n } else {\n this.#nextCheck = playheadTime + 0.2 + Math.random() * 0.3;\n }\n }\n }\n }\n\n /**\n * Decide drop boundaries. With trackBeats, snap drop start to the next\n * beat at-or-after `playheadTime` and unmute to N beats later (random,\n * scaled by sporadicism). Without beats — or near track end where there\n * aren't enough beats ahead — fall back to the time-based silence range\n * so dropouts keep happening even on tracks without madmom data.\n */\n #scheduleDrop(playheadTime: number, sporadicism: number): void {\n const beats = this.#host.trackBeats;\n if (beats && beats.length >= 2) {\n const startIdx = findFirstBeatAtOrAfter(beats, playheadTime);\n const dropBeats = Math.max(\n 1,\n Math.round(\n SporadiciserController.#MIN_DROP_BEATS +\n Math.random() *\n (SporadiciserController.#MAX_DROP_BEATS -\n SporadiciserController.#MIN_DROP_BEATS) *\n sporadicism,\n ),\n );\n const endIdx = startIdx + dropBeats;\n if (startIdx < beats.length && endIdx < beats.length) {\n this.#pendingDropAt = beats[startIdx];\n this.#unmuteAt = beats[endIdx];\n this.#hasPendingDrop = true;\n return;\n }\n }\n\n this.#setMuteGate(true);\n const silenceRange =\n SporadiciserController.#MAX_SILENCE_S -\n SporadiciserController.#MIN_SILENCE_S;\n const silenceDuration =\n SporadiciserController.#MIN_SILENCE_S +\n Math.random() * silenceRange * sporadicism;\n this.#unmuteAt = playheadTime + silenceDuration;\n }\n\n /**\n * Clear timing state and unmute, without touching the probability-model\n * phase. Called on loop-back (detected by updateState or via count-in) and\n * on fresh playback start from AudioEngine.play().\n */\n handleLoopBack(): void {\n this.#nextCheck = 0;\n this.#unmuteAt = 0;\n this.#pendingDropAt = 0;\n this.#hasPendingDrop = false;\n if (this.#isMuted) this.#setMuteGate(false);\n }\n\n /** Explicit call for AudioEngine.play(); same semantics as handleLoopBack. */\n handlePlaybackStart(): void {\n this.#hasLastPlayhead = false;\n this.handleLoopBack();\n }\n\n /**\n * If currently muted, unmute. Used when sporadicism is set to 0 so a\n * lingering dropout doesn't outlive the feature toggle.\n */\n ensureUnmuted(): void {\n if (this.#isMuted) this.#setMuteGate(false);\n }\n\n /** Full reset — probability phase, timing state, mute gate. */\n reset(): void {\n this.#sporadiciser.reset();\n this.#isMuted = false;\n this.#nextCheck = 0;\n this.#unmuteAt = 0;\n this.#pendingDropAt = 0;\n this.#hasPendingDrop = false;\n this.#hasLastPlayhead = false;\n this.#lastPlayheadTime = 0;\n }\n\n #setMuteGate(mute: boolean): void {\n const ctx = this.#host.ctx;\n const gate = this.#host.muteGate;\n if (!ctx || !gate) {\n this.#isMuted = mute;\n return;\n }\n\n this.#isMuted = mute;\n const now = ctx.currentTime;\n gate.gain.cancelScheduledValues(now);\n gate.gain.setValueAtTime(gate.gain.value, now);\n\n if (mute) {\n gate.gain.linearRampToValueAtTime(\n 0,\n now + SporadiciserController.#DROP_RAMP_S,\n );\n this.#host.reverbFill.fadeIn(\n ctx,\n SporadiciserController.#REVERB_FADE_IN_S,\n );\n } else {\n // Reverse of the drop: reverb swells up first, then dry returns.\n // Hold gate at 0 through the swell, then ramp up faster than the drop.\n const dryStartAt = now + SporadiciserController.#SWELL_LEAD_S;\n gate.gain.setValueAtTime(0, dryStartAt);\n gate.gain.linearRampToValueAtTime(\n 1,\n dryStartAt + SporadiciserController.#RETURN_RAMP_S,\n );\n this.#host.reverbFill.swell(\n ctx,\n SporadiciserController.#SWELL_LEAD_S,\n SporadiciserController.#REVERB_FADE_OUT_S,\n );\n }\n }\n}\n\nfunction findFirstBeatAtOrAfter(beats: readonly number[], t: number): number {\n let lo = 0;\n let hi = beats.length;\n while (lo < hi) {\n const mid = (lo + hi) >>> 1;\n if (beats[mid] < t) lo = mid + 1;\n else hi = mid;\n }\n return lo;\n}\n","// ============================================================================\n// StereoFocusNode\n//\n// Equal-power crossfeed node: collapses the stereo field toward one side\n// without making the other channel silent, so the user can \"focus\" on\n// audio panned to a particular side (e.g., the guitar on the left) while\n// still hearing the rest of the mix on both speakers.\n//\n// Signal graph (2x2 matrix):\n//\n// input -> ChannelSplitter(2) -> [gLL, gRL, gLR, gRR] -> ChannelMerger(2) -> output\n//\n// L_out = gLL * L + gRL * R\n// R_out = gLR * L + gRR * R\n//\n// Gain matrix for focus factor f in [-1, +1]:\n//\n// f = 0 : identity (passthrough)\n// f > 0 (left) : L_out = L\n// R_out = cos(pi*f/2) * R + sin(pi*f/2) * L\n// f < 0 (right): L_out = cos(pi*|f|/2) * L + sin(pi*|f|/2) * R\n// R_out = R\n//\n// Crossfeed uses an equal-power cosine/sine taper so total per-channel\n// power stays flat as f sweeps.\n//\n// Control-rate only — gains are set via setValueAtTime on user input or\n// persistence hydration; no audio-rate modulation needed.\n// ============================================================================\n\nexport function computeStereoFocusGains(focus: number): {\n gLL: number;\n gRL: number;\n gLR: number;\n gRR: number;\n} {\n const f = Math.max(-1, Math.min(1, focus));\n const abs = Math.abs(f);\n const c = Math.cos((Math.PI * abs) / 2);\n const s = Math.sin((Math.PI * abs) / 2);\n\n if (f >= 0) {\n // Focus left: L channel is untouched; R blends in a cosine of R and sine\n // of L so the right speaker still carries left-panned content.\n return { gLL: 1, gRL: 0, gLR: s, gRR: c };\n }\n // Focus right: mirrored.\n return { gLL: c, gRL: s, gLR: 0, gRR: 1 };\n}\n\nexport class StereoFocusNode {\n readonly input: ChannelSplitterNode;\n readonly output: ChannelMergerNode;\n readonly #gLL: GainNode;\n readonly #gRL: GainNode;\n readonly #gLR: GainNode;\n readonly #gRR: GainNode;\n readonly #ctx: BaseAudioContext;\n\n constructor(ctx: BaseAudioContext) {\n this.#ctx = ctx;\n this.input = ctx.createChannelSplitter(2);\n this.output = ctx.createChannelMerger(2);\n this.#gLL = ctx.createGain();\n this.#gRL = ctx.createGain();\n this.#gLR = ctx.createGain();\n this.#gRR = ctx.createGain();\n\n // L (channel 0) feeds gLL and gLR.\n this.input.connect(this.#gLL, 0);\n this.input.connect(this.#gLR, 0);\n // R (channel 1) feeds gRL and gRR.\n this.input.connect(this.#gRL, 1);\n this.input.connect(this.#gRR, 1);\n\n // gLL + gRL sum into the L output (merger channel 0).\n this.#gLL.connect(this.output, 0, 0);\n this.#gRL.connect(this.output, 0, 0);\n // gLR + gRR sum into the R output (merger channel 1).\n this.#gLR.connect(this.output, 0, 1);\n this.#gRR.connect(this.output, 0, 1);\n\n // Default to identity.\n this.setFocus(0);\n }\n\n setFocus(focus: number): void {\n const { gLL, gRL, gLR, gRR } = computeStereoFocusGains(focus);\n const t = this.#ctx.currentTime;\n this.#gLL.gain.setValueAtTime(gLL, t);\n this.#gRL.gain.setValueAtTime(gRL, t);\n this.#gLR.gain.setValueAtTime(gLR, t);\n this.#gRR.gain.setValueAtTime(gRR, t);\n }\n\n disconnect(): void {\n // Only sever outgoing connections from the merger. The internal\n // splitter -> gains -> merger wiring is structural and must survive\n // across rebuild-chain calls, or signal entering .input has no path\n // to .output and audio goes silent.\n this.output.disconnect();\n }\n}\n","// ============================================================================\n// KaraokeNode\n//\n// Center-subtract (\"karaoke\") node: attenuates content that's equally\n// present in both channels (typically the vocal) while preserving the\n// side material.\n//\n// Signal graph (2x2 matrix, same shape as StereoFocusNode):\n//\n// input -> ChannelSplitter(2) -> [gLL, gRL, gLR, gRR] -> ChannelMerger(2) -> output\n//\n// L_out = gLL * L + gRL * R\n// R_out = gLR * L + gRR * R\n//\n// Gain matrix for amount alpha in [0, 1]:\n//\n// gLL = 1 - alpha/2 gRL = -alpha/2\n// gLR = -alpha/2 gRR = 1 - alpha/2\n//\n// L_out = (1 - alpha/2)*L - (alpha/2)*R\n// R_out = (1 - alpha/2)*R - (alpha/2)*L\n//\n// alpha = 0 : passthrough\n// alpha = 1 : pure mid-subtract ((L-R)/2 and (R-L)/2)\n//\n// At alpha=1 any signal equal in L and R (centered vocals, snare, etc.)\n// cancels exactly, while content panned to one side survives at reduced\n// amplitude.\n// ============================================================================\n\nexport function computeKaraokeGains(amount: number): {\n gLL: number;\n gRL: number;\n gLR: number;\n gRR: number;\n} {\n const alpha = Math.max(0, Math.min(1, amount));\n const diag = 1 - alpha / 2;\n const cross = -alpha / 2;\n return { gLL: diag, gRL: cross, gLR: cross, gRR: diag };\n}\n\nexport class KaraokeNode {\n readonly input: ChannelSplitterNode;\n readonly output: ChannelMergerNode;\n readonly #gLL: GainNode;\n readonly #gRL: GainNode;\n readonly #gLR: GainNode;\n readonly #gRR: GainNode;\n readonly #ctx: BaseAudioContext;\n\n constructor(ctx: BaseAudioContext) {\n this.#ctx = ctx;\n this.input = ctx.createChannelSplitter(2);\n this.output = ctx.createChannelMerger(2);\n this.#gLL = ctx.createGain();\n this.#gRL = ctx.createGain();\n this.#gLR = ctx.createGain();\n this.#gRR = ctx.createGain();\n\n // L (channel 0) feeds gLL (into L_out) and gLR (into R_out).\n this.input.connect(this.#gLL, 0);\n this.input.connect(this.#gLR, 0);\n // R (channel 1) feeds gRL (into L_out) and gRR (into R_out).\n this.input.connect(this.#gRL, 1);\n this.input.connect(this.#gRR, 1);\n\n this.#gLL.connect(this.output, 0, 0);\n this.#gRL.connect(this.output, 0, 0);\n this.#gLR.connect(this.output, 0, 1);\n this.#gRR.connect(this.output, 0, 1);\n\n this.setAmount(0);\n }\n\n setAmount(amount: number): void {\n const { gLL, gRL, gLR, gRR } = computeKaraokeGains(amount);\n const t = this.#ctx.currentTime;\n this.#gLL.gain.setValueAtTime(gLL, t);\n this.#gRL.gain.setValueAtTime(gRL, t);\n this.#gLR.gain.setValueAtTime(gLR, t);\n this.#gRR.gain.setValueAtTime(gRR, t);\n }\n\n disconnect(): void {\n // Only sever outgoing connections from the merger. The internal\n // splitter -> gains -> merger wiring is structural and must survive\n // across rebuild-chain calls, or signal entering .input has no path\n // to .output and audio goes silent.\n this.output.disconnect();\n }\n}\n","let module = {}, exports = {};\n\nvar SignalsmithStretch = (() => {\n var _scriptName = typeof document != 'undefined' ? document.currentScript?.src : undefined;\n \n return (\nfunction(moduleArg = {}) {\n var moduleRtn;\n\nvar Module=moduleArg;var readyPromiseResolve,readyPromiseReject;var readyPromise=new Promise((resolve,reject)=>{readyPromiseResolve=resolve;readyPromiseReject=reject});var ENVIRONMENT_IS_WEB=typeof window==\"object\";var ENVIRONMENT_IS_WORKER=typeof WorkerGlobalScope!=\"undefined\";var ENVIRONMENT_IS_NODE=typeof process==\"object\"&&typeof process.versions==\"object\"&&typeof process.versions.node==\"string\"&&process.type!=\"renderer\";var ENVIRONMENT_IS_SHELL=!ENVIRONMENT_IS_WEB&&!ENVIRONMENT_IS_NODE&&!ENVIRONMENT_IS_WORKER;var crypto=globalThis?.crypto||{getRandomValues:array=>{for(var i=0;iDate.now()};var moduleOverrides=Object.assign({},Module);var arguments_=[];var quit_=(status,toThrow)=>{throw toThrow};var scriptDirectory=\"\";var readAsync,readBinary;if(ENVIRONMENT_IS_SHELL){readBinary=f=>{if(typeof readbuffer==\"function\"){return new Uint8Array(readbuffer(f))}let data=read(f,\"binary\");assert(typeof data==\"object\");return data};readAsync=f=>new Promise((resolve,reject)=>{setTimeout(()=>resolve(readBinary(f)))});globalThis.clearTimeout??=id=>{};globalThis.setTimeout??=f=>f();arguments_=globalThis.arguments||globalThis.scriptArgs;if(typeof quit==\"function\"){quit_=(status,toThrow)=>{setTimeout(()=>{if(!(toThrow instanceof ExitStatus)){let toLog=toThrow;if(toThrow&&typeof toThrow==\"object\"&&toThrow.stack){toLog=[toThrow,toThrow.stack]}err(`exiting due to exception: ${toLog}`)}quit(status)});throw toThrow}}if(typeof print!=\"undefined\"){globalThis.console??={};console.log=print;console.warn=console.error=globalThis.printErr??print}}else if(ENVIRONMENT_IS_WEB||ENVIRONMENT_IS_WORKER){if(ENVIRONMENT_IS_WORKER){scriptDirectory=self.location.href}else if(typeof document!=\"undefined\"&&document.currentScript){scriptDirectory=document.currentScript.src}if(_scriptName){scriptDirectory=_scriptName}if(scriptDirectory.startsWith(\"blob:\")){scriptDirectory=\"\"}else{scriptDirectory=scriptDirectory.substr(0,scriptDirectory.replace(/[?#].*/,\"\").lastIndexOf(\"/\")+1)}{if(ENVIRONMENT_IS_WORKER){readBinary=url=>{var xhr=new XMLHttpRequest;xhr.open(\"GET\",url,false);xhr.responseType=\"arraybuffer\";xhr.send(null);return new Uint8Array(xhr.response)}}readAsync=url=>fetch(url,{credentials:\"same-origin\"}).then(response=>{if(response.ok){return response.arrayBuffer()}return Promise.reject(new Error(response.status+\" : \"+response.url))})}}else{}var out=console.log.bind(console);var err=console.error.bind(console);Object.assign(Module,moduleOverrides);moduleOverrides=null;var wasmBinary;if(typeof atob==\"undefined\"){if(typeof global!=\"undefined\"&&typeof globalThis==\"undefined\"){globalThis=global}globalThis.atob=function(input){var keyStr=\"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=\";var output=\"\";var chr1,chr2,chr3;var enc1,enc2,enc3,enc4;var i=0;input=input.replace(/[^A-Za-z0-9\\+\\/\\=]/g,\"\");do{enc1=keyStr.indexOf(input.charAt(i++));enc2=keyStr.indexOf(input.charAt(i++));enc3=keyStr.indexOf(input.charAt(i++));enc4=keyStr.indexOf(input.charAt(i++));chr1=enc1<<2|enc2>>4;chr2=(enc2&15)<<4|enc3>>2;chr3=(enc3&3)<<6|enc4;output=output+String.fromCharCode(chr1);if(enc3!==64){output=output+String.fromCharCode(chr2)}if(enc4!==64){output=output+String.fromCharCode(chr3)}}while(ifilename.startsWith(dataURIPrefix);function findWasmBinary(){var f=\"data:application/octet-stream;base64,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fyAAKAIIIQMgBCgCACEFAkACQCABQQRPBEAgAyAFckEDcQ0BA0AgAygCACAFKAIARw0CIAVBBGohBSADQQRqIQMgAUEEayIBQQNLDQALCyABRQ0BCwNAIAMtAAAiCSAFLQAAIgpGBEAgBUEBaiEFIANBAWohAyABQQFrIgENAQwCCwsgCSAKawwBC0EACyIBDQBBACEBIAAoAgwiAyAEKAIEIgVGDQBBf0EBIAMgBUkbIQELIAZBEGokACABRSEDCyAEQRBqJAAgAEEgaiQAIANFBEAjAEEQayIFJABBuggQHCEEAn8gAi0AC0EHdgRAIAIoAgQMAQsgAi0AC0H/AHELIQMCfwJ/IwBBEGsiByQAIAhBBGohASADIARqIgBB9////wdNBEACQCAAQQtJBEAgAUIANwIAIAFBADYCCCABIAEtAAtBgAFxIABB/wBxcjoACyABIAEtAAtB/wBxOgALDAELIABBC08EfyAAQQhqQXhxIgYgBkEBayIGIAZBC0YbBUEKC0EBaiIGEAchCCABIAEoAghBgICAgHhxIAZB/////wdxcjYCCCABIAEoAghBgICAgHhyNgIIIAEgCDYCACABIAA2AgQLIAdBEGokACABDAELEA0ACyIALQALQQd2BEAgACgCAAwBCyAACyIAQboIIAQQGyAAIARqIgACfyACLQALQQd2BEAgAigCAAwBCyACCyADEBsgACADaiECIwBBEGsiACQAIABBADoAD0EBIQQDQCAEBEAgAiAALQAPOgAAIARBAWshBCACQQFqIQIMAQsLIABBEGokACAFQRBqJAACfyABLQALQQd2BEAgASgCAAwBC0EACxoQDgALIAhBEGokACAHLAAPQQBIBEAgBygCBBAECyMAQRBrIgIkACMAQRBrIgEkACACQQxqQQQQACIABH9B3DQgADYCAEF/BUEACyABKAIMGiABQRBqJAAEQEHcNCgCABoQDgALIAIoAgwhASACQRBqJABBkDRBASABQf////8HcCICIAJBAU0bNgIAQZw0QgA3AgBBlDRCADcCAEGoNEIANwMAQbA0QgA3AwAgB0EQaiQAQbg0QgA3AgBBwDRBADYCAEHENEIANwIAQcw0QQA2AgBB0DRCADcCAEHYNEEANgIAC+gBAQR/IwBBEGsiBiQAIwBBIGsiAyQAIwBBEGsiBCQAIAQg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\";return f}var wasmBinaryFile;function getBinarySync(file){if(file==wasmBinaryFile&&wasmBinary){return new Uint8Array(wasmBinary)}var binary=tryParseAsDataURI(file);if(binary){return binary}if(readBinary){return readBinary(file)}throw\"both async and sync fetching of the wasm failed\"}function getBinaryPromise(binaryFile){return Promise.resolve().then(()=>getBinarySync(binaryFile))}function instantiateArrayBuffer(binaryFile,imports,receiver){return getBinaryPromise(binaryFile).then(binary=>WebAssembly.instantiate(binary,imports)).then(receiver,reason=>{err(`failed to asynchronously prepare wasm: ${reason}`);abort(reason)})}function instantiateAsync(binary,binaryFile,imports,callback){return instantiateArrayBuffer(binaryFile,imports,callback)}function getWasmImports(){return{a:wasmImports}}function createWasm(){function receiveInstance(instance,module){wasmExports=instance.exports;wasmMemory=wasmExports[\"e\"];updateMemoryViews();addOnInit(wasmExports[\"f\"]);removeRunDependency(\"wasm-instantiate\");return wasmExports}addRunDependency(\"wasm-instantiate\");function receiveInstantiationResult(result){receiveInstance(result[\"instance\"])}var info=getWasmImports();wasmBinaryFile??=findWasmBinary();instantiateAsync(wasmBinary,wasmBinaryFile,info,receiveInstantiationResult).catch(readyPromiseReject);return{}}class ExitStatus{name=\"ExitStatus\";constructor(status){this.message=`Program terminated with exit(${status})`;this.status=status}}var callRuntimeCallbacks=callbacks=>{while(callbacks.length>0){callbacks.shift()(Module)}};var __abort_js=()=>abort(\"\");var __emscripten_memcpy_js=(dest,src,num)=>HEAPU8.copyWithin(dest,src,src+num);var getHeapMax=()=>2147483648;var alignMemory=(size,alignment)=>Math.ceil(size/alignment)*alignment;var abortOnCannotGrowMemory=requestedSize=>{abort(\"OOM\")};var growMemory=size=>{var b=wasmMemory.buffer;var pages=(size-b.byteLength+65535)/65536|0;try{wasmMemory.grow(pages);updateMemoryViews();return 1}catch(e){}};var _emscripten_resize_heap=requestedSize=>{var oldSize=HEAPU8.length;requestedSize>>>=0;var maxHeapSize=getHeapMax();if(requestedSize>maxHeapSize){abortOnCannotGrowMemory(requestedSize)}for(var cutDown=1;cutDown<=4;cutDown*=2){var overGrownHeapSize=oldSize*(1+.5/cutDown);overGrownHeapSize=Math.min(overGrownHeapSize,requestedSize+100663296);var newSize=Math.min(maxHeapSize,alignMemory(Math.max(requestedSize,overGrownHeapSize),65536));var replacement=growMemory(newSize);if(replacement){return true}}abortOnCannotGrowMemory(requestedSize)};var initRandomFill=()=>{if(typeof crypto==\"object\"&&typeof crypto[\"getRandomValues\"]==\"function\"){return view=>crypto.getRandomValues(view)}else abort(\"initRandomDevice\")};var randomFill=view=>(randomFill=initRandomFill())(view);var _random_get=(buffer,size)=>{randomFill(HEAPU8.subarray(buffer,buffer+size));return 0};var keepRuntimeAlive=()=>true;var _proc_exit=code=>{EXITSTATUS=code;if(!keepRuntimeAlive()){ABORT=true}quit_(code,new ExitStatus(code))};var exitJS=(status,implicit)=>{EXITSTATUS=status;_proc_exit(status)};var handleException=e=>{if(e instanceof ExitStatus||e==\"unwind\"){return EXITSTATUS}quit_(1,e)};var UTF8Decoder=typeof TextDecoder!=\"undefined\"?new TextDecoder:undefined;var UTF8ArrayToString=(heapOrArray,idx=0,maxBytesToRead=NaN)=>{var endIdx=idx+maxBytesToRead;var endPtr=idx;while(heapOrArray[endPtr]&&!(endPtr>=endIdx))++endPtr;if(endPtr-idx>16&&heapOrArray.buffer&&UTF8Decoder){return UTF8Decoder.decode(heapOrArray.subarray(idx,endPtr))}var str=\"\";while(idx>10,56320|ch&1023)}}return str};var UTF8ToString=(ptr,maxBytesToRead)=>ptr?UTF8ArrayToString(HEAPU8,ptr,maxBytesToRead):\"\";var wasmImports={d:__abort_js,c:__emscripten_memcpy_js,b:_emscripten_resize_heap,a:_random_get};var wasmExports=createWasm();var ___wasm_call_ctors=()=>(___wasm_call_ctors=wasmExports[\"f\"])();var _setBuffers=Module[\"_setBuffers\"]=(a0,a1)=>(_setBuffers=Module[\"_setBuffers\"]=wasmExports[\"h\"])(a0,a1);var _blockSamples=Module[\"_blockSamples\"]=()=>(_blockSamples=Module[\"_blockSamples\"]=wasmExports[\"i\"])();var _intervalSamples=Module[\"_intervalSamples\"]=()=>(_intervalSamples=Module[\"_intervalSamples\"]=wasmExports[\"j\"])();var _inputLatency=Module[\"_inputLatency\"]=()=>(_inputLatency=Module[\"_inputLatency\"]=wasmExports[\"k\"])();var _outputLatency=Module[\"_outputLatency\"]=()=>(_outputLatency=Module[\"_outputLatency\"]=wasmExports[\"l\"])();var _reset=Module[\"_reset\"]=()=>(_reset=Module[\"_reset\"]=wasmExports[\"m\"])();var _presetDefault=Module[\"_presetDefault\"]=(a0,a1)=>(_presetDefault=Module[\"_presetDefault\"]=wasmExports[\"n\"])(a0,a1);var _presetCheaper=Module[\"_presetCheaper\"]=(a0,a1)=>(_presetCheaper=Module[\"_presetCheaper\"]=wasmExports[\"o\"])(a0,a1);var _configure=Module[\"_configure\"]=(a0,a1,a2,a3)=>(_configure=Module[\"_configure\"]=wasmExports[\"p\"])(a0,a1,a2,a3);var _setTransposeFactor=Module[\"_setTransposeFactor\"]=(a0,a1)=>(_setTransposeFactor=Module[\"_setTransposeFactor\"]=wasmExports[\"q\"])(a0,a1);var _setTransposeSemitones=Module[\"_setTransposeSemitones\"]=(a0,a1)=>(_setTransposeSemitones=Module[\"_setTransposeSemitones\"]=wasmExports[\"r\"])(a0,a1);var _setFormantFactor=Module[\"_setFormantFactor\"]=(a0,a1)=>(_setFormantFactor=Module[\"_setFormantFactor\"]=wasmExports[\"s\"])(a0,a1);var _setFormantSemitones=Module[\"_setFormantSemitones\"]=(a0,a1)=>(_setFormantSemitones=Module[\"_setFormantSemitones\"]=wasmExports[\"t\"])(a0,a1);var _setFormantBase=Module[\"_setFormantBase\"]=a0=>(_setFormantBase=Module[\"_setFormantBase\"]=wasmExports[\"u\"])(a0);var _seek=Module[\"_seek\"]=(a0,a1)=>(_seek=Module[\"_seek\"]=wasmExports[\"v\"])(a0,a1);var _process=Module[\"_process\"]=(a0,a1)=>(_process=Module[\"_process\"]=wasmExports[\"w\"])(a0,a1);var _flush=Module[\"_flush\"]=a0=>(_flush=Module[\"_flush\"]=wasmExports[\"x\"])(a0);var _main=Module[\"_main\"]=(a0,a1)=>(_main=Module[\"_main\"]=wasmExports[\"y\"])(a0,a1);Module[\"UTF8ToString\"]=UTF8ToString;var calledRun;dependenciesFulfilled=function runCaller(){if(!calledRun)run();if(!calledRun)dependenciesFulfilled=runCaller};function callMain(){var entryFunction=_main;var argc=0;var argv=0;try{var ret=entryFunction(argc,argv);exitJS(ret,true);return ret}catch(e){return handleException(e)}}function run(){if(runDependencies>0){return}preRun();if(runDependencies>0){return}function doRun(){if(calledRun)return;calledRun=true;Module[\"calledRun\"]=true;if(ABORT)return;initRuntime();preMain();readyPromiseResolve(Module);if(shouldRunNow)callMain();postRun()}{doRun()}}var shouldRunNow=true;run();moduleRtn=readyPromise;\n\n\n return moduleRtn;\n}\n);\n})();\nif (typeof exports === 'object' && typeof module === 'object')\n module.exports = SignalsmithStretch;\nelse if (typeof define === 'function' && define['amd'])\n define([], () => SignalsmithStretch);\n\"use strict\";\nfunction registerWorkletProcessor(ModuleFactory, audioNodeKey) {\n class WasmProcessor extends AudioWorkletProcessor {\n constructor(options = {}) {\n super(options);\n this.wasmReady = false;\n this.wasmModule = null;\n this.channels = 0;\n this.buffersIn = [];\n this.buffersOut = [];\n this.audioBuffers = [];\n this.audioBuffersStart = 0;\n this.audioBuffersEnd = 0;\n this.timeIntervalSamples = sampleRate * 0.1;\n this.timeIntervalCounter = 0;\n this.bufferLength = 0;\n this.inputLatencySeconds = 0;\n this.outputLatencySeconds = 0;\n this.timeMap = [\n {\n active: false,\n input: 0,\n output: 0,\n rate: 1,\n semitones: 0,\n tonalityHz: 8000,\n formantSemitones: 0,\n formantCompensation: false,\n formantBaseHz: 0,\n loopStart: 0,\n loopEnd: 0\n }\n ];\n this.config = { preset: 'default' };\n this.pendingMessages = [];\n this.port.onmessage = (event) => this.pendingMessages.push(event);\n ModuleFactory().then(wasmModule => {\n this.wasmModule = wasmModule;\n this.wasmReady = true;\n wasmModule._main();\n this.channels = options.numberOfOutputs ? options.outputChannelCount?.[0] ?? 2 : 2;\n this.configure();\n const remoteMethods = {\n configure: config => {\n Object.assign(this.config, config);\n this.configure();\n },\n latency: () => this.inputLatencySeconds + this.outputLatencySeconds,\n setUpdateInterval: seconds => {\n this.timeIntervalSamples = sampleRate * seconds;\n },\n stop: when => {\n const stopTime = typeof when === 'number' ? when : currentTime;\n return remoteMethods.schedule({ active: false, output: stopTime });\n },\n start: (when, offset, duration, rate, semitones) => {\n if (typeof when === 'object') {\n const schedule = when;\n if (!('active' in schedule))\n schedule.active = true;\n return remoteMethods.schedule(schedule);\n }\n const obj = {\n active: true,\n input: 0,\n output: currentTime + this.outputLatencySeconds\n };\n if (typeof when === 'number')\n obj.output = when;\n if (typeof offset === 'number')\n obj.input = offset;\n if (typeof rate === 'number')\n obj.rate = rate;\n if (typeof semitones === 'number')\n obj.semitones = semitones;\n const result = remoteMethods.schedule(obj);\n if (typeof duration === 'number') {\n remoteMethods.stop((obj.output ?? 0) + duration);\n if (obj.output !== undefined) {\n obj.output += duration;\n }\n obj.active = false;\n remoteMethods.schedule(obj);\n }\n return result;\n },\n schedule: (objIn, adjustPrevious) => {\n const outputTime = 'outputTime' in objIn ? objIn.outputTime : currentTime;\n let latestSegment = this.timeMap[this.timeMap.length - 1];\n while (this.timeMap.length && (this.timeMap[this.timeMap.length - 1].output ?? 0) >= outputTime) {\n latestSegment = this.timeMap.pop();\n }\n const obj = {\n active: latestSegment.active,\n input: null,\n output: outputTime,\n rate: latestSegment.rate,\n semitones: latestSegment.semitones,\n loopStart: latestSegment.loopStart,\n loopEnd: latestSegment.loopEnd\n };\n Object.assign(obj, objIn);\n if (obj.input === null) {\n const rate = latestSegment.active ? (latestSegment.rate ?? 0) : 0;\n obj.input = (latestSegment.input ?? 0) + ((obj.output ?? 0) - (latestSegment.output ?? 0)) * rate;\n }\n this.timeMap.push(obj);\n if (adjustPrevious && this.timeMap.length > 1) {\n const previous = this.timeMap[this.timeMap.length - 2];\n if ((previous.output ?? 0) < currentTime) {\n const rate = previous.active ? (previous.rate ?? 0) : 0;\n previous.input = (previous.input ?? 0) + (currentTime - (previous.output ?? 0)) * rate;\n previous.output = currentTime;\n }\n if ((obj.output ?? 0) !== (previous.output ?? 0)) {\n previous.rate = ((obj.input ?? 0) - (previous.input ?? 0)) / ((obj.output ?? 0) - (previous.output ?? 0));\n }\n }\n let currentMapSegment = this.timeMap[0];\n while (this.timeMap.length > 1 && (this.timeMap[1].output ?? 0) <= outputTime) {\n this.timeMap.shift();\n currentMapSegment = this.timeMap[0];\n }\n const rate = currentMapSegment.active ? (currentMapSegment.rate ?? 0) : 0;\n const inputTime = (currentMapSegment.input ?? 0) + (outputTime - (currentMapSegment.output ?? 0)) * rate;\n this.timeIntervalCounter = this.timeIntervalSamples;\n this.port.postMessage(['time', inputTime]);\n return obj;\n },\n dropBuffers: toSeconds => {\n if (typeof toSeconds !== 'number') {\n const buffers = this.audioBuffers.flat(1).map(buffer => buffer.buffer);\n this.audioBuffers = [];\n this.audioBuffersStart = this.audioBuffersEnd = 0;\n return {\n value: { start: 0, end: 0 },\n transfer: buffers\n };\n }\n const transfer = [];\n while (this.audioBuffers.length) {\n const first = this.audioBuffers[0];\n const length = first[0].length;\n const endSamples = this.audioBuffersStart + length;\n const endSeconds = endSamples / sampleRate;\n if (endSeconds > toSeconds)\n break;\n this.audioBuffers.shift().forEach(buffer => transfer.push(buffer.buffer));\n this.audioBuffersStart += length;\n }\n return {\n value: {\n start: this.audioBuffersStart / sampleRate,\n end: this.audioBuffersEnd / sampleRate\n },\n transfer\n };\n },\n addBuffers: sampleBuffers => {\n const bufferSet = [].concat(sampleBuffers);\n this.audioBuffers.push(bufferSet);\n const length = bufferSet[0]?.length ?? 0;\n this.audioBuffersEnd += length;\n return this.audioBuffersEnd / sampleRate;\n }\n };\n const pendingMessages = this.pendingMessages;\n this.port.onmessage = (event) => {\n const data = event.data;\n const messageId = data.shift();\n const methodName = data.shift();\n const args = data;\n const method = remoteMethods[methodName];\n const result = method(...args);\n if (result?.transfer) {\n const transferResult = result;\n this.port.postMessage([messageId, transferResult.value], transferResult.transfer);\n }\n else {\n this.port.postMessage([messageId, result]);\n }\n };\n const methodArgCounts = Object.keys(remoteMethods).reduce((map, key) => {\n const typedKey = key;\n map[typedKey] = remoteMethods[typedKey].length;\n return map;\n }, {});\n this.port.postMessage(['ready', methodArgCounts]);\n pendingMessages.forEach(message => this.port.onmessage(message));\n this.pendingMessages = [];\n });\n }\n configure() {\n const wasmModule = this.wasmModule;\n if (!wasmModule)\n return;\n if (this.config.blockMs) {\n const blockSamples = Math.round((this.config.blockMs / 1000) * sampleRate);\n const intervalSamples = Math.round(((this.config.intervalMs ?? (this.config.blockMs * 0.25)) / 1000) * sampleRate);\n const splitComputation = Boolean(this.config.splitComputation);\n wasmModule._configure(this.channels, blockSamples, intervalSamples, splitComputation);\n wasmModule._reset();\n }\n else if (this.config.preset === 'cheaper') {\n wasmModule._presetCheaper(this.channels, sampleRate);\n }\n else {\n wasmModule._presetDefault(this.channels, sampleRate);\n }\n this.updateBuffers();\n this.inputLatencySeconds = wasmModule._inputLatency() / sampleRate;\n this.outputLatencySeconds = wasmModule._outputLatency() / sampleRate;\n }\n updateBuffers() {\n const wasmModule = this.wasmModule;\n if (!wasmModule)\n return;\n this.bufferLength = wasmModule._inputLatency() + wasmModule._outputLatency();\n const lengthBytes = this.bufferLength * 4;\n const bufferPointer = wasmModule._setBuffers(this.channels, this.bufferLength);\n this.buffersIn = [];\n this.buffersOut = [];\n for (let c = 0; c < this.channels; ++c) {\n this.buffersIn.push(bufferPointer + lengthBytes * c);\n this.buffersOut.push(bufferPointer + lengthBytes * (c + this.channels));\n }\n }\n process(inputList, outputList) {\n if (!this.wasmReady || !this.wasmModule) {\n outputList.forEach(output => {\n output.forEach(channel => channel.fill(0));\n });\n return true;\n }\n if (!outputList[0]?.length)\n return false;\n let outputTime = currentTime + this.outputLatencySeconds;\n while (this.timeMap.length > 1 && (this.timeMap[1].output ?? 0) <= outputTime) {\n this.timeMap.shift();\n }\n const currentMapSegment = this.timeMap[0];\n const wasmModule = this.wasmModule;\n wasmModule._setTransposeSemitones(currentMapSegment.semitones ?? 0, (currentMapSegment.tonalityHz ?? 0) / sampleRate);\n wasmModule._setFormantSemitones(currentMapSegment.formantSemitones ?? 0, Boolean(currentMapSegment.formantCompensation));\n wasmModule._setFormantBase((currentMapSegment.formantBaseHz ?? 0) / sampleRate);\n if ((outputList[0].length ?? 0) !== this.channels) {\n this.channels = outputList[0]?.length ?? 0;\n this.configure();\n }\n const outputBlockSize = outputList[0][0].length;\n let memory = wasmModule.exports ? wasmModule.exports.memory.buffer : wasmModule.HEAP8.buffer;\n const inputs = inputList[0];\n if (!currentMapSegment.active) {\n outputList[0].forEach((_, c) => {\n const buffer = new Float32Array(memory, this.buffersIn[c], outputBlockSize);\n buffer.fill(0);\n });\n wasmModule._process(outputBlockSize, outputBlockSize);\n }\n else if (inputs?.length) {\n outputList[0].forEach((_, c) => {\n const channelBuffer = inputs[c % inputs.length];\n const buffer = new Float32Array(memory, this.buffersIn[c], outputBlockSize);\n if (channelBuffer) {\n buffer.set(channelBuffer);\n }\n else {\n buffer.fill(0);\n }\n });\n wasmModule._process(outputBlockSize, outputBlockSize);\n }\n else {\n let inputTime = (currentMapSegment.input ?? 0) + (outputTime - (currentMapSegment.output ?? 0)) * (currentMapSegment.rate ?? 0);\n const loopLength = (currentMapSegment.loopEnd ?? 0) - (currentMapSegment.loopStart ?? 0);\n if (loopLength > 0 && inputTime >= (currentMapSegment.loopEnd ?? 0)) {\n currentMapSegment.input = (currentMapSegment.input ?? 0) - loopLength;\n inputTime -= loopLength;\n }\n inputTime += this.inputLatencySeconds;\n const inputSamplesEnd = Math.round(inputTime * sampleRate);\n const buffers = outputList[0].map((_, c) => new Float32Array(memory, this.buffersIn[c], this.bufferLength));\n let blockSamples = 0;\n let audioBufferIndex = 0;\n let audioSamples = this.audioBuffersStart;\n let inputSamples = inputSamplesEnd - this.bufferLength;\n if (inputSamples < audioSamples) {\n blockSamples = audioSamples - inputSamples;\n buffers.forEach(buffer => buffer.fill(0, 0, blockSamples));\n inputSamples = audioSamples;\n }\n while (audioBufferIndex < this.audioBuffers.length && audioSamples < inputSamplesEnd) {\n const audioBuffer = this.audioBuffers[audioBufferIndex];\n const startIndex = inputSamples - audioSamples;\n const bufferEnd = audioSamples + audioBuffer[0].length;\n const count = Math.min(audioBuffer[0].length - startIndex, inputSamplesEnd - inputSamples);\n if (count > 0) {\n buffers.forEach((buffer, c) => {\n const channelBuffer = audioBuffer[c % audioBuffer.length];\n buffer.subarray(blockSamples).set(channelBuffer.subarray(startIndex, startIndex + count));\n });\n audioSamples += count;\n blockSamples += count;\n }\n else {\n audioSamples += audioBuffer[0].length;\n }\n ++audioBufferIndex;\n }\n if (blockSamples < this.bufferLength) {\n buffers.forEach(buffer => buffer.subarray(blockSamples).fill(0));\n }\n wasmModule._seek(this.bufferLength, currentMapSegment.rate ?? 0);\n wasmModule._process(0, outputBlockSize);\n this.timeIntervalCounter -= outputBlockSize;\n if (this.timeIntervalCounter <= 0) {\n this.timeIntervalCounter = this.timeIntervalSamples;\n this.port.postMessage(['time', inputTime]);\n }\n }\n memory = wasmModule.exports ? wasmModule.exports.memory.buffer : wasmModule.HEAP8.buffer;\n outputList[0].forEach((channelBuffer, c) => {\n const buffer = new Float32Array(memory, this.buffersOut[c], outputBlockSize);\n channelBuffer.set(buffer);\n });\n return true;\n }\n }\n registerProcessor(audioNodeKey, WasmProcessor);\n}\nfunction createStretchBinding(ModuleFactory, audioNodeKey = 'signalsmith-stretch') {\n if (typeof AudioWorkletProcessor === 'function' && typeof registerProcessor === 'function') {\n registerWorkletProcessor(ModuleFactory, audioNodeKey);\n return {};\n }\n const promiseKey = Symbol('SignalsmithStretchModule');\n const createNode = async (audioContext, options) => {\n let audioNode;\n const nodeOptions = options ?? {\n numberOfInputs: 1,\n numberOfOutputs: 1,\n outputChannelCount: [2]\n };\n try {\n audioNode = new AudioWorkletNode(audioContext, audioNodeKey, nodeOptions);\n }\n catch (error) {\n const ctx = audioContext;\n if (!ctx[promiseKey]) {\n let moduleUrl = createNode.moduleUrl;\n if (!moduleUrl) {\n const moduleCode = `(${registerWorkletProcessor})((_scriptName=>${ModuleFactory})(),${JSON.stringify(audioNodeKey)})`;\n moduleUrl = URL.createObjectURL(new Blob([moduleCode], { type: 'text/javascript' }));\n createNode.moduleUrl = moduleUrl;\n }\n ctx[promiseKey] = ctx.audioWorklet.addModule(moduleUrl);\n }\n await ctx[promiseKey];\n audioNode = new AudioWorkletNode(audioContext, audioNodeKey, nodeOptions);\n }\n const requestMap = {};\n let idCounter = 0;\n let timeUpdateCallback = null;\n const post = (transfer, ...data) => {\n const id = idCounter++;\n return new Promise(resolve => {\n requestMap[id] = resolve;\n if (transfer && transfer.length) {\n audioNode.port.postMessage([id, ...data], transfer);\n }\n else {\n audioNode.port.postMessage([id, ...data]);\n }\n });\n };\n audioNode.inputTime = 0;\n audioNode.port.onmessage = (event) => {\n const data = event.data;\n const [id, value] = data;\n if (id === 'time') {\n audioNode.inputTime = value;\n if (timeUpdateCallback)\n timeUpdateCallback(value);\n }\n if (id in requestMap) {\n requestMap[id](value);\n delete requestMap[id];\n }\n };\n return new Promise(resolve => {\n requestMap['ready'] = (remoteMethodKeys) => {\n Object.keys(remoteMethodKeys).forEach(key => {\n const argCount = remoteMethodKeys[key];\n audioNode[key] = (...args) => {\n let transfer = null;\n if (args.length > argCount) {\n transfer = args.pop();\n }\n return post(transfer, key, ...args);\n };\n });\n audioNode.setUpdateInterval = (seconds, callback) => {\n timeUpdateCallback = callback ?? null;\n return post(null, 'setUpdateInterval', seconds);\n };\n resolve(audioNode);\n };\n });\n };\n return createNode;\n}\nconst stretchEntry = createStretchBinding(SignalsmithStretch, 'signalsmith-stretch');\n// eslint-disable-next-line @typescript-eslint/ban-ts-comment\n// @ts-ignore - reassign the global factory exported by the WASM bundle\nSignalsmithStretch = stretchEntry;\nif (typeof exports === 'object' && typeof module === 'object' && module) {\n module.exports = stretchEntry;\n}\nelse if (typeof define === 'function' && define.amd) {\n define([], () => stretchEntry);\n}\nlet _export=SignalsmithStretch;export default _export;\n","import { AudioFile } from \"./AudioFile\";\nimport { ReverbFill } from \"./ReverbFill\"; // ReverbFill\nimport {\n CountInController,\n type CountInContextOptions,\n type CountInHost,\n} from \"./CountInController\";\nimport {\n SporadiciserController,\n type SporadiciserHost,\n} from \"./SporadiciserController\";\nimport { StereoFocusNode } from \"./StereoFocusNode\";\nimport { KaraokeNode } from \"./KaraokeNode\";\nimport type { AudioEngineState, LoadOptions } from \"./types\";\nimport * as PlayheadCalculator from \"./PlayheadCalculator\";\nimport _SignalsmithStretch from \"./vendor/SignalsmithStretch.mjs\";\nimport type {\n StretchNode,\n SignalsmithStretchEntryPoint,\n} from \"./vendor/SignalsmithStretch.mjs.d.ts\";\n\nconst SignalsmithStretch =\n _SignalsmithStretch as unknown as SignalsmithStretchEntryPoint;\n\n// ============================================================================\n// Constants\n// ============================================================================\n\n// 6 musically-spaced bands: lowshelf, 4 peaking, highshelf. See `#applyEQ`\n// for the fixed Q values (peaking = 1.0, shelves = 0.707 / Butterworth).\nexport const EQ_BANDS = [80, 240, 750, 2500, 6000, 12000];\nexport const AVAILABLE_SPEEDS = [25, 50, 75, 100];\n\n// Tolerance used by `seek` to decide if a seek target is inside the passage.\nconst COUNT_IN_SEEK_INSIDE_TOLERANCE_S = 0.01;\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport type LoadingProgress =\n | { phase: \"downloading\"; progress: number }\n | { phase: \"decoding\" }\n | { phase: \"initializing\" };\n\ntype Listener = () => void;\n\nexport type { CountInContextOptions };\n\n// ============================================================================\n// iOS silent-switch bypass\n//\n// On iOS, Web Audio output is muted when the hardware silent switch is on.\n// Playing a looping silent