@waveform-playlist/spectrogram 9.5.1 → 10.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/computation/fft.ts","../src/computation/windowFunctions.ts","../src/computation/computeSpectrogram.ts","../src/computation/colorMaps.ts","../src/computation/frequencyScales.ts","../src/components/SpectrogramMenuItems.tsx","../src/components/SpectrogramSettingsModal.tsx","../src/worker/createSpectrogramWorker.ts","../src/worker/createSpectrogramWorkerPool.ts","../src/SpectrogramProvider.tsx"],"sourcesContent":["// Computation\nexport {\n computeSpectrogram,\n computeSpectrogramMono,\n getColorMap,\n getFrequencyScale,\n} from './computation';\nexport type { FrequencyScaleName } from './computation';\n\n// Components\nexport { SpectrogramMenuItems } from './components';\nexport type { SpectrogramMenuItemsProps } from './components';\nexport { SpectrogramSettingsModal } from './components';\nexport type { SpectrogramSettingsModalProps } from './components';\nexport type { TrackMenuItem } from './components';\n\n// Worker\nexport { createSpectrogramWorker, SpectrogramAbortError } from './worker';\nexport { createSpectrogramWorkerPool } from './worker';\nexport type { SpectrogramWorkerApi } from './worker';\n\n// Provider\nexport { SpectrogramProvider } from './SpectrogramProvider';\nexport type { SpectrogramProviderProps } from './SpectrogramProvider';\n","import FFT from 'fft.js';\n\n/**\n * Cache fft.js instances per size (pre-computes twiddle factors).\n */\nconst fftInstances = new Map<number, FFT>();\nconst complexBuffers = new Map<number, number[]>();\n\nfunction getFftInstance(size: number): FFT {\n let instance = fftInstances.get(size);\n if (!instance) {\n instance = new FFT(size);\n fftInstances.set(size, instance);\n complexBuffers.set(size, instance.createComplexArray());\n }\n return instance;\n}\n\nfunction getComplexBuffer(size: number): number[] {\n const buffer = complexBuffers.get(size);\n if (!buffer) {\n throw new Error(`No complex buffer for size ${size}. Call getFftInstance first.`);\n }\n return buffer;\n}\n\n/**\n * In-place FFT using fft.js (radix-4).\n * @param real - Real part (modified in place)\n * @param imag - Imaginary part (modified in place)\n */\nexport function fft(real: Float32Array, imag: Float32Array): void {\n const n = real.length;\n const f = getFftInstance(n);\n const input = f.createComplexArray();\n const out = getComplexBuffer(n);\n\n for (let i = 0; i < n; i++) {\n input[i * 2] = real[i];\n input[i * 2 + 1] = imag[i];\n }\n\n f.transform(out, input);\n\n for (let i = 0; i < n; i++) {\n real[i] = out[i * 2];\n imag[i] = out[i * 2 + 1];\n }\n}\n\n/**\n * Fused FFT → magnitude → decibels for real-valued input.\n * Uses fft.js realTransform (radix-4, ~25% faster for real input).\n * Writes dB values for positive frequencies (n/2 bins) into `out`.\n *\n * @param real - Real input (windowed audio frame, length n)\n * @param out - Output array for dB values (length >= n/2)\n */\nexport function fftMagnitudeDb(real: Float32Array, out: Float32Array): void {\n const n = real.length;\n const f = getFftInstance(n);\n const complexOut = getComplexBuffer(n);\n\n f.realTransform(complexOut, real);\n\n const half = n >> 1;\n for (let i = 0; i < half; i++) {\n const re = complexOut[i * 2];\n const im = complexOut[i * 2 + 1];\n let db = 20 * Math.log10(Math.sqrt(re * re + im * im) + 1e-10);\n if (db < -160) db = -160;\n out[i] = db;\n }\n}\n\n/**\n * Compute magnitude spectrum from FFT output.\n * Returns only the first half (positive frequencies).\n */\nexport function magnitudeSpectrum(real: Float32Array, imag: Float32Array): Float32Array {\n const n = real.length >> 1;\n const magnitudes = new Float32Array(n);\n for (let i = 0; i < n; i++) {\n magnitudes[i] = Math.sqrt(real[i] * real[i] + imag[i] * imag[i]);\n }\n return magnitudes;\n}\n\n/**\n * Convert magnitudes to decibels with a fixed -160 dB floor.\n * Gain is applied at render time, not during FFT.\n */\nexport function toDecibels(magnitudes: Float32Array): Float32Array {\n const result = new Float32Array(magnitudes.length);\n for (let i = 0; i < magnitudes.length; i++) {\n let db = 20 * Math.log10(magnitudes[i] + 1e-10);\n if (db < -160) db = -160;\n result[i] = db;\n }\n return result;\n}\n","/**\n * Window functions for spectral analysis.\n *\n * Uses periodic (DFT-even) windows where the denominator is N, not N-1.\n * Periodic windows tile perfectly over consecutive FFT frames, giving better\n * frequency resolution in STFT/spectrogram computation. This matches the\n * convention used by Audacity, SciPy (sym=False), and MATLAB ('periodic').\n */\n\nexport function getWindowFunction(name: string, size: number, alpha?: number): Float32Array {\n const window = new Float32Array(size);\n const N = size;\n\n switch (name) {\n case 'rectangular':\n for (let i = 0; i < size; i++) window[i] = 1;\n break;\n\n case 'bartlett':\n for (let i = 0; i < size; i++) {\n window[i] = 1 - Math.abs((2 * i - N) / N);\n }\n break;\n\n case 'hann':\n for (let i = 0; i < size; i++) {\n window[i] = 0.5 * (1 - Math.cos((2 * Math.PI * i) / N));\n }\n break;\n\n case 'hamming':\n for (let i = 0; i < size; i++) {\n const a = alpha ?? 0.54;\n window[i] = a - (1 - a) * Math.cos((2 * Math.PI * i) / N);\n }\n break;\n\n case 'blackman': {\n const a0 = 0.42;\n const a1 = 0.5;\n const a2 = 0.08;\n for (let i = 0; i < size; i++) {\n window[i] =\n a0 - a1 * Math.cos((2 * Math.PI * i) / N) + a2 * Math.cos((4 * Math.PI * i) / N);\n }\n break;\n }\n\n case 'blackman-harris': {\n const c0 = 0.35875;\n const c1 = 0.48829;\n const c2 = 0.14128;\n const c3 = 0.01168;\n for (let i = 0; i < size; i++) {\n window[i] =\n c0 -\n c1 * Math.cos((2 * Math.PI * i) / N) +\n c2 * Math.cos((4 * Math.PI * i) / N) -\n c3 * Math.cos((6 * Math.PI * i) / N);\n }\n break;\n }\n\n default:\n console.warn(`[spectrogram] Unknown window function \"${name}\", falling back to hann`);\n for (let i = 0; i < size; i++) {\n window[i] = 0.5 * (1 - Math.cos((2 * Math.PI * i) / N));\n }\n }\n\n // Amplitude normalization: scale so a 0 dB sine produces a 0 dB spectrum peak.\n // Matches Audacity: scale = 2.0 / sum(window)\n let sum = 0;\n for (let i = 0; i < size; i++) sum += window[i];\n if (sum > 0) {\n const scale = 2.0 / sum;\n for (let i = 0; i < size; i++) window[i] *= scale;\n }\n\n return window;\n}\n","/**\n * Compute spectrogram data from an AudioBuffer.\n */\n\nimport type { SpectrogramConfig, SpectrogramData } from '@waveform-playlist/core';\nimport { fftMagnitudeDb } from './fft';\nimport { getWindowFunction } from './windowFunctions';\n\n/**\n * Compute spectrogram for a single channel of audio.\n *\n * @param audioBuffer - Source audio buffer\n * @param config - Spectrogram configuration\n * @param offsetSamples - Start offset into the audio buffer\n * @param durationSamples - Number of samples to process\n * @param channel - Channel index (0 = left, 1 = right). Default: 0\n */\nexport function computeSpectrogram(\n audioBuffer: AudioBuffer,\n config: SpectrogramConfig = {},\n offsetSamples: number = 0,\n durationSamples?: number,\n channel: number = 0\n): SpectrogramData {\n const windowSize = config.fftSize ?? 2048;\n const zeroPaddingFactor = config.zeroPaddingFactor ?? 2;\n const actualFftSize = windowSize * zeroPaddingFactor;\n const hopSize = config.hopSize ?? Math.floor(windowSize / 4);\n const windowName = config.windowFunction ?? 'hann';\n const gainDb = config.gainDb ?? 20;\n const rangeDb = config.rangeDb ?? 80;\n const alpha = config.alpha;\n\n const sampleRate = audioBuffer.sampleRate;\n const frequencyBinCount = actualFftSize >> 1;\n const totalSamples = durationSamples ?? audioBuffer.length - offsetSamples;\n\n // Get channel data\n const channelIdx = Math.min(channel, audioBuffer.numberOfChannels - 1);\n const channelData = audioBuffer.getChannelData(channelIdx);\n\n // Pre-compute window (at windowSize, not actualFftSize)\n const window = getWindowFunction(windowName, windowSize, alpha);\n\n // Calculate frame count (step by windowSize, not actualFftSize)\n const frameCount = Math.max(1, Math.floor((totalSamples - windowSize) / hopSize) + 1);\n\n // Output: frameCount × frequencyBinCount\n const data = new Float32Array(frameCount * frequencyBinCount);\n\n // Reusable buffers at actualFftSize\n const real = new Float32Array(actualFftSize);\n const dbBuf = new Float32Array(frequencyBinCount);\n\n for (let frame = 0; frame < frameCount; frame++) {\n const start = offsetSamples + frame * hopSize;\n\n // Fill first windowSize samples with windowed audio, rest stays zero\n for (let i = 0; i < windowSize; i++) {\n const sampleIdx = start + i;\n real[i] = sampleIdx < channelData.length ? channelData[sampleIdx] * window[i] : 0;\n }\n // Zero-pad the rest\n for (let i = windowSize; i < actualFftSize; i++) {\n real[i] = 0;\n }\n\n fftMagnitudeDb(real, dbBuf);\n data.set(dbBuf, frame * frequencyBinCount);\n }\n\n return {\n fftSize: actualFftSize,\n windowSize,\n frequencyBinCount,\n sampleRate,\n hopSize,\n frameCount,\n data,\n gainDb,\n rangeDb,\n };\n}\n\n/**\n * Compute a mono (mixed-down) spectrogram from all channels.\n */\nexport function computeSpectrogramMono(\n audioBuffer: AudioBuffer,\n config: SpectrogramConfig = {},\n offsetSamples: number = 0,\n durationSamples?: number\n): SpectrogramData {\n if (audioBuffer.numberOfChannels === 1) {\n return computeSpectrogram(audioBuffer, config, offsetSamples, durationSamples, 0);\n }\n\n // Mix down channels\n const windowSize = config.fftSize ?? 2048;\n const zeroPaddingFactor = config.zeroPaddingFactor ?? 2;\n const actualFftSize = windowSize * zeroPaddingFactor;\n const hopSize = config.hopSize ?? Math.floor(windowSize / 4);\n const windowName = config.windowFunction ?? 'hann';\n const gainDb = config.gainDb ?? 20;\n const rangeDb = config.rangeDb ?? 80;\n const alpha = config.alpha;\n\n const sampleRate = audioBuffer.sampleRate;\n const frequencyBinCount = actualFftSize >> 1;\n const totalSamples = durationSamples ?? audioBuffer.length - offsetSamples;\n const numChannels = audioBuffer.numberOfChannels;\n\n const window = getWindowFunction(windowName, windowSize, alpha);\n const frameCount = Math.max(1, Math.floor((totalSamples - windowSize) / hopSize) + 1);\n const data = new Float32Array(frameCount * frequencyBinCount);\n const real = new Float32Array(actualFftSize);\n const dbBuf = new Float32Array(frequencyBinCount);\n\n // Get all channel data\n const channels: Float32Array[] = [];\n for (let ch = 0; ch < numChannels; ch++) {\n channels.push(audioBuffer.getChannelData(ch));\n }\n\n for (let frame = 0; frame < frameCount; frame++) {\n const start = offsetSamples + frame * hopSize;\n\n // Mix channels and apply window\n for (let i = 0; i < windowSize; i++) {\n const sampleIdx = start + i;\n let sum = 0;\n for (let ch = 0; ch < numChannels; ch++) {\n sum += sampleIdx < channels[ch].length ? channels[ch][sampleIdx] : 0;\n }\n real[i] = (sum / numChannels) * window[i];\n }\n // Zero-pad the rest\n for (let i = windowSize; i < actualFftSize; i++) {\n real[i] = 0;\n }\n\n fftMagnitudeDb(real, dbBuf);\n data.set(dbBuf, frame * frequencyBinCount);\n }\n\n return {\n fftSize: actualFftSize,\n windowSize,\n frequencyBinCount,\n sampleRate,\n hopSize,\n frameCount,\n data,\n gainDb,\n rangeDb,\n };\n}\n","/**\n * Color maps for spectrogram rendering.\n * Each map is a 256-entry RGB lookup table (768 bytes).\n *\n * Viridis, Magma, Inferno: Perceptually uniform colormaps from matplotlib.\n * By Stéfan van der Walt, Nathaniel Smith, and Eric Firing. Released under CC0.\n * Data from https://github.com/BIDS/colormap\n *\n * Roseus: Perceptually uniform colormap from https://github.com/dofuuz/roseus\n * By dofuuz, licensed under CC0 1.0 Universal.\n */\n\nimport type { ColorMapValue } from '@waveform-playlist/core';\n\n// Pre-computed 256-entry LUT: Uint8Array of length 768 (256 * 3 RGB)\ntype ColorLUT = Uint8Array;\n\nfunction interpolateLUT(stops: number[][]): ColorLUT {\n const lut = new Uint8Array(256 * 3);\n const n = stops.length;\n for (let i = 0; i < 256; i++) {\n const t = i / 255;\n const pos = t * (n - 1);\n const lo = Math.floor(pos);\n const hi = Math.min(lo + 1, n - 1);\n const frac = pos - lo;\n lut[i * 3] = Math.round(stops[lo][0] * (1 - frac) + stops[hi][0] * frac);\n lut[i * 3 + 1] = Math.round(stops[lo][1] * (1 - frac) + stops[hi][1] * frac);\n lut[i * 3 + 2] = Math.round(stops[lo][2] * (1 - frac) + stops[hi][2] * frac);\n }\n return lut;\n}\n\n// prettier-ignore\nconst VIRIDIS_LUT = new Uint8Array([\n 68, 1, 84, 68, 2, 86, 69, 4, 87, 69, 5, 89, 70, 7, 90, 70, 8, 92, 70, 10, 93, 70, 11, 94,\n 71, 13, 96, 71, 14, 97, 71, 16, 99, 71, 17, 100, 71, 19, 101, 72, 20, 103, 72, 22, 104, 72, 23, 105,\n 72, 24, 106, 72, 26, 108, 72, 27, 109, 72, 28, 110, 72, 29, 111, 72, 31, 112, 72, 32, 113, 72, 33, 115,\n 72, 35, 116, 72, 36, 117, 72, 37, 118, 72, 38, 119, 72, 40, 120, 72, 41, 121, 71, 42, 122, 71, 44, 122,\n 71, 45, 123, 71, 46, 124, 71, 47, 125, 70, 48, 126, 70, 50, 126, 70, 51, 127, 70, 52, 128, 69, 53, 129,\n 69, 55, 129, 69, 56, 130, 68, 57, 131, 68, 58, 131, 68, 59, 132, 67, 61, 132, 67, 62, 133, 66, 63, 133,\n 66, 64, 134, 66, 65, 134, 65, 66, 135, 65, 68, 135, 64, 69, 136, 64, 70, 136, 63, 71, 136, 63, 72, 137,\n 62, 73, 137, 62, 74, 137, 62, 76, 138, 61, 77, 138, 61, 78, 138, 60, 79, 138, 60, 80, 139, 59, 81, 139,\n 59, 82, 139, 58, 83, 139, 58, 84, 140, 57, 85, 140, 57, 86, 140, 56, 88, 140, 56, 89, 140, 55, 90, 140,\n 55, 91, 141, 54, 92, 141, 54, 93, 141, 53, 94, 141, 53, 95, 141, 52, 96, 141, 52, 97, 141, 51, 98, 141,\n 51, 99, 141, 50, 100, 142, 50, 101, 142, 49, 102, 142, 49, 103, 142, 49, 104, 142, 48, 105, 142, 48, 106, 142,\n 47, 107, 142, 47, 108, 142, 46, 109, 142, 46, 110, 142, 46, 111, 142, 45, 112, 142, 45, 113, 142, 44, 113, 142,\n 44, 114, 142, 44, 115, 142, 43, 116, 142, 43, 117, 142, 42, 118, 142, 42, 119, 142, 42, 120, 142, 41, 121, 142,\n 41, 122, 142, 41, 123, 142, 40, 124, 142, 40, 125, 142, 39, 126, 142, 39, 127, 142, 39, 128, 142, 38, 129, 142,\n 38, 130, 142, 38, 130, 142, 37, 131, 142, 37, 132, 142, 37, 133, 142, 36, 134, 142, 36, 135, 142, 35, 136, 142,\n 35, 137, 142, 35, 138, 141, 34, 139, 141, 34, 140, 141, 34, 141, 141, 33, 142, 141, 33, 143, 141, 33, 144, 141,\n 33, 145, 140, 32, 146, 140, 32, 146, 140, 32, 147, 140, 31, 148, 140, 31, 149, 139, 31, 150, 139, 31, 151, 139,\n 31, 152, 139, 31, 153, 138, 31, 154, 138, 30, 155, 138, 30, 156, 137, 30, 157, 137, 31, 158, 137, 31, 159, 136,\n 31, 160, 136, 31, 161, 136, 31, 161, 135, 31, 162, 135, 32, 163, 134, 32, 164, 134, 33, 165, 133, 33, 166, 133,\n 34, 167, 133, 34, 168, 132, 35, 169, 131, 36, 170, 131, 37, 171, 130, 37, 172, 130, 38, 173, 129, 39, 173, 129,\n 40, 174, 128, 41, 175, 127, 42, 176, 127, 44, 177, 126, 45, 178, 125, 46, 179, 124, 47, 180, 124, 49, 181, 123,\n 50, 182, 122, 52, 182, 121, 53, 183, 121, 55, 184, 120, 56, 185, 119, 58, 186, 118, 59, 187, 117, 61, 188, 116,\n 63, 188, 115, 64, 189, 114, 66, 190, 113, 68, 191, 112, 70, 192, 111, 72, 193, 110, 74, 193, 109, 76, 194, 108,\n 78, 195, 107, 80, 196, 106, 82, 197, 105, 84, 197, 104, 86, 198, 103, 88, 199, 101, 90, 200, 100, 92, 200, 99,\n 94, 201, 98, 96, 202, 96, 99, 203, 95, 101, 203, 94, 103, 204, 92, 105, 205, 91, 108, 205, 90, 110, 206, 88,\n 112, 207, 87, 115, 208, 86, 117, 208, 84, 119, 209, 83, 122, 209, 81, 124, 210, 80, 127, 211, 78, 129, 211, 77,\n 132, 212, 75, 134, 213, 73, 137, 213, 72, 139, 214, 70, 142, 214, 69, 144, 215, 67, 147, 215, 65, 149, 216, 64,\n 152, 216, 62, 155, 217, 60, 157, 217, 59, 160, 218, 57, 162, 218, 55, 165, 219, 54, 168, 219, 52, 170, 220, 50,\n 173, 220, 48, 176, 221, 47, 178, 221, 45, 181, 222, 43, 184, 222, 41, 186, 222, 40, 189, 223, 38, 192, 223, 37,\n 194, 223, 35, 197, 224, 33, 200, 224, 32, 202, 225, 31, 205, 225, 29, 208, 225, 28, 210, 226, 27, 213, 226, 26,\n 216, 226, 25, 218, 227, 25, 221, 227, 24, 223, 227, 24, 226, 228, 24, 229, 228, 25, 231, 228, 25, 234, 229, 26,\n 236, 229, 27, 239, 229, 28, 241, 229, 29, 244, 230, 30, 246, 230, 32, 248, 230, 33, 251, 231, 35, 253, 231, 37,\n]);\n\n// prettier-ignore\nconst MAGMA_LUT = new Uint8Array([\n 0, 0, 4, 1, 0, 5, 1, 1, 6, 1, 1, 8, 2, 1, 9, 2, 2, 11, 2, 2, 13, 3, 3, 15,\n 3, 3, 18, 4, 4, 20, 5, 4, 22, 6, 5, 24, 6, 5, 26, 7, 6, 28, 8, 7, 30, 9, 7, 32,\n 10, 8, 34, 11, 9, 36, 12, 9, 38, 13, 10, 41, 14, 11, 43, 16, 11, 45, 17, 12, 47, 18, 13, 49,\n 19, 13, 52, 20, 14, 54, 21, 14, 56, 22, 15, 59, 24, 15, 61, 25, 16, 63, 26, 16, 66, 28, 16, 68,\n 29, 17, 71, 30, 17, 73, 32, 17, 75, 33, 17, 78, 34, 17, 80, 36, 18, 83, 37, 18, 85, 39, 18, 88,\n 41, 17, 90, 42, 17, 92, 44, 17, 95, 45, 17, 97, 47, 17, 99, 49, 17, 101, 51, 16, 103, 52, 16, 105,\n 54, 16, 107, 56, 16, 108, 57, 15, 110, 59, 15, 112, 61, 15, 113, 63, 15, 114, 64, 15, 116, 66, 15, 117,\n 68, 15, 118, 69, 16, 119, 71, 16, 120, 73, 16, 120, 74, 16, 121, 76, 17, 122, 78, 17, 123, 79, 18, 123,\n 81, 18, 124, 82, 19, 124, 84, 19, 125, 86, 20, 125, 87, 21, 126, 89, 21, 126, 90, 22, 126, 92, 22, 127,\n 93, 23, 127, 95, 24, 127, 96, 24, 128, 98, 25, 128, 100, 26, 128, 101, 26, 128, 103, 27, 128, 104, 28, 129,\n 106, 28, 129, 107, 29, 129, 109, 29, 129, 110, 30, 129, 112, 31, 129, 114, 31, 129, 115, 32, 129, 117, 33, 129,\n 118, 33, 129, 120, 34, 129, 121, 34, 130, 123, 35, 130, 124, 35, 130, 126, 36, 130, 128, 37, 130, 129, 37, 129,\n 131, 38, 129, 132, 38, 129, 134, 39, 129, 136, 39, 129, 137, 40, 129, 139, 41, 129, 140, 41, 129, 142, 42, 129,\n 144, 42, 129, 145, 43, 129, 147, 43, 128, 148, 44, 128, 150, 44, 128, 152, 45, 128, 153, 45, 128, 155, 46, 127,\n 156, 46, 127, 158, 47, 127, 160, 47, 127, 161, 48, 126, 163, 48, 126, 165, 49, 126, 166, 49, 125, 168, 50, 125,\n 170, 51, 125, 171, 51, 124, 173, 52, 124, 174, 52, 123, 176, 53, 123, 178, 53, 123, 179, 54, 122, 181, 54, 122,\n 183, 55, 121, 184, 55, 121, 186, 56, 120, 188, 57, 120, 189, 57, 119, 191, 58, 119, 192, 58, 118, 194, 59, 117,\n 196, 60, 117, 197, 60, 116, 199, 61, 115, 200, 62, 115, 202, 62, 114, 204, 63, 113, 205, 64, 113, 207, 64, 112,\n 208, 65, 111, 210, 66, 111, 211, 67, 110, 213, 68, 109, 214, 69, 108, 216, 69, 108, 217, 70, 107, 219, 71, 106,\n 220, 72, 105, 222, 73, 104, 223, 74, 104, 224, 76, 103, 226, 77, 102, 227, 78, 101, 228, 79, 100, 229, 80, 100,\n 231, 82, 99, 232, 83, 98, 233, 84, 98, 234, 86, 97, 235, 87, 96, 236, 88, 96, 237, 90, 95, 238, 91, 94,\n 239, 93, 94, 240, 95, 94, 241, 96, 93, 242, 98, 93, 242, 100, 92, 243, 101, 92, 244, 103, 92, 244, 105, 92,\n 245, 107, 92, 246, 108, 92, 246, 110, 92, 247, 112, 92, 247, 114, 92, 248, 116, 92, 248, 118, 92, 249, 120, 93,\n 249, 121, 93, 249, 123, 93, 250, 125, 94, 250, 127, 94, 250, 129, 95, 251, 131, 95, 251, 133, 96, 251, 135, 97,\n 252, 137, 97, 252, 138, 98, 252, 140, 99, 252, 142, 100, 252, 144, 101, 253, 146, 102, 253, 148, 103, 253, 150, 104,\n 253, 152, 105, 253, 154, 106, 253, 155, 107, 254, 157, 108, 254, 159, 109, 254, 161, 110, 254, 163, 111, 254, 165, 113,\n 254, 167, 114, 254, 169, 115, 254, 170, 116, 254, 172, 118, 254, 174, 119, 254, 176, 120, 254, 178, 122, 254, 180, 123,\n 254, 182, 124, 254, 183, 126, 254, 185, 127, 254, 187, 129, 254, 189, 130, 254, 191, 132, 254, 193, 133, 254, 194, 135,\n 254, 196, 136, 254, 198, 138, 254, 200, 140, 254, 202, 141, 254, 204, 143, 254, 205, 144, 254, 207, 146, 254, 209, 148,\n 254, 211, 149, 254, 213, 151, 254, 215, 153, 254, 216, 154, 253, 218, 156, 253, 220, 158, 253, 222, 160, 253, 224, 161,\n 253, 226, 163, 253, 227, 165, 253, 229, 167, 253, 231, 169, 253, 233, 170, 253, 235, 172, 252, 236, 174, 252, 238, 176,\n 252, 240, 178, 252, 242, 180, 252, 244, 182, 252, 246, 184, 252, 247, 185, 252, 249, 187, 252, 251, 189, 252, 253, 191,\n]);\n\n// prettier-ignore\nconst INFERNO_LUT = new Uint8Array([\n 0, 0, 4, 1, 0, 5, 1, 1, 6, 1, 1, 8, 2, 1, 10, 2, 2, 12, 2, 2, 14, 3, 2, 16,\n 4, 3, 18, 4, 3, 20, 5, 4, 23, 6, 4, 25, 7, 5, 27, 8, 5, 29, 9, 6, 31, 10, 7, 34,\n 11, 7, 36, 12, 8, 38, 13, 8, 41, 14, 9, 43, 16, 9, 45, 17, 10, 48, 18, 10, 50, 20, 11, 52,\n 21, 11, 55, 22, 11, 57, 24, 12, 60, 25, 12, 62, 27, 12, 65, 28, 12, 67, 30, 12, 69, 31, 12, 72,\n 33, 12, 74, 35, 12, 76, 36, 12, 79, 38, 12, 81, 40, 11, 83, 41, 11, 85, 43, 11, 87, 45, 11, 89,\n 47, 10, 91, 49, 10, 92, 50, 10, 94, 52, 10, 95, 54, 9, 97, 56, 9, 98, 57, 9, 99, 59, 9, 100,\n 61, 9, 101, 62, 9, 102, 64, 10, 103, 66, 10, 104, 68, 10, 104, 69, 10, 105, 71, 11, 106, 73, 11, 106,\n 74, 12, 107, 76, 12, 107, 77, 13, 108, 79, 13, 108, 81, 14, 108, 82, 14, 109, 84, 15, 109, 85, 15, 109,\n 87, 16, 110, 89, 16, 110, 90, 17, 110, 92, 18, 110, 93, 18, 110, 95, 19, 110, 97, 19, 110, 98, 20, 110,\n 100, 21, 110, 101, 21, 110, 103, 22, 110, 105, 22, 110, 106, 23, 110, 108, 24, 110, 109, 24, 110, 111, 25, 110,\n 113, 25, 110, 114, 26, 110, 116, 26, 110, 117, 27, 110, 119, 28, 109, 120, 28, 109, 122, 29, 109, 124, 29, 109,\n 125, 30, 109, 127, 30, 108, 128, 31, 108, 130, 32, 108, 132, 32, 107, 133, 33, 107, 135, 33, 107, 136, 34, 106,\n 138, 34, 106, 140, 35, 105, 141, 35, 105, 143, 36, 105, 144, 37, 104, 146, 37, 104, 147, 38, 103, 149, 38, 103,\n 151, 39, 102, 152, 39, 102, 154, 40, 101, 155, 41, 100, 157, 41, 100, 159, 42, 99, 160, 42, 99, 162, 43, 98,\n 163, 44, 97, 165, 44, 96, 166, 45, 96, 168, 46, 95, 169, 46, 94, 171, 47, 94, 173, 48, 93, 174, 48, 92,\n 176, 49, 91, 177, 50, 90, 179, 50, 90, 180, 51, 89, 182, 52, 88, 183, 53, 87, 185, 53, 86, 186, 54, 85,\n 188, 55, 84, 189, 56, 83, 191, 57, 82, 192, 58, 81, 193, 58, 80, 195, 59, 79, 196, 60, 78, 198, 61, 77,\n 199, 62, 76, 200, 63, 75, 202, 64, 74, 203, 65, 73, 204, 66, 72, 206, 67, 71, 207, 68, 70, 208, 69, 69,\n 210, 70, 68, 211, 71, 67, 212, 72, 66, 213, 74, 65, 215, 75, 63, 216, 76, 62, 217, 77, 61, 218, 78, 60,\n 219, 80, 59, 221, 81, 58, 222, 82, 56, 223, 83, 55, 224, 85, 54, 225, 86, 53, 226, 87, 52, 227, 89, 51,\n 228, 90, 49, 229, 92, 48, 230, 93, 47, 231, 94, 46, 232, 96, 45, 233, 97, 43, 234, 99, 42, 235, 100, 41,\n 235, 102, 40, 236, 103, 38, 237, 105, 37, 238, 106, 36, 239, 108, 35, 239, 110, 33, 240, 111, 32, 241, 113, 31,\n 241, 115, 29, 242, 116, 28, 243, 118, 27, 243, 120, 25, 244, 121, 24, 245, 123, 23, 245, 125, 21, 246, 126, 20,\n 246, 128, 19, 247, 130, 18, 247, 132, 16, 248, 133, 15, 248, 135, 14, 248, 137, 12, 249, 139, 11, 249, 140, 10,\n 249, 142, 9, 250, 144, 8, 250, 146, 7, 250, 148, 7, 251, 150, 6, 251, 151, 6, 251, 153, 6, 251, 155, 6,\n 251, 157, 7, 252, 159, 7, 252, 161, 8, 252, 163, 9, 252, 165, 10, 252, 166, 12, 252, 168, 13, 252, 170, 15,\n 252, 172, 17, 252, 174, 18, 252, 176, 20, 252, 178, 22, 252, 180, 24, 251, 182, 26, 251, 184, 29, 251, 186, 31,\n 251, 188, 33, 251, 190, 35, 250, 192, 38, 250, 194, 40, 250, 196, 42, 250, 198, 45, 249, 199, 47, 249, 201, 50,\n 249, 203, 53, 248, 205, 55, 248, 207, 58, 247, 209, 61, 247, 211, 64, 246, 213, 67, 246, 215, 70, 245, 217, 73,\n 245, 219, 76, 244, 221, 79, 244, 223, 83, 244, 225, 86, 243, 227, 90, 243, 229, 93, 242, 230, 97, 242, 232, 101,\n 242, 234, 105, 241, 236, 109, 241, 237, 113, 241, 239, 117, 241, 241, 121, 242, 242, 125, 242, 244, 130, 243, 245, 134,\n 243, 246, 138, 244, 248, 142, 245, 249, 146, 246, 250, 150, 248, 251, 154, 249, 252, 157, 250, 253, 161, 252, 255, 164,\n]);\n\n// prettier-ignore\nconst ROSEUS_LUT = new Uint8Array([\n 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 3, 3, 2, 3, 4, 2, 4, 5, 2, 5, 6, 3, 6, 7,\n 3, 7, 8, 3, 8, 10, 3, 9, 12, 3, 10, 14, 3, 12, 16, 3, 13, 17, 3, 14, 19, 2, 15, 21,\n 2, 16, 23, 2, 17, 25, 2, 18, 27, 2, 19, 30, 1, 20, 32, 1, 21, 34, 1, 22, 36, 1, 23, 38,\n 1, 24, 40, 0, 25, 43, 0, 26, 45, 0, 27, 47, 0, 27, 50, 0, 28, 52, 0, 29, 54, 0, 30, 57,\n 0, 30, 59, 1, 31, 62, 1, 32, 64, 1, 32, 67, 2, 33, 69, 3, 33, 72, 4, 34, 74, 5, 35, 77,\n 6, 35, 79, 8, 35, 82, 9, 36, 84, 11, 36, 86, 13, 37, 89, 15, 37, 91, 17, 37, 94, 19, 37, 96,\n 21, 38, 99, 23, 38, 101, 25, 38, 104, 27, 38, 106, 29, 38, 108, 31, 38, 111, 33, 38, 113, 35, 38, 115,\n 38, 38, 118, 40, 38, 120, 42, 38, 122, 44, 38, 124, 46, 38, 126, 49, 38, 128, 51, 38, 130, 53, 37, 132,\n 55, 37, 134, 58, 37, 136, 60, 36, 138, 62, 36, 139, 65, 36, 141, 67, 35, 143, 69, 35, 144, 72, 35, 146,\n 74, 34, 147, 76, 34, 149, 79, 33, 150, 81, 33, 151, 84, 32, 152, 86, 32, 153, 88, 31, 154, 91, 31, 155,\n 93, 30, 156, 95, 29, 157, 98, 29, 158, 100, 28, 159, 103, 28, 159, 105, 27, 160, 107, 27, 160, 110, 26, 161,\n 112, 26, 161, 114, 25, 161, 117, 25, 162, 119, 24, 162, 121, 24, 162, 124, 23, 162, 126, 23, 162, 128, 23, 162,\n 131, 22, 161, 133, 22, 161, 135, 22, 161, 137, 22, 161, 140, 22, 160, 142, 22, 160, 144, 22, 159, 146, 22, 159,\n 148, 22, 158, 150, 22, 157, 153, 22, 157, 155, 23, 156, 157, 23, 155, 159, 23, 154, 161, 24, 153, 163, 24, 152,\n 165, 25, 151, 167, 26, 150, 169, 26, 149, 171, 27, 148, 173, 28, 147, 175, 29, 146, 177, 29, 145, 179, 30, 144,\n 181, 31, 142, 183, 32, 141, 184, 33, 140, 186, 34, 139, 188, 35, 137, 190, 36, 136, 192, 37, 135, 193, 39, 133,\n 195, 40, 132, 197, 41, 130, 198, 42, 129, 200, 43, 128, 202, 45, 126, 203, 46, 125, 205, 47, 123, 206, 48, 122,\n 208, 50, 120, 209, 51, 119, 211, 52, 117, 212, 54, 116, 214, 55, 114, 215, 57, 113, 217, 58, 111, 218, 60, 110,\n 219, 61, 109, 221, 63, 107, 222, 64, 106, 223, 66, 104, 225, 67, 103, 226, 69, 101, 227, 70, 100, 228, 72, 99,\n 229, 73, 97, 230, 75, 96, 231, 77, 94, 233, 78, 93, 234, 80, 92, 235, 82, 91, 236, 83, 89, 237, 85, 88,\n 237, 87, 87, 238, 89, 86, 239, 90, 84, 240, 92, 83, 241, 94, 82, 242, 96, 81, 242, 97, 80, 243, 99, 79,\n 244, 101, 78, 245, 103, 77, 245, 105, 76, 246, 107, 75, 246, 108, 74, 247, 110, 74, 248, 112, 73, 248, 114, 72,\n 248, 116, 72, 249, 118, 71, 249, 120, 71, 250, 122, 70, 250, 124, 70, 250, 126, 70, 251, 128, 70, 251, 130, 69,\n 251, 132, 70, 251, 134, 70, 251, 136, 70, 252, 138, 70, 252, 140, 70, 252, 142, 71, 252, 144, 72, 252, 146, 72,\n 252, 148, 73, 252, 150, 74, 251, 152, 75, 251, 154, 76, 251, 156, 77, 251, 158, 78, 251, 160, 80, 251, 162, 81,\n 250, 164, 83, 250, 166, 85, 250, 168, 87, 249, 170, 88, 249, 172, 90, 248, 174, 93, 248, 176, 95, 248, 178, 97,\n 247, 180, 99, 247, 182, 102, 246, 184, 104, 246, 186, 107, 245, 188, 110, 244, 190, 112, 244, 192, 115, 243, 194, 118,\n 243, 195, 121, 242, 197, 124, 242, 199, 127, 241, 201, 131, 240, 203, 134, 240, 205, 137, 239, 207, 140, 239, 208, 144,\n 238, 210, 147, 238, 212, 151, 237, 213, 154, 237, 215, 158, 236, 217, 161, 236, 218, 165, 236, 220, 169, 236, 222, 172,\n 235, 223, 176, 235, 225, 180, 235, 226, 183, 235, 228, 187, 235, 229, 191, 235, 230, 194, 236, 232, 198, 236, 233, 201,\n 236, 234, 205, 237, 236, 208, 237, 237, 212, 238, 238, 215, 239, 239, 219, 240, 240, 222, 241, 242, 225, 242, 243, 228,\n 243, 244, 231, 244, 245, 234, 246, 246, 237, 247, 247, 240, 249, 248, 242, 251, 249, 245, 253, 250, 247, 254, 251, 249,\n]);\n\nconst lutCache = new Map<string, ColorLUT>();\n\nfunction grayscaleLUT(): ColorLUT {\n let lut = lutCache.get('grayscale');\n if (!lut) {\n lut = new Uint8Array(256 * 3);\n for (let i = 0; i < 256; i++) {\n lut[i * 3] = lut[i * 3 + 1] = lut[i * 3 + 2] = i;\n }\n lutCache.set('grayscale', lut);\n }\n return lut;\n}\n\nfunction igrayLUT(): ColorLUT {\n let lut = lutCache.get('igray');\n if (!lut) {\n lut = new Uint8Array(256 * 3);\n for (let i = 0; i < 256; i++) {\n const v = 255 - i;\n lut[i * 3] = lut[i * 3 + 1] = lut[i * 3 + 2] = v;\n }\n lutCache.set('igray', lut);\n }\n return lut;\n}\n\n/**\n * Get a 256-entry RGB LUT for the given color map.\n */\nexport function getColorMap(value: ColorMapValue): ColorLUT {\n if (Array.isArray(value)) {\n return interpolateLUT(value);\n }\n\n switch (value) {\n case 'viridis':\n return VIRIDIS_LUT;\n case 'magma':\n return MAGMA_LUT;\n case 'inferno':\n return INFERNO_LUT;\n case 'roseus':\n return ROSEUS_LUT;\n case 'grayscale':\n return grayscaleLUT();\n case 'igray':\n return igrayLUT();\n default:\n return VIRIDIS_LUT;\n }\n}\n","/**\n * Frequency scale mapping functions.\n * Each maps a frequency (Hz) to a normalized position [0, 1].\n */\n\nfunction linearScale(f: number, minF: number, maxF: number): number {\n if (maxF === minF) return 0;\n return (f - minF) / (maxF - minF);\n}\n\nfunction logarithmicScale(f: number, minF: number, maxF: number): number {\n const logMin = Math.log2(Math.max(minF, 1));\n const logMax = Math.log2(maxF);\n if (logMax === logMin) return 0;\n return (Math.log2(Math.max(f, 1)) - logMin) / (logMax - logMin);\n}\n\nfunction hzToMel(f: number): number {\n return 2595 * Math.log10(1 + f / 700);\n}\n\nfunction melScale(f: number, minF: number, maxF: number): number {\n const melMin = hzToMel(minF);\n const melMax = hzToMel(maxF);\n if (melMax === melMin) return 0;\n return (hzToMel(f) - melMin) / (melMax - melMin);\n}\n\nfunction hzToBark(f: number): number {\n return 13 * Math.atan(0.00076 * f) + 3.5 * Math.atan((f / 7500) ** 2);\n}\n\nfunction barkScale(f: number, minF: number, maxF: number): number {\n const barkMin = hzToBark(minF);\n const barkMax = hzToBark(maxF);\n if (barkMax === barkMin) return 0;\n return (hzToBark(f) - barkMin) / (barkMax - barkMin);\n}\n\nfunction hzToErb(f: number): number {\n return 21.4 * Math.log10(1 + 0.00437 * f);\n}\n\nfunction erbScale(f: number, minF: number, maxF: number): number {\n const erbMin = hzToErb(minF);\n const erbMax = hzToErb(maxF);\n if (erbMax === erbMin) return 0;\n return (hzToErb(f) - erbMin) / (erbMax - erbMin);\n}\n\nexport type FrequencyScaleName = 'linear' | 'logarithmic' | 'mel' | 'bark' | 'erb';\n\n/**\n * Returns a mapping function: (frequencyHz, minFrequency, maxFrequency) → [0, 1]\n */\nexport function getFrequencyScale(\n name: FrequencyScaleName\n): (f: number, minF: number, maxF: number) => number {\n switch (name) {\n case 'logarithmic':\n return logarithmicScale;\n case 'mel':\n return melScale;\n case 'bark':\n return barkScale;\n case 'erb':\n return erbScale;\n case 'linear':\n return linearScale;\n default:\n console.warn(`[spectrogram] Unknown frequency scale \"${name}\", falling back to linear`);\n return linearScale;\n }\n}\n","import React from 'react';\nimport styled from 'styled-components';\nimport type { RenderMode } from '@waveform-playlist/core';\nimport type { TrackMenuItem } from './types';\n\nconst SectionLabel = styled.div`\n font-size: 0.65rem;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.05em;\n opacity: 0.5;\n margin-bottom: 0.25rem;\n`;\n\nconst RadioLabel = styled.label`\n display: flex;\n align-items: center;\n gap: 0.4rem;\n padding: 0.2rem 0;\n font-size: 0.8rem;\n cursor: pointer;\n\n &:hover {\n opacity: 0.8;\n }\n`;\n\nconst SettingsButton = styled.button`\n background: none;\n border: none;\n color: inherit;\n cursor: pointer;\n font-size: 0.8rem;\n padding: 0.35rem 0.75rem;\n width: 100%;\n text-align: left;\n\n &:hover {\n background: rgba(128, 128, 128, 0.15);\n }\n`;\n\nconst DropdownSection = styled.div`\n padding: 0.25rem 0.75rem;\n`;\n\nconst RENDER_MODES: { value: RenderMode; label: string }[] = [\n { value: 'waveform', label: 'Waveform' },\n { value: 'spectrogram', label: 'Spectrogram' },\n { value: 'both', label: 'Both' },\n];\n\nexport interface SpectrogramMenuItemsProps {\n renderMode: RenderMode;\n onRenderModeChange: (mode: RenderMode) => void;\n onOpenSettings: () => void;\n onClose?: () => void;\n}\n\n/**\n * Returns TrackMenuItem[] for the spectrogram display mode radios and settings button.\n */\nexport function SpectrogramMenuItems({\n renderMode,\n onRenderModeChange,\n onOpenSettings,\n onClose,\n}: SpectrogramMenuItemsProps): TrackMenuItem[] {\n return [\n {\n id: 'spectrogram-display',\n label: 'Display',\n content: (\n <DropdownSection>\n <SectionLabel>Display</SectionLabel>\n {RENDER_MODES.map(({ value, label }) => (\n <RadioLabel key={value}>\n <input\n type=\"radio\"\n name=\"render-mode\"\n checked={renderMode === value}\n onChange={() => {\n onRenderModeChange(value);\n onClose?.();\n }}\n />\n {label}\n </RadioLabel>\n ))}\n </DropdownSection>\n ),\n },\n {\n id: 'spectrogram-settings',\n content: (\n <SettingsButton\n onClick={(e) => {\n e.stopPropagation();\n onClose?.();\n onOpenSettings();\n }}\n onMouseDown={(e) => e.stopPropagation()}\n >\n Spectrogram Settings...\n </SettingsButton>\n ),\n },\n ];\n}\n","import React, { useRef, useEffect, useState } from 'react';\nimport styled from 'styled-components';\nimport type {\n SpectrogramConfig,\n ColorMapValue,\n ColorMapName,\n FFTSize,\n} from '@waveform-playlist/core';\n\nexport interface SpectrogramSettingsModalProps {\n open: boolean;\n onClose: () => void;\n config: SpectrogramConfig;\n colorMap: ColorMapValue;\n onApply: (config: SpectrogramConfig, colorMap: ColorMapValue) => void;\n}\n\nconst StyledDialog = styled.dialog`\n border: 1px solid rgba(128, 128, 128, 0.4);\n border-radius: 8px;\n padding: 1.5rem;\n background: ${(p) => p.theme.timescaleBackgroundColor ?? '#222'};\n color: ${(p) => p.theme.textColor ?? 'inherit'};\n min-width: 380px;\n max-width: 500px;\n\n &::backdrop {\n background: rgba(0, 0, 0, 0.5);\n }\n`;\n\nconst Title = styled.h3`\n margin: 0 0 1rem;\n font-size: 1rem;\n`;\n\nconst FormGrid = styled.div`\n display: grid;\n grid-template-columns: 1fr 1fr;\n gap: 0.75rem;\n`;\n\nconst Field = styled.div<{ $span?: boolean }>`\n display: flex;\n flex-direction: column;\n gap: 0.2rem;\n grid-column: ${(p) => (p.$span ? '1 / -1' : 'auto')};\n`;\n\nconst Label = styled.label`\n font-size: 0.7rem;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.05em;\n opacity: 0.6;\n`;\n\nconst Select = styled.select`\n padding: 0.3rem 0.4rem;\n border: 1px solid rgba(128, 128, 128, 0.4);\n border-radius: 4px;\n background: rgba(128, 128, 128, 0.15);\n color: inherit;\n font-size: 0.85rem;\n`;\n\nconst NumberInput = styled.input`\n padding: 0.3rem 0.4rem;\n border: 1px solid rgba(128, 128, 128, 0.4);\n border-radius: 4px;\n background: rgba(128, 128, 128, 0.15);\n color: inherit;\n font-size: 0.85rem;\n width: 100%;\n box-sizing: border-box;\n`;\n\nconst CheckboxLabel = styled.label`\n display: flex;\n align-items: center;\n gap: 0.4rem;\n font-size: 0.85rem;\n cursor: pointer;\n`;\n\nconst ButtonRow = styled.div`\n display: flex;\n justify-content: flex-end;\n gap: 0.5rem;\n margin-top: 1.25rem;\n`;\n\nconst ModalButton = styled.button<{ $primary?: boolean }>`\n padding: 0.4rem 1rem;\n border: 1px solid rgba(128, 128, 128, 0.4);\n border-radius: 4px;\n cursor: pointer;\n font-size: 0.85rem;\n background: ${(p) => (p.$primary ? 'var(--ifm-color-primary, #4a9)' : 'transparent')};\n color: ${(p) => (p.$primary ? '#fff' : 'inherit')};\n\n &:hover {\n opacity: 0.85;\n }\n`;\n\nconst FFT_SIZES = [256, 512, 1024, 2048, 4096, 8192];\nconst WINDOW_FUNCTIONS = [\n 'hann',\n 'hamming',\n 'blackman',\n 'blackman-harris',\n 'bartlett',\n 'rectangular',\n] as const;\nconst FREQ_SCALES = ['linear', 'logarithmic', 'mel', 'bark', 'erb'] as const;\nconst COLOR_MAPS: ColorMapName[] = ['viridis', 'magma', 'inferno', 'grayscale', 'igray', 'roseus'];\n\nexport const SpectrogramSettingsModal: React.FC<SpectrogramSettingsModalProps> = ({\n open,\n onClose,\n config,\n colorMap,\n onApply,\n}) => {\n const dialogRef = useRef<HTMLDialogElement>(null);\n\n // Local form state\n const [fftSize, setFftSize] = useState(config.fftSize ?? 2048);\n const [windowFn, setWindowFn] = useState(config.windowFunction ?? 'hann');\n const [freqScale, setFreqScale] = useState(config.frequencyScale ?? 'mel');\n const [localColorMap, setLocalColorMap] = useState<ColorMapName>(\n typeof colorMap === 'string' ? colorMap : 'viridis'\n );\n const [minFreq, setMinFreq] = useState(config.minFrequency ?? 0);\n const [maxFreq, setMaxFreq] = useState(config.maxFrequency ?? 20000);\n const [gainDb, setGainDb] = useState(config.gainDb ?? 20);\n const [rangeDb, setRangeDb] = useState(config.rangeDb ?? 80);\n const [zeroPadding, setZeroPadding] = useState(config.zeroPaddingFactor ?? 2);\n const [hopSize, setHopSize] = useState(\n config.hopSize ?? Math.floor((config.fftSize ?? 2048) / 4)\n );\n const [showLabels, setShowLabels] = useState(config.labels ?? false);\n\n // Sync local state when props change\n useEffect(() => {\n setFftSize(config.fftSize ?? 2048);\n setWindowFn(config.windowFunction ?? 'hann');\n setFreqScale(config.frequencyScale ?? 'mel');\n setLocalColorMap(typeof colorMap === 'string' ? colorMap : 'viridis');\n setMinFreq(config.minFrequency ?? 0);\n setMaxFreq(config.maxFrequency ?? 20000);\n setGainDb(config.gainDb ?? 20);\n setRangeDb(config.rangeDb ?? 80);\n setZeroPadding(config.zeroPaddingFactor ?? 2);\n setHopSize(config.hopSize ?? Math.floor((config.fftSize ?? 2048) / 4));\n setShowLabels(config.labels ?? false);\n }, [config, colorMap]);\n\n // Open/close dialog + handle native close (Escape key)\n useEffect(() => {\n const dialog = dialogRef.current;\n if (!dialog) return;\n\n if (open && !dialog.open) {\n dialog.showModal();\n } else if (!open && dialog.open) {\n dialog.close();\n }\n\n const handleClose = () => {\n // Only call onClose if dialog was open (avoids double-fire)\n if (open) {\n onClose();\n }\n };\n dialog.addEventListener('close', handleClose);\n return () => dialog.removeEventListener('close', handleClose);\n }, [open, onClose]);\n\n const handleApply = () => {\n onApply(\n {\n fftSize,\n windowFunction: windowFn as SpectrogramConfig['windowFunction'],\n frequencyScale: freqScale as SpectrogramConfig['frequencyScale'],\n minFrequency: minFreq,\n maxFrequency: maxFreq,\n gainDb,\n rangeDb,\n zeroPaddingFactor: zeroPadding,\n hopSize,\n labels: showLabels,\n },\n localColorMap\n );\n onClose();\n };\n\n return (\n <StyledDialog ref={dialogRef}>\n <Title>Spectrogram Settings</Title>\n <FormGrid>\n <Field>\n <Label>FFT Size</Label>\n <Select\n value={fftSize}\n onChange={(e) => {\n const v = Number(e.target.value) as FFTSize;\n setFftSize(v);\n setHopSize(Math.floor(v / 4));\n }}\n >\n {FFT_SIZES.map((s) => (\n <option key={s} value={s}>\n {s}\n </option>\n ))}\n </Select>\n </Field>\n\n <Field>\n <Label>Hop Size</Label>\n <Select value={hopSize} onChange={(e) => setHopSize(Number(e.target.value))}>\n {[\n { label: `${fftSize} (no overlap)`, value: fftSize },\n { label: `${Math.floor(fftSize / 2)} (50%)`, value: Math.floor(fftSize / 2) },\n { label: `${Math.floor(fftSize / 4)} (75%)`, value: Math.floor(fftSize / 4) },\n { label: `${Math.floor(fftSize / 8)} (87.5%)`, value: Math.floor(fftSize / 8) },\n ].map((o) => (\n <option key={o.value} value={o.value}>\n {o.label}\n </option>\n ))}\n </Select>\n </Field>\n\n <Field>\n <Label>Zero Padding</Label>\n <Select value={zeroPadding} onChange={(e) => setZeroPadding(Number(e.target.value))}>\n {[1, 2, 4, 8, 16].map((v) => (\n <option key={v} value={v}>\n {v}\n </option>\n ))}\n </Select>\n </Field>\n\n <Field>\n <Label>Window Function</Label>\n <Select value={windowFn} onChange={(e) => setWindowFn(e.target.value as typeof windowFn)}>\n {WINDOW_FUNCTIONS.map((w) => (\n <option key={w} value={w}>\n {w}\n </option>\n ))}\n </Select>\n </Field>\n\n <Field>\n <Label>Frequency Scale</Label>\n <Select\n value={freqScale}\n onChange={(e) => setFreqScale(e.target.value as typeof freqScale)}\n >\n {FREQ_SCALES.map((s) => (\n <option key={s} value={s}>\n {s}\n </option>\n ))}\n </Select>\n </Field>\n\n <Field>\n <Label>Color Map</Label>\n <Select\n value={localColorMap}\n onChange={(e) => setLocalColorMap(e.target.value as ColorMapName)}\n >\n {COLOR_MAPS.map((c) => (\n <option key={c} value={c}>\n {c}\n </option>\n ))}\n </Select>\n </Field>\n\n <Field>\n <Label>Min Frequency (Hz)</Label>\n <NumberInput\n type=\"number\"\n min={0}\n max={5000}\n step={50}\n value={minFreq}\n onChange={(e) => setMinFreq(Number(e.target.value))}\n />\n </Field>\n\n <Field>\n <Label>Max Frequency (Hz)</Label>\n <NumberInput\n type=\"number\"\n min={1000}\n max={22050}\n step={50}\n value={maxFreq}\n onChange={(e) => setMaxFreq(Number(e.target.value))}\n />\n </Field>\n\n <Field>\n <Label>Range (dB)</Label>\n <NumberInput\n type=\"number\"\n min={1}\n max={120}\n step={1}\n value={rangeDb}\n onChange={(e) => setRangeDb(Number(e.target.value))}\n />\n </Field>\n\n <Field>\n <Label>Gain (dB)</Label>\n <NumberInput\n type=\"number\"\n min={-20}\n max={60}\n step={1}\n value={gainDb}\n onChange={(e) => setGainDb(Number(e.target.value))}\n />\n </Field>\n\n <Field $span>\n <CheckboxLabel>\n <input\n type=\"checkbox\"\n checked={showLabels}\n onChange={(e) => setShowLabels(e.target.checked)}\n />\n Show Frequency Labels\n </CheckboxLabel>\n </Field>\n </FormGrid>\n\n <ButtonRow>\n <ModalButton onClick={onClose}>Cancel</ModalButton>\n <ModalButton $primary onClick={handleApply}>\n Apply\n </ModalButton>\n </ButtonRow>\n </StyledDialog>\n );\n};\n","import type { SpectrogramConfig } from '@waveform-playlist/core';\n\n/**\n * Error thrown when a spectrogram computation is aborted due to a generation change.\n * Use `instanceof SpectrogramAbortError` instead of string matching on error messages.\n */\nexport class SpectrogramAbortError extends Error {\n constructor() {\n super('aborted');\n this.name = 'SpectrogramAbortError';\n }\n}\n\nexport interface SpectrogramWorkerFFTParams {\n clipId: string;\n channelDataArrays: Float32Array[];\n config: SpectrogramConfig;\n sampleRate: number;\n offsetSamples: number;\n durationSamples: number;\n mono: boolean;\n sampleRange?: { start: number; end: number };\n /** If set, compute only this channel index (used by worker pool). */\n channelFilter?: number;\n}\n\nexport interface SpectrogramWorkerRenderChunksParams {\n cacheKey: string;\n canvasIds: string[];\n canvasWidths: number[];\n globalPixelOffsets: number[];\n canvasHeight: number;\n devicePixelRatio: number;\n samplesPerPixel: number;\n colorLUT: Uint8Array;\n frequencyScale: string;\n minFrequency: number;\n maxFrequency: number;\n gainDb: number;\n rangeDb: number;\n channelIndex: number;\n}\n\ntype ComputeResponse =\n | { id: string; type: 'cache-key'; cacheKey: string }\n | { id: string; type: 'done' }\n | { id: string; type: 'aborted' }\n | { id: string; type: 'error'; error: string };\n\n/** Union of all values that worker resolve callbacks receive. */\ntype PendingResolveValue = { cacheKey: string } | void;\n\ninterface PendingEntry {\n resolve: (value: PendingResolveValue) => void;\n reject: (reason: unknown) => void;\n}\n\n/** Add a pending promise entry, centralizing the single unavoidable resolve cast. */\nfunction addPending<T>(\n map: Map<string, PendingEntry>,\n id: string,\n resolve: (value: T) => void,\n reject: (reason: unknown) => void\n): void {\n map.set(id, { resolve: resolve as PendingEntry['resolve'], reject });\n}\n\nexport interface SpectrogramWorkerApi {\n computeFFT(\n params: SpectrogramWorkerFFTParams,\n generation?: number\n ): Promise<{ cacheKey: string }>;\n renderChunks(params: SpectrogramWorkerRenderChunksParams, generation?: number): Promise<void>;\n abortGeneration(generation: number): void;\n registerCanvas(canvasId: string, canvas: OffscreenCanvas): void;\n unregisterCanvas(canvasId: string): void;\n registerAudioData(clipId: string, channelDataArrays: Float32Array[], sampleRate: number): void;\n unregisterAudioData(clipId: string): void;\n terminate(): void;\n}\n\nlet idCounter = 0;\n\n/**\n * Wraps a Web Worker running `spectrogram.worker.ts` with a promise-based API.\n *\n * The caller is responsible for creating the Worker, e.g.:\n * ```ts\n * const worker = new Worker(\n * new URL('@waveform-playlist/spectrogram/worker/spectrogram.worker', import.meta.url),\n * { type: 'module' }\n * );\n * const api = createSpectrogramWorker(worker);\n * ```\n */\nexport function createSpectrogramWorker(worker: Worker): SpectrogramWorkerApi {\n const pending = new Map<string, PendingEntry>();\n\n // Track which clipIds have pre-registered audio data in the worker\n const registeredClipIds = new Set<string>();\n let terminated = false;\n\n worker.onmessage = (e: MessageEvent<ComputeResponse>) => {\n const msg = e.data;\n const entry = pending.get(msg.id);\n if (entry) {\n pending.delete(msg.id);\n switch (msg.type) {\n case 'error':\n entry.reject(new Error(msg.error));\n break;\n case 'aborted':\n entry.reject(new SpectrogramAbortError());\n break;\n case 'cache-key':\n entry.resolve({ cacheKey: msg.cacheKey });\n break;\n case 'done':\n entry.resolve(undefined);\n break;\n }\n } else if (msg.id) {\n console.warn(`[spectrogram] Received response for unknown message ID: ${msg.id}`);\n }\n };\n\n worker.onerror = (e: ErrorEvent) => {\n terminated = true;\n for (const [, entry] of pending) {\n entry.reject(e.error ?? new Error(e.message));\n }\n pending.clear();\n };\n\n return {\n computeFFT(params: SpectrogramWorkerFFTParams, generation = 0): Promise<{ cacheKey: string }> {\n if (terminated) return Promise.reject(new Error('Worker terminated'));\n const id = String(++idCounter);\n\n return new Promise<{ cacheKey: string }>((resolve, reject) => {\n addPending(pending, id, resolve, reject);\n\n // Skip transfer if audio data is pre-registered in the worker\n const isPreRegistered = registeredClipIds.has(params.clipId);\n const transferableArrays = isPreRegistered\n ? []\n : params.channelDataArrays.map((arr) => arr.slice());\n const transferables = transferableArrays.map((arr) => arr.buffer);\n\n worker.postMessage(\n {\n type: 'compute-fft',\n id,\n generation,\n clipId: params.clipId,\n channelDataArrays: transferableArrays,\n config: params.config,\n sampleRate: params.sampleRate,\n offsetSamples: params.offsetSamples,\n durationSamples: params.durationSamples,\n mono: params.mono,\n ...(params.sampleRange ? { sampleRange: params.sampleRange } : {}),\n ...(params.channelFilter !== undefined ? { channelFilter: params.channelFilter } : {}),\n },\n transferables\n );\n });\n },\n\n renderChunks(params: SpectrogramWorkerRenderChunksParams, generation = 0): Promise<void> {\n if (terminated) return Promise.reject(new Error('Worker terminated'));\n const id = String(++idCounter);\n\n return new Promise<void>((resolve, reject) => {\n addPending(pending, id, resolve, reject);\n\n worker.postMessage({\n type: 'render-chunks',\n id,\n generation,\n cacheKey: params.cacheKey,\n canvasIds: params.canvasIds,\n canvasWidths: params.canvasWidths,\n globalPixelOffsets: params.globalPixelOffsets,\n canvasHeight: params.canvasHeight,\n devicePixelRatio: params.devicePixelRatio,\n samplesPerPixel: params.samplesPerPixel,\n colorLUT: params.colorLUT,\n frequencyScale: params.frequencyScale,\n minFrequency: params.minFrequency,\n maxFrequency: params.maxFrequency,\n gainDb: params.gainDb,\n rangeDb: params.rangeDb,\n channelIndex: params.channelIndex,\n });\n });\n },\n\n abortGeneration(generation: number): void {\n if (terminated) return;\n worker.postMessage({ type: 'abort-generation', generation });\n },\n\n registerCanvas(canvasId: string, canvas: OffscreenCanvas): void {\n worker.postMessage({ type: 'register-canvas', canvasId, canvas }, [canvas]);\n },\n\n unregisterCanvas(canvasId: string): void {\n worker.postMessage({ type: 'unregister-canvas', canvasId });\n },\n\n registerAudioData(clipId: string, channelDataArrays: Float32Array[], sampleRate: number): void {\n const transferableArrays = channelDataArrays.map((arr) => arr.slice());\n const transferables = transferableArrays.map((arr) => arr.buffer);\n worker.postMessage(\n { type: 'register-audio-data', clipId, channelDataArrays: transferableArrays, sampleRate },\n transferables\n );\n registeredClipIds.add(clipId);\n },\n\n unregisterAudioData(clipId: string): void {\n worker.postMessage({ type: 'unregister-audio-data', clipId });\n registeredClipIds.delete(clipId);\n },\n\n terminate() {\n terminated = true;\n worker.terminate();\n for (const [, entry] of pending) {\n entry.reject(new Error('Worker terminated'));\n }\n pending.clear();\n },\n };\n}\n","import {\n createSpectrogramWorker,\n type SpectrogramWorkerApi,\n type SpectrogramWorkerFFTParams,\n type SpectrogramWorkerRenderChunksParams,\n} from './createSpectrogramWorker';\n\n/**\n * Parse the channel index from a canvas ID like \"clipId-ch0-chunk5\" → 0.\n */\nfunction parseChannelFromCanvasId(canvasId: string): number {\n const match = canvasId.match(/-ch(\\d+)-/);\n return match ? parseInt(match[1], 10) : 0;\n}\n\n/**\n * Creates a pool of spectrogram workers that parallelize FFT computation\n * across channels. Each worker handles a subset of channels, so stereo\n * audio computes ch0 and ch1 FFTs in parallel (~1.5s instead of ~2.9s).\n *\n * The pool exposes the same `SpectrogramWorkerApi` interface, so it's\n * a drop-in replacement for a single worker in SpectrogramProvider.\n *\n * Audio data is registered in ALL workers (each needs full data for mono\n * mode). Canvases are routed to the worker for their channel. computeFFT\n * fans out with channelFilter so each worker computes only its channel.\n */\n/**\n * Default pool size: 2 workers (one per channel for stereo).\n * Most web audio is mono or stereo, so 2 is sufficient.\n * Configurable via `<SpectrogramProvider workerPoolSize={N}>` for\n * multi-channel audio (e.g., 5.1 surround).\n */\nfunction defaultPoolSize(): number {\n return 2;\n}\n\nexport function createSpectrogramWorkerPool(\n createWorker: () => Worker,\n poolSize = defaultPoolSize()\n): SpectrogramWorkerApi {\n const workers: SpectrogramWorkerApi[] = [];\n try {\n for (let i = 0; i < poolSize; i++) {\n workers.push(createSpectrogramWorker(createWorker()));\n }\n } catch (err) {\n for (const w of workers) {\n w.terminate();\n }\n throw err;\n }\n\n function getWorkerForChannel(channelIndex: number): SpectrogramWorkerApi {\n return workers[channelIndex % workers.length];\n }\n\n return {\n computeFFT(params: SpectrogramWorkerFFTParams, generation = 0): Promise<{ cacheKey: string }> {\n // Mono: single worker computes the mono mix (needs all channel data)\n if (params.mono) {\n return workers[0].computeFFT(params, generation);\n }\n\n // Multi-channel: fan out with channelFilter, one worker per channel.\n // Pool may have more workers than channels (e.g., 3 workers for stereo) —\n // only use workers up to the channel count.\n const channelCount = params.channelDataArrays.length;\n const activeWorkers = workers.slice(0, channelCount);\n const promises = activeWorkers.map((w, i) =>\n w.computeFFT({ ...params, channelFilter: i }, generation)\n );\n // Wait for all workers, return any cacheKey (all are identical)\n return Promise.all(promises).then((results) => results[0]);\n },\n\n renderChunks(params: SpectrogramWorkerRenderChunksParams, generation = 0): Promise<void> {\n const worker = getWorkerForChannel(params.channelIndex);\n // Remap channelIndex to 0 — each worker stores its channel at index 0\n return worker.renderChunks({ ...params, channelIndex: 0 }, generation);\n },\n\n abortGeneration(generation: number): void {\n for (const w of workers) {\n w.abortGeneration(generation);\n }\n },\n\n registerCanvas(canvasId: string, canvas: OffscreenCanvas): void {\n const ch = parseChannelFromCanvasId(canvasId);\n getWorkerForChannel(ch).registerCanvas(canvasId, canvas);\n },\n\n unregisterCanvas(canvasId: string): void {\n const ch = parseChannelFromCanvasId(canvasId);\n getWorkerForChannel(ch).unregisterCanvas(canvasId);\n },\n\n registerAudioData(clipId: string, channelDataArrays: Float32Array[], sampleRate: number): void {\n // All workers get full audio data (needed for mono computation)\n for (const w of workers) {\n w.registerAudioData(clipId, channelDataArrays, sampleRate);\n }\n },\n\n unregisterAudioData(clipId: string): void {\n for (const w of workers) {\n w.unregisterAudioData(clipId);\n }\n },\n\n terminate(): void {\n for (const w of workers) {\n w.terminate();\n }\n },\n };\n}\n","import React, { useState, useEffect, useRef, useCallback, useMemo, type ReactNode } from 'react';\nimport {\n MAX_CANVAS_WIDTH,\n type SpectrogramConfig,\n type SpectrogramComputeConfig,\n type ColorMapValue,\n type RenderMode,\n type TrackSpectrogramOverrides,\n} from '@waveform-playlist/core';\nimport { getColorMap, getFrequencyScale } from './computation';\nimport {\n createSpectrogramWorkerPool,\n SpectrogramAbortError,\n type SpectrogramWorkerApi,\n} from './worker';\nimport { SpectrogramMenuItems } from './components';\nimport { SpectrogramSettingsModal } from './components';\nimport {\n SpectrogramIntegrationProvider,\n type SpectrogramIntegration,\n} from '@waveform-playlist/browser';\nimport { usePlaylistData, usePlaylistControls } from '@waveform-playlist/browser';\n\n/** Extract the chunk number from a canvas ID like \"clipId-ch0-chunk5\" → 5 */\nfunction extractChunkNumber(canvasId: string): number {\n const match = canvasId.match(/chunk(\\d+)$/);\n if (!match) {\n console.warn(`[spectrogram] Unexpected canvas ID format: ${canvasId}`);\n return 0;\n }\n return parseInt(match[1], 10);\n}\n\nexport interface SpectrogramProviderProps {\n config?: SpectrogramConfig;\n colorMap?: ColorMapValue;\n /** Number of Web Workers for parallel FFT computation. Defaults to 2 (one per stereo channel). */\n workerPoolSize?: number;\n children: ReactNode;\n}\n\nexport const SpectrogramProvider: React.FC<SpectrogramProviderProps> = ({\n config: spectrogramConfig,\n colorMap: spectrogramColorMap,\n workerPoolSize,\n children,\n}) => {\n const { tracks, waveHeight, samplesPerPixel, isReady, mono } = usePlaylistData();\n const { scrollContainerRef } = usePlaylistControls();\n\n // State\n const [trackSpectrogramOverrides, setTrackSpectrogramOverrides] = useState<\n Map<string, TrackSpectrogramOverrides>\n >(new Map());\n\n // OffscreenCanvas registry for worker-rendered spectrograms\n const spectrogramCanvasRegistryRef = useRef<\n Map<string, Map<number, { canvasIds: string[]; canvasWidths: number[] }>>\n >(new Map());\n const [spectrogramCanvasVersion, setSpectrogramCanvasVersion] = useState(0);\n\n // Spectrogram refs\n const prevSpectrogramConfigRef = useRef<Map<string, string>>(new Map());\n const prevSpectrogramFFTKeyRef = useRef<Map<string, string>>(new Map());\n const spectrogramWorkerRef = useRef<SpectrogramWorkerApi | null>(null);\n const spectrogramGenerationRef = useRef(0);\n const prevCanvasVersionRef = useRef(0);\n const [spectrogramWorkerReady, setSpectrogramWorkerReady] = useState(false);\n const renderedClipIdsRef = useRef<Set<string>>(new Set());\n const backgroundRenderAbortRef = useRef<{ aborted: boolean } | null>(null);\n const registeredAudioClipIdsRef = useRef<Set<string>>(new Set());\n\n // Terminate worker on unmount\n useEffect(() => {\n return () => {\n spectrogramWorkerRef.current?.terminate();\n spectrogramWorkerRef.current = null;\n };\n }, []);\n\n // Eagerly transfer audio data to worker when tracks load\n useEffect(() => {\n if (!isReady || tracks.length === 0) return;\n\n let workerApi = spectrogramWorkerRef.current;\n if (!workerApi) {\n try {\n workerApi = createSpectrogramWorkerPool(\n () =>\n new Worker(\n new URL('@waveform-playlist/spectrogram/worker/spectrogram.worker', import.meta.url),\n { type: 'module' }\n ),\n workerPoolSize\n );\n spectrogramWorkerRef.current = workerApi;\n setSpectrogramWorkerReady(true);\n } catch (err) {\n console.warn(\n `[waveform-playlist] Spectrogram Web Worker unavailable for pre-transfer: ${err instanceof Error ? err.message : String(err)}`\n );\n return;\n }\n }\n\n const currentClipIds = new Set<string>();\n\n for (const track of tracks) {\n for (const clip of track.clips) {\n if (!clip.audioBuffer) continue;\n currentClipIds.add(clip.id);\n\n if (!registeredAudioClipIdsRef.current.has(clip.id)) {\n const channelDataArrays: Float32Array[] = [];\n for (let ch = 0; ch < clip.audioBuffer.numberOfChannels; ch++) {\n channelDataArrays.push(clip.audioBuffer.getChannelData(ch));\n }\n workerApi.registerAudioData(clip.id, channelDataArrays, clip.audioBuffer.sampleRate);\n registeredAudioClipIdsRef.current.add(clip.id);\n }\n }\n }\n\n for (const clipId of registeredAudioClipIdsRef.current) {\n if (!currentClipIds.has(clipId)) {\n workerApi.unregisterAudioData(clipId);\n registeredAudioClipIdsRef.current.delete(clipId);\n }\n }\n // workerPoolSize intentionally omitted — pool is created once via spectrogramWorkerRef guard\n }, [isReady, tracks]); // eslint-disable-line react-hooks/exhaustive-deps\n\n // Main spectrogram computation effect\n useEffect(() => {\n if (tracks.length === 0) return;\n\n const currentKeys = new Map<string, string>();\n const currentFFTKeys = new Map<string, string>();\n tracks.forEach((track) => {\n const mode =\n trackSpectrogramOverrides.get(track.id)?.renderMode ?? track.renderMode ?? 'waveform';\n if (mode === 'waveform') return;\n const cfg =\n trackSpectrogramOverrides.get(track.id)?.config ??\n track.spectrogramConfig ??\n spectrogramConfig;\n const cm =\n trackSpectrogramOverrides.get(track.id)?.colorMap ??\n track.spectrogramColorMap ??\n spectrogramColorMap;\n currentKeys.set(track.id, JSON.stringify({ mode, cfg, cm, mono }));\n const computeConfig: SpectrogramComputeConfig = {\n fftSize: cfg?.fftSize,\n hopSize: cfg?.hopSize,\n windowFunction: cfg?.windowFunction,\n alpha: cfg?.alpha,\n zeroPaddingFactor: cfg?.zeroPaddingFactor,\n };\n currentFFTKeys.set(track.id, JSON.stringify({ mode, mono, ...computeConfig }));\n });\n\n const prevKeys = prevSpectrogramConfigRef.current;\n const prevFFTKeys = prevSpectrogramFFTKeyRef.current;\n\n let configChanged = currentKeys.size !== prevKeys.size;\n if (!configChanged) {\n for (const [idx, key] of currentKeys) {\n if (prevKeys.get(idx) !== key) {\n configChanged = true;\n break;\n }\n }\n }\n\n let fftKeyChanged = currentFFTKeys.size !== prevFFTKeys.size;\n if (!fftKeyChanged) {\n for (const [idx, key] of currentFFTKeys) {\n if (prevFFTKeys.get(idx) !== key) {\n fftKeyChanged = true;\n break;\n }\n }\n }\n\n const canvasVersionChanged = spectrogramCanvasVersion !== prevCanvasVersionRef.current;\n prevCanvasVersionRef.current = spectrogramCanvasVersion;\n\n if (!configChanged && !canvasVersionChanged) return;\n\n if (configChanged) {\n prevSpectrogramConfigRef.current = currentKeys;\n prevSpectrogramFFTKeyRef.current = currentFFTKeys;\n }\n\n if (backgroundRenderAbortRef.current) {\n backgroundRenderAbortRef.current.aborted = true;\n }\n\n const generation = ++spectrogramGenerationRef.current;\n\n // Tell the worker to abort any in-flight FFT from previous generations\n if (spectrogramWorkerRef.current) {\n spectrogramWorkerRef.current.abortGeneration(generation);\n }\n\n let workerApi = spectrogramWorkerRef.current;\n if (!workerApi) {\n try {\n workerApi = createSpectrogramWorkerPool(\n () =>\n new Worker(\n new URL('@waveform-playlist/spectrogram/worker/spectrogram.worker', import.meta.url),\n { type: 'module' }\n ),\n workerPoolSize\n );\n spectrogramWorkerRef.current = workerApi;\n setSpectrogramWorkerReady(true);\n } catch (err) {\n console.error(`[waveform-playlist] Spectrogram Web Worker required but unavailable: ${err instanceof Error ? err.message : String(err)}`);\n return;\n }\n }\n\n const clipsNeedingFFT: Array<{\n clipId: string;\n trackIndex: number;\n channelDataArrays: Float32Array[];\n config: SpectrogramConfig;\n sampleRate: number;\n offsetSamples: number;\n durationSamples: number;\n clipStartSample: number;\n monoFlag: boolean;\n colorMap: ColorMapValue;\n }> = [];\n const clipsNeedingDisplayOnly: Array<{\n clipId: string;\n trackIndex: number;\n channelDataArrays: Float32Array[];\n config: SpectrogramConfig;\n sampleRate: number;\n offsetSamples: number;\n durationSamples: number;\n clipStartSample: number;\n monoFlag: boolean;\n colorMap: ColorMapValue;\n numChannels: number;\n }> = [];\n\n tracks.forEach((track, i) => {\n const mode =\n trackSpectrogramOverrides.get(track.id)?.renderMode ?? track.renderMode ?? 'waveform';\n if (mode === 'waveform') return;\n\n const trackConfigChanged =\n configChanged && currentKeys.get(track.id) !== prevKeys.get(track.id);\n const trackFFTChanged =\n fftKeyChanged && currentFFTKeys.get(track.id) !== prevFFTKeys.get(track.id);\n const hasRegisteredCanvases =\n canvasVersionChanged &&\n track.clips.some((clip) => spectrogramCanvasRegistryRef.current.has(clip.id));\n if (!trackConfigChanged && !hasRegisteredCanvases) return;\n\n const cfg =\n trackSpectrogramOverrides.get(track.id)?.config ??\n track.spectrogramConfig ??\n spectrogramConfig ??\n {};\n const cm =\n trackSpectrogramOverrides.get(track.id)?.colorMap ??\n track.spectrogramColorMap ??\n spectrogramColorMap ??\n 'viridis';\n\n for (const clip of track.clips) {\n if (!clip.audioBuffer) continue;\n\n const monoFlag = mono || clip.audioBuffer.numberOfChannels === 1;\n\n if (!trackFFTChanged && !hasRegisteredCanvases && renderedClipIdsRef.current.has(clip.id)) {\n const channelDataArrays: Float32Array[] = [];\n for (let ch = 0; ch < clip.audioBuffer.numberOfChannels; ch++) {\n channelDataArrays.push(clip.audioBuffer.getChannelData(ch));\n }\n clipsNeedingDisplayOnly.push({\n clipId: clip.id,\n trackIndex: i,\n channelDataArrays,\n config: cfg,\n sampleRate: clip.audioBuffer.sampleRate,\n offsetSamples: clip.offsetSamples,\n durationSamples: clip.durationSamples,\n clipStartSample: clip.startSample,\n monoFlag,\n colorMap: cm,\n numChannels: monoFlag ? 1 : clip.audioBuffer.numberOfChannels,\n });\n continue;\n }\n\n const channelDataArrays: Float32Array[] = [];\n for (let ch = 0; ch < clip.audioBuffer.numberOfChannels; ch++) {\n channelDataArrays.push(clip.audioBuffer.getChannelData(ch));\n }\n\n clipsNeedingFFT.push({\n clipId: clip.id,\n trackIndex: i,\n channelDataArrays,\n config: cfg,\n sampleRate: clip.audioBuffer.sampleRate,\n offsetSamples: clip.offsetSamples,\n durationSamples: clip.durationSamples,\n clipStartSample: clip.startSample,\n monoFlag,\n colorMap: cm,\n });\n }\n });\n\n if (clipsNeedingFFT.length === 0 && clipsNeedingDisplayOnly.length === 0) return;\n\n // Three-tier chunk classification:\n // - viewportIndices: chunks intersecting the exact viewport (phase 1a — fast first paint)\n // - bufferIndices: chunks in the 1.5× overscan buffer but outside viewport (phase 1b)\n // - remainingIndices: chunks outside the buffer (phase 2 — background batches)\n const getVisibleChunkRange = (\n channelInfo: { canvasIds: string[]; canvasWidths: number[] },\n clipPixelOffset = 0\n ): { viewportIndices: number[]; bufferIndices: number[]; remainingIndices: number[] } => {\n const container = scrollContainerRef.current;\n if (!container) {\n return {\n viewportIndices: channelInfo.canvasWidths.map((_, i) => i),\n bufferIndices: [],\n remainingIndices: [],\n };\n }\n\n const scrollLeft = container.scrollLeft;\n const viewportWidth = container.clientWidth;\n // Match the 1.5× overscan buffer used by useVisibleChunkIndices\n // (ScrollViewport.tsx) so spectrogram FFT covers all mounted canvases.\n const buffer = viewportWidth * 1.5;\n const bufferStart = Math.max(0, scrollLeft - buffer);\n const bufferEnd = scrollLeft + viewportWidth + buffer;\n\n const viewportIndices: number[] = [];\n const bufferIndices: number[] = [];\n const remainingIndices: number[] = [];\n\n for (let i = 0; i < channelInfo.canvasWidths.length; i++) {\n const chunkNumber = extractChunkNumber(channelInfo.canvasIds[i]);\n const chunkLeft = chunkNumber * MAX_CANVAS_WIDTH + clipPixelOffset;\n const chunkRight = chunkLeft + channelInfo.canvasWidths[i];\n if (chunkRight > scrollLeft && chunkLeft < scrollLeft + viewportWidth) {\n viewportIndices.push(i);\n } else if (chunkRight > bufferStart && chunkLeft < bufferEnd) {\n bufferIndices.push(i);\n } else {\n remainingIndices.push(i);\n }\n }\n\n return { viewportIndices, bufferIndices, remainingIndices };\n };\n\n const renderChunkSubset = async (\n api: SpectrogramWorkerApi,\n cacheKey: string,\n channelInfo: { canvasIds: string[]; canvasWidths: number[] },\n indices: number[],\n item: { config: SpectrogramConfig; colorMap: ColorMapValue },\n channelIndex: number,\n gen: number\n ) => {\n if (indices.length === 0) return;\n\n const canvasIds = indices.map((i) => channelInfo.canvasIds[i]);\n const canvasWidths = indices.map((i) => channelInfo.canvasWidths[i]);\n\n // Compute correct global pixel offsets by extracting chunk numbers from\n // canvas IDs. With virtual scrolling, the registry may contain non-consecutive\n // chunks (e.g., chunks 50-55), so summing widths from index 0 gives wrong offsets.\n const globalPixelOffsets: number[] = [];\n for (const idx of indices) {\n const chunkNumber = extractChunkNumber(channelInfo.canvasIds[idx]);\n globalPixelOffsets.push(chunkNumber * MAX_CANVAS_WIDTH);\n }\n\n const colorLUT = getColorMap(item.colorMap);\n\n await api.renderChunks(\n {\n cacheKey,\n canvasIds,\n canvasWidths,\n globalPixelOffsets,\n canvasHeight: waveHeight,\n devicePixelRatio: typeof window !== 'undefined' ? window.devicePixelRatio : 1,\n samplesPerPixel,\n colorLUT,\n frequencyScale: item.config.frequencyScale ?? 'mel',\n minFrequency: item.config.minFrequency ?? 0,\n maxFrequency: item.config.maxFrequency ?? 0,\n gainDb: item.config.gainDb ?? 20,\n rangeDb: item.config.rangeDb ?? 80,\n channelIndex,\n },\n gen\n );\n };\n\n // Compute FFT for the sample range covered by a set of chunk indices.\n // Returns the cache key (data covers all channels).\n // This avoids computing a single full-clip FFT (which OOMs on 1hr+ files)\n // by computing per-batch ranges on demand.\n const computeFFTForChunks = async (\n api: SpectrogramWorkerApi,\n channelInfo: { canvasIds: string[]; canvasWidths: number[] },\n indices: number[],\n item: {\n clipId: string;\n channelDataArrays: Float32Array[];\n config: SpectrogramConfig;\n sampleRate: number;\n offsetSamples: number;\n durationSamples: number;\n monoFlag: boolean;\n },\n gen: number\n ): Promise<string> => {\n // Determine the sample range these chunks cover\n const chunkNumbers = indices.map((i) => extractChunkNumber(channelInfo.canvasIds[i]));\n const minChunk = Math.min(...chunkNumbers);\n const maxChunk = Math.max(...chunkNumbers);\n const maxChunkIdx = indices[chunkNumbers.indexOf(maxChunk)];\n const lastChunkWidth = channelInfo.canvasWidths[maxChunkIdx];\n\n const startPx = minChunk * MAX_CANVAS_WIDTH;\n const endPx = maxChunk * MAX_CANVAS_WIDTH + lastChunkWidth;\n\n const windowSize = item.config.fftSize ?? 2048;\n const rangeStartSample = item.offsetSamples + Math.floor(startPx * samplesPerPixel);\n const rangeEndSample = Math.min(\n item.offsetSamples + item.durationSamples,\n item.offsetSamples + Math.ceil(endPx * samplesPerPixel)\n );\n\n // Pad by windowSize to avoid edge artifacts\n const paddedStart = Math.max(item.offsetSamples, rangeStartSample - windowSize);\n const paddedEnd = Math.min(\n item.offsetSamples + item.durationSamples,\n rangeEndSample + windowSize\n );\n\n const { cacheKey } = await api.computeFFT(\n {\n clipId: item.clipId,\n channelDataArrays: item.channelDataArrays,\n config: item.config,\n sampleRate: item.sampleRate,\n offsetSamples: item.offsetSamples,\n durationSamples: item.durationSamples,\n mono: item.monoFlag,\n sampleRange: { start: paddedStart, end: paddedEnd },\n },\n gen\n );\n\n return cacheKey;\n };\n\n // Split indices into contiguous groups based on chunk numbers.\n // E.g., remaining=[0,1,4,5] → [[0,1],[4,5]] — prevents computing\n // an FFT range spanning the gap between 1 and 4.\n const groupContiguousIndices = (\n channelInfo: { canvasIds: string[] },\n indices: number[]\n ): number[][] => {\n if (indices.length === 0) return [];\n const groups: number[][] = [];\n let currentGroup = [indices[0]];\n let prevChunk = extractChunkNumber(channelInfo.canvasIds[indices[0]]);\n for (let i = 1; i < indices.length; i++) {\n const chunk = extractChunkNumber(channelInfo.canvasIds[indices[i]]);\n if (chunk === prevChunk + 1) {\n currentGroup.push(indices[i]);\n } else {\n groups.push(currentGroup);\n currentGroup = [indices[i]];\n }\n prevChunk = chunk;\n }\n groups.push(currentGroup);\n return groups;\n };\n\n const computeAsync = async () => {\n const abortToken = { aborted: false };\n backgroundRenderAbortRef.current = abortToken;\n\n // Render off-screen chunks in idle-callback batches, computing FFT\n // per contiguous group to avoid allocating one giant Float32Array for the\n // full clip (which OOMs on 1hr+ files — e.g., 310K frames × 2048 bins = 2.5GB).\n // Groups remaining indices into contiguous runs (e.g., [0,1,4,5] → [0,1]+[4,5])\n // so each FFT only covers the sample range actually needed.\n // Returns true if aborted (caller should return early).\n const renderBackgroundBatches = async (\n channelRanges: Array<{\n ch: number;\n channelInfo: { canvasIds: string[]; canvasWidths: number[] };\n remainingIndices: number[];\n }>,\n item: {\n clipId: string;\n channelDataArrays: Float32Array[];\n config: SpectrogramConfig;\n sampleRate: number;\n offsetSamples: number;\n durationSamples: number;\n monoFlag: boolean;\n colorMap: ColorMapValue;\n }\n ): Promise<boolean> => {\n // Collect all contiguous groups across channels, then render\n // each group for ALL channels before moving to the next group\n // (multi-channel fairness — avoids ch1 starvation).\n const allGroups: Array<{\n group: number[];\n channelRangeEntries: Array<{\n ch: number;\n channelInfo: { canvasIds: string[]; canvasWidths: number[] };\n }>;\n }> = [];\n\n // Build contiguous groups from the first channel's remaining indices\n // (all channels have the same chunk layout).\n if (channelRanges.length > 0) {\n const { channelInfo, remainingIndices } = channelRanges[0];\n const groups = groupContiguousIndices(channelInfo, remainingIndices);\n for (const group of groups) {\n allGroups.push({\n group,\n channelRangeEntries: channelRanges.map(({ ch, channelInfo: ci }) => ({\n ch,\n channelInfo: ci,\n })),\n });\n }\n }\n\n for (const { group, channelRangeEntries } of allGroups) {\n if (spectrogramGenerationRef.current !== generation || abortToken.aborted) return true;\n\n await new Promise<void>((resolve) => {\n if (typeof requestIdleCallback === 'function') {\n requestIdleCallback(() => resolve());\n } else {\n setTimeout(resolve, 0);\n }\n });\n\n if (spectrogramGenerationRef.current !== generation || abortToken.aborted) return true;\n\n // Compute FFT once for this contiguous group (covers all channels)\n const { channelInfo: firstChannelInfo } = channelRangeEntries[0];\n const cacheKey = await computeFFTForChunks(\n workerApi!,\n firstChannelInfo,\n group,\n item,\n generation\n );\n\n // Render all channels from the cached FFT data\n for (const { ch, channelInfo: ci } of channelRangeEntries) {\n if (spectrogramGenerationRef.current !== generation || abortToken.aborted) return true;\n await renderChunkSubset(workerApi!, cacheKey, ci, group, item, ch, generation);\n }\n }\n return false;\n };\n\n for (const item of clipsNeedingFFT) {\n if (spectrogramGenerationRef.current !== generation || abortToken.aborted) return;\n\n try {\n const clipCanvasInfo = spectrogramCanvasRegistryRef.current.get(item.clipId);\n if (clipCanvasInfo && clipCanvasInfo.size > 0) {\n const numChannels = item.monoFlag ? 1 : item.channelDataArrays.length;\n const clipPixelOffset = Math.floor(item.clipStartSample / samplesPerPixel);\n\n // Three-phase rendering:\n // Phase 1a: viewport-only chunks (fast first paint)\n // Phase 1b: buffer-zone chunks (prevents black chunks on scroll)\n // Phase 2: off-screen chunks (background batches)\n const channelRanges: Array<{\n ch: number;\n channelInfo: { canvasIds: string[]; canvasWidths: number[] };\n viewportIndices: number[];\n bufferIndices: number[];\n remainingIndices: number[];\n }> = [];\n\n for (let ch = 0; ch < numChannels; ch++) {\n const channelInfo = clipCanvasInfo.get(ch);\n if (!channelInfo) continue;\n const range = getVisibleChunkRange(channelInfo, clipPixelOffset);\n channelRanges.push({ ch, channelInfo, ...range });\n }\n\n // Phase 1a: Compute FFT for viewport chunks only, render all channels\n if (channelRanges.length > 0 && channelRanges[0].viewportIndices.length > 0) {\n const cacheKey = await computeFFTForChunks(\n workerApi!,\n channelRanges[0].channelInfo,\n channelRanges[0].viewportIndices,\n item,\n generation\n );\n\n if (spectrogramGenerationRef.current !== generation || abortToken.aborted) return;\n\n for (const { ch, channelInfo, viewportIndices } of channelRanges) {\n await renderChunkSubset(\n workerApi!,\n cacheKey,\n channelInfo,\n viewportIndices,\n item,\n ch,\n generation\n );\n }\n }\n\n if (spectrogramGenerationRef.current !== generation || abortToken.aborted) return;\n\n // Phase 1b: Compute FFT for buffer-zone chunks, render all channels.\n // Buffer indices may be non-contiguous (e.g., chunks [10,14,15] from\n // indices [0,3,4,5]), so group them to avoid spanning a huge FFT range.\n if (channelRanges.length > 0 && channelRanges[0].bufferIndices.length > 0) {\n const bufferGroups = groupContiguousIndices(\n channelRanges[0].channelInfo,\n channelRanges[0].bufferIndices\n );\n\n for (const group of bufferGroups) {\n if (spectrogramGenerationRef.current !== generation || abortToken.aborted) return;\n\n const cacheKey = await computeFFTForChunks(\n workerApi!,\n channelRanges[0].channelInfo,\n group,\n item,\n generation\n );\n\n if (spectrogramGenerationRef.current !== generation || abortToken.aborted) return;\n\n for (const { ch, channelInfo } of channelRanges) {\n await renderChunkSubset(\n workerApi!,\n cacheKey,\n channelInfo,\n group,\n item,\n ch,\n generation\n );\n }\n }\n }\n\n renderedClipIdsRef.current.add(item.clipId);\n\n if (spectrogramGenerationRef.current !== generation || abortToken.aborted) return;\n\n // Phase 2: Render off-screen chunks in background batches\n // (each batch computes its own bounded FFT range).\n if (await renderBackgroundBatches(channelRanges, item)) return;\n }\n } catch (err) {\n if (err instanceof SpectrogramAbortError) return;\n console.warn(\n `[waveform-playlist] Spectrogram worker error for clip ${item.clipId}: ${err instanceof Error ? err.message : String(err)}`\n );\n }\n }\n\n for (const item of clipsNeedingDisplayOnly) {\n if (spectrogramGenerationRef.current !== generation || abortToken.aborted) return;\n\n const clipCanvasInfo = spectrogramCanvasRegistryRef.current.get(item.clipId);\n if (!clipCanvasInfo || clipCanvasInfo.size === 0) continue;\n\n try {\n const clipPixelOffset = Math.floor(item.clipStartSample / samplesPerPixel);\n\n // Three-phase rendering with per-batch FFT (same as FFT path above).\n // Worker cache provides instant hits for previously computed ranges.\n const channelRanges: Array<{\n ch: number;\n channelInfo: { canvasIds: string[]; canvasWidths: number[] };\n viewportIndices: number[];\n bufferIndices: number[];\n remainingIndices: number[];\n }> = [];\n for (let ch = 0; ch < item.numChannels; ch++) {\n const channelInfo = clipCanvasInfo.get(ch);\n if (!channelInfo) continue;\n const range = getVisibleChunkRange(channelInfo, clipPixelOffset);\n channelRanges.push({ ch, channelInfo, ...range });\n }\n\n // Phase 1a: viewport chunks\n if (channelRanges.length > 0 && channelRanges[0].viewportIndices.length > 0) {\n const cacheKey = await computeFFTForChunks(\n workerApi!,\n channelRanges[0].channelInfo,\n channelRanges[0].viewportIndices,\n item,\n generation\n );\n if (spectrogramGenerationRef.current !== generation || abortToken.aborted) return;\n for (const { ch, channelInfo, viewportIndices } of channelRanges) {\n await renderChunkSubset(\n workerApi!,\n cacheKey,\n channelInfo,\n viewportIndices,\n item,\n ch,\n generation\n );\n }\n }\n\n if (spectrogramGenerationRef.current !== generation || abortToken.aborted) return;\n\n // Phase 1b: buffer-zone chunks (grouped for contiguous FFT ranges)\n if (channelRanges.length > 0 && channelRanges[0].bufferIndices.length > 0) {\n const bufferGroups = groupContiguousIndices(\n channelRanges[0].channelInfo,\n channelRanges[0].bufferIndices\n );\n for (const group of bufferGroups) {\n if (spectrogramGenerationRef.current !== generation || abortToken.aborted) return;\n const cacheKey = await computeFFTForChunks(\n workerApi!,\n channelRanges[0].channelInfo,\n group,\n item,\n generation\n );\n if (spectrogramGenerationRef.current !== generation || abortToken.aborted) return;\n for (const { ch, channelInfo } of channelRanges) {\n await renderChunkSubset(\n workerApi!,\n cacheKey,\n channelInfo,\n group,\n item,\n ch,\n generation\n );\n }\n }\n }\n\n if (spectrogramGenerationRef.current !== generation || abortToken.aborted) return;\n\n // Phase 2: Render off-screen chunks in background batches.\n if (await renderBackgroundBatches(channelRanges, item)) return;\n } catch (err) {\n if (err instanceof SpectrogramAbortError) return;\n console.warn(\n `[waveform-playlist] Spectrogram display re-render error for clip ${item.clipId}: ${err instanceof Error ? err.message : String(err)}`\n );\n }\n }\n };\n\n computeAsync().catch((err) => {\n console.error(`[waveform-playlist] Spectrogram computation failed: ${err instanceof Error ? err.message : String(err)}`);\n });\n // eslint-disable-next-line react-hooks/exhaustive-deps -- workerPoolSize intentionally omitted, pool created once via spectrogramWorkerRef guard\n }, [\n tracks,\n mono,\n spectrogramConfig,\n spectrogramColorMap,\n trackSpectrogramOverrides,\n waveHeight,\n samplesPerPixel,\n spectrogramCanvasVersion,\n scrollContainerRef,\n ]);\n\n // Setters\n const setTrackRenderMode = useCallback((trackId: string, mode: RenderMode) => {\n setTrackSpectrogramOverrides((prev) => {\n const next = new Map(prev);\n const existing = next.get(trackId);\n next.set(trackId, { ...existing, renderMode: mode });\n return next;\n });\n }, []);\n\n const setTrackSpectrogramConfig = useCallback(\n (trackId: string, config: SpectrogramConfig, colorMap?: ColorMapValue) => {\n setTrackSpectrogramOverrides((prev) => {\n const next = new Map(prev);\n const existing = next.get(trackId);\n next.set(trackId, {\n renderMode: existing?.renderMode ?? 'waveform',\n config,\n ...(colorMap !== undefined ? { colorMap } : { colorMap: existing?.colorMap }),\n });\n return next;\n });\n },\n []\n );\n\n const registerSpectrogramCanvases = useCallback(\n (clipId: string, channelIndex: number, canvasIds: string[], canvasWidths: number[]) => {\n const registry = spectrogramCanvasRegistryRef.current;\n if (!registry.has(clipId)) {\n registry.set(clipId, new Map());\n }\n // Replace: SpectrogramChannel passes ALL currently-registered canvas IDs\n // (not just new ones), so replacing gives the correct full set.\n registry.get(clipId)!.set(channelIndex, { canvasIds, canvasWidths });\n setSpectrogramCanvasVersion((v) => v + 1);\n },\n []\n );\n\n const unregisterSpectrogramCanvases = useCallback((clipId: string, channelIndex: number) => {\n const registry = spectrogramCanvasRegistryRef.current;\n const clipChannels = registry.get(clipId);\n if (clipChannels) {\n clipChannels.delete(channelIndex);\n if (clipChannels.size === 0) {\n registry.delete(clipId);\n }\n }\n }, []);\n\n const renderMenuItems = useCallback(\n (props: {\n renderMode: string;\n onRenderModeChange: (mode: RenderMode) => void;\n onOpenSettings: () => void;\n onClose?: () => void;\n }) => {\n return SpectrogramMenuItems({\n renderMode: props.renderMode as RenderMode,\n onRenderModeChange: props.onRenderModeChange,\n onOpenSettings: props.onOpenSettings,\n onClose: props.onClose,\n });\n },\n []\n );\n\n const value: SpectrogramIntegration = useMemo(\n () => ({\n trackSpectrogramOverrides,\n spectrogramWorkerApi: spectrogramWorkerReady ? spectrogramWorkerRef.current : null,\n spectrogramConfig,\n spectrogramColorMap,\n setTrackRenderMode,\n setTrackSpectrogramConfig,\n registerSpectrogramCanvases,\n unregisterSpectrogramCanvases,\n renderMenuItems,\n SettingsModal: SpectrogramSettingsModal,\n getColorMap,\n getFrequencyScale: getFrequencyScale as (\n name: string\n ) => (f: number, minF: number, maxF: number) => number,\n }),\n [\n trackSpectrogramOverrides,\n spectrogramWorkerReady,\n spectrogramConfig,\n spectrogramColorMap,\n setTrackRenderMode,\n setTrackSpectrogramConfig,\n registerSpectrogramCanvases,\n unregisterSpectrogramCanvases,\n renderMenuItems,\n ]\n );\n\n return <SpectrogramIntegrationProvider value={value}>{children}</SpectrogramIntegrationProvider>;\n};\n"],"mappings":"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AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EACnG;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EACnG;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EACnG;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EACnG;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EACnG;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EACnG;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EACnG;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EACnG;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAC1G;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAC3G;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAC3G;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAC3G;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAC3G;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAC3G;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAC3G;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAC3G;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAC3G;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAC3G;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAC3G;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAC3G;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAC3G;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAC3G;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EACzG;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAC5G;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAC5G;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAC5G;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAC5G;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAC5G;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAC5G;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAC9G,CAAC;AAGD,IAAM,YAAY,IAAI,WAAW;AAAA,EAC/B;AAAA,EAAG;AAAA,EAAG;AAAA,EAAG;AAAA,EAAG;AAAA,EAAG;AAAA,EAAG;AAAA,EAAG;AAAA,EAAG;AAAA,EAAG;AAAA,EAAG;AAAA,EAAG;AAAA,EAAG;AAAA,EAAG;AAAA,EAAG;AAAA,EAAG;AAAA,EAAG;AAAA,EAAG;AAAA,EAAI;AAAA,EAAG;AAAA,EAAG;AAAA,EAAI;AAAA,EAAG;AAAA,EAAG;AAAA,EACvE;AAAA,EAAG;AAAA,EAAG;AAAA,EAAI;AAAA,EAAG;AAAA,EAAG;AAAA,EAAI;AAAA,EAAG;AAAA,EAAG;AAAA,EAAI;AAAA,EAAG;AAAA,EAAG;AAAA,EAAI;AAAA,EAAG;AAAA,EAAG;AAAA,EAAI;AAAA,EAAG;AAAA,EAAG;AAAA,EAAI;AAAA,EAAG;AAAA,EAAG;AAAA,EAAI;AAAA,EAAG;AAAA,EAAG;AAAA,EAC5E;AAAA,EAAI;AAAA,EAAG;AAAA,EAAI;AAAA,EAAI;AAAA,EAAG;AAAA,EAAI;AAAA,EAAI;AAAA,EAAG;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EACzF;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAC5F;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAC5F;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAC9F;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EACnG;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EACnG;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EACnG;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EACvG;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAC3G;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAC3G;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAC3G;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAC3G;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAC3G;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAC3G;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAC3G;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAC3G;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAC3G;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAC3G;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EACpG;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EACxG;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAC5G;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAC5G;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAChH;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EACnH;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EACnH;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EACnH;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EACnH;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EACnH;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EACnH;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AACrH,CAAC;AAGD,IAAM,cAAc,IAAI,WAAW;AAAA,EACjC;AAAA,EAAG;AAAA,EAAG;AAAA,EAAG;AAAA,EAAG;AAAA,EAAG;AAAA,EAAG;AAAA,EAAG;AAAA,EAAG;AAAA,EAAG;AAAA,EAAG;AAAA,EAAG;AAAA,EAAG;AAAA,EAAG;AAAA,EAAG;AAAA,EAAI;AAAA,EAAG;AAAA,EAAG;AAAA,EAAI;AAAA,EAAG;AAAA,EAAG;AAAA,EAAI;AAAA,EAAG;AAAA,EAAG;AAAA,EACxE;AAAA,EAAG;AAAA,EAAG;AAAA,EAAI;AAAA,EAAG;AAAA,EAAG;AAAA,EAAI;AAAA,EAAG;AAAA,EAAG;AAAA,EAAI;AAAA,EAAG;AAAA,EAAG;AAAA,EAAI;AAAA,EAAG;AAAA,EAAG;AAAA,EAAI;AAAA,EAAG;AAAA,EAAG;AAAA,EAAI;AAAA,EAAG;AAAA,EAAG;AAAA,EAAI;AAAA,EAAI;AAAA,EAAG;AAAA,EAC7E;AAAA,EAAI;AAAA,EAAG;AAAA,EAAI;AAAA,EAAI;AAAA,EAAG;AAAA,EAAI;AAAA,EAAI;AAAA,EAAG;AAAA,EAAI;AAAA,EAAI;AAAA,EAAG;AAAA,EAAI;AAAA,EAAI;AAAA,EAAG;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EACvF;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAC5F;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAC5F;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAG;AAAA,EAAI;AAAA,EAAI;AAAA,EAAG;AAAA,EAAI;AAAA,EAAI;AAAA,EAAG;AAAA,EAAI;AAAA,EAAI;AAAA,EAAG;AAAA,EACxF;AAAA,EAAI;AAAA,EAAG;AAAA,EAAK;AAAA,EAAI;AAAA,EAAG;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EACjG;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EACnG;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EACnG;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAC3G;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAC3G;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAC3G;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAC3G;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EACzG;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EACpG;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EACpG;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EACpG;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EACpG;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EACpG;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EACpG;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EACrG;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAC5G;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAC5G;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAC5G;AAAA,EAAK;AAAA,EAAK;AAAA,EAAG;AAAA,EAAK;AAAA,EAAK;AAAA,EAAG;AAAA,EAAK;AAAA,EAAK;AAAA,EAAG;AAAA,EAAK;AAAA,EAAK;AAAA,EAAG;AAAA,EAAK;AAAA,EAAK;AAAA,EAAG;AAAA,EAAK;AAAA,EAAK;AAAA,EAAG;AAAA,EAAK;AAAA,EAAK;AAAA,EAAG;AAAA,EAAK;AAAA,EAAK;AAAA,EACrG;AAAA,EAAK;AAAA,EAAK;AAAA,EAAG;AAAA,EAAK;AAAA,EAAK;AAAA,EAAG;AAAA,EAAK;AAAA,EAAK;AAAA,EAAG;AAAA,EAAK;AAAA,EAAK;AAAA,EAAG;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EACxG;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAC5G;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAC5G;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAC5G;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAC5G;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EACnH;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AACrH,CAAC;AAGD,IAAM,aAAa,IAAI,WAAW;AAAA,EAChC;AAAA,EAAG;AAAA,EAAG;AAAA,EAAG;AAAA,EAAG;AAAA,EAAG;AAAA,EAAG;AAAA,EAAG;AAAA,EAAG;AAAA,EAAG;AAAA,EAAG;AAAA,EAAG;AAAA,EAAG;AAAA,EAAG;AAAA,EAAG;AAAA,EAAG;AAAA,EAAG;AAAA,EAAG;AAAA,EAAG;AAAA,EAAG;AAAA,EAAG;AAAA,EAAG;AAAA,EAAG;AAAA,EAAG;AAAA,EACrE;AAAA,EAAG;AAAA,EAAG;AAAA,EAAG;AAAA,EAAG;AAAA,EAAG;AAAA,EAAI;AAAA,EAAG;AAAA,EAAG;AAAA,EAAI;AAAA,EAAG;AAAA,EAAI;AAAA,EAAI;AAAA,EAAG;AAAA,EAAI;AAAA,EAAI;AAAA,EAAG;AAAA,EAAI;AAAA,EAAI;AAAA,EAAG;AAAA,EAAI;AAAA,EAAI;AAAA,EAAG;AAAA,EAAI;AAAA,EAChF;AAAA,EAAG;AAAA,EAAI;AAAA,EAAI;AAAA,EAAG;AAAA,EAAI;AAAA,EAAI;AAAA,EAAG;AAAA,EAAI;AAAA,EAAI;AAAA,EAAG;AAAA,EAAI;AAAA,EAAI;AAAA,EAAG;AAAA,EAAI;AAAA,EAAI;AAAA,EAAG;AAAA,EAAI;AAAA,EAAI;AAAA,EAAG;AAAA,EAAI;AAAA,EAAI;AAAA,EAAG;AAAA,EAAI;AAAA,EACpF;AAAA,EAAG;AAAA,EAAI;AAAA,EAAI;AAAA,EAAG;AAAA,EAAI;AAAA,EAAI;AAAA,EAAG;AAAA,EAAI;AAAA,EAAI;AAAA,EAAG;AAAA,EAAI;AAAA,EAAI;AAAA,EAAG;AAAA,EAAI;AAAA,EAAI;AAAA,EAAG;AAAA,EAAI;AAAA,EAAI;AAAA,EAAG;AAAA,EAAI;AAAA,EAAI;AAAA,EAAG;AAAA,EAAI;AAAA,EACpF;AAAA,EAAG;AAAA,EAAI;AAAA,EAAI;AAAA,EAAG;AAAA,EAAI;AAAA,EAAI;AAAA,EAAG;AAAA,EAAI;AAAA,EAAI;AAAA,EAAG;AAAA,EAAI;AAAA,EAAI;AAAA,EAAG;AAAA,EAAI;AAAA,EAAI;AAAA,EAAG;AAAA,EAAI;AAAA,EAAI;AAAA,EAAG;AAAA,EAAI;AAAA,EAAI;AAAA,EAAG;AAAA,EAAI;AAAA,EACpF;AAAA,EAAG;AAAA,EAAI;AAAA,EAAI;AAAA,EAAG;AAAA,EAAI;AAAA,EAAI;AAAA,EAAG;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EACzF;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAClG;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EACnG;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EACnG;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EACnG;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EACxG;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAC3G;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAC3G;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAC3G;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAC3G;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAC3G;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAC3G;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAC3G;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAC3G;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EACpG;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EACpG;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAC5G;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAC5G;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAC5G;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAC5G;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAC5G;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAClH;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EACnH;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EACnH;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EACnH;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAA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","names":["FFT","window","window","styled","import_styled_components","import_jsx_runtime","styled","import_react","import_browser","import_jsx_runtime","channelDataArrays"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/computation/fft.ts","../src/computation/windowFunctions.ts","../src/computation/computeSpectrogram.ts","../src/computation/colorMaps.ts","../src/computation/frequencyScales.ts","../src/components/SpectrogramMenuItems.tsx","../src/components/SpectrogramSettingsModal.tsx","../src/worker/createSpectrogramWorker.ts","../src/worker/createSpectrogramWorkerPool.ts","../src/SpectrogramProvider.tsx"],"sourcesContent":["// Computation\nexport {\n computeSpectrogram,\n computeSpectrogramMono,\n getColorMap,\n getFrequencyScale,\n} from './computation';\nexport type { FrequencyScaleName } from './computation';\n\n// Components\nexport { SpectrogramMenuItems } from './components';\nexport type { SpectrogramMenuItemsProps } from './components';\nexport { SpectrogramSettingsModal } from './components';\nexport type { SpectrogramSettingsModalProps } from './components';\nexport type { TrackMenuItem } from './components';\n\n// Worker\nexport { createSpectrogramWorker, SpectrogramAbortError } from './worker';\nexport { createSpectrogramWorkerPool } from './worker';\nexport type { SpectrogramWorkerApi } from './worker';\n\n// Provider\nexport { SpectrogramProvider } from './SpectrogramProvider';\nexport type { SpectrogramProviderProps } from './SpectrogramProvider';\n","import FFT from 'fft.js';\n\n/**\n * Cache fft.js instances per size (pre-computes twiddle factors).\n */\nconst fftInstances = new Map<number, FFT>();\nconst complexBuffers = new Map<number, number[]>();\n\nfunction getFftInstance(size: number): FFT {\n let instance = fftInstances.get(size);\n if (!instance) {\n instance = new FFT(size);\n fftInstances.set(size, instance);\n complexBuffers.set(size, instance.createComplexArray());\n }\n return instance;\n}\n\nfunction getComplexBuffer(size: number): number[] {\n const buffer = complexBuffers.get(size);\n if (!buffer) {\n throw new Error(`No complex buffer for size ${size}. Call getFftInstance first.`);\n }\n return buffer;\n}\n\n/**\n * In-place FFT using fft.js (radix-4).\n * @param real - Real part (modified in place)\n * @param imag - Imaginary part (modified in place)\n */\nexport function fft(real: Float32Array, imag: Float32Array): void {\n const n = real.length;\n const f = getFftInstance(n);\n const input = f.createComplexArray();\n const out = getComplexBuffer(n);\n\n for (let i = 0; i < n; i++) {\n input[i * 2] = real[i];\n input[i * 2 + 1] = imag[i];\n }\n\n f.transform(out, input);\n\n for (let i = 0; i < n; i++) {\n real[i] = out[i * 2];\n imag[i] = out[i * 2 + 1];\n }\n}\n\n/**\n * Fused FFT → magnitude → decibels for real-valued input.\n * Uses fft.js realTransform (radix-4, ~25% faster for real input).\n * Writes dB values for positive frequencies (n/2 bins) into `out`.\n *\n * @param real - Real input (windowed audio frame, length n)\n * @param out - Output array for dB values (length >= n/2)\n */\nexport function fftMagnitudeDb(real: Float32Array, out: Float32Array): void {\n const n = real.length;\n const f = getFftInstance(n);\n const complexOut = getComplexBuffer(n);\n\n f.realTransform(complexOut, real);\n\n const half = n >> 1;\n for (let i = 0; i < half; i++) {\n const re = complexOut[i * 2];\n const im = complexOut[i * 2 + 1];\n let db = 20 * Math.log10(Math.sqrt(re * re + im * im) + 1e-10);\n if (db < -160) db = -160;\n out[i] = db;\n }\n}\n\n/**\n * Compute magnitude spectrum from FFT output.\n * Returns only the first half (positive frequencies).\n */\nexport function magnitudeSpectrum(real: Float32Array, imag: Float32Array): Float32Array {\n const n = real.length >> 1;\n const magnitudes = new Float32Array(n);\n for (let i = 0; i < n; i++) {\n magnitudes[i] = Math.sqrt(real[i] * real[i] + imag[i] * imag[i]);\n }\n return magnitudes;\n}\n\n/**\n * Convert magnitudes to decibels with a fixed -160 dB floor.\n * Gain is applied at render time, not during FFT.\n */\nexport function toDecibels(magnitudes: Float32Array): Float32Array {\n const result = new Float32Array(magnitudes.length);\n for (let i = 0; i < magnitudes.length; i++) {\n let db = 20 * Math.log10(magnitudes[i] + 1e-10);\n if (db < -160) db = -160;\n result[i] = db;\n }\n return result;\n}\n","/**\n * Window functions for spectral analysis.\n *\n * Uses periodic (DFT-even) windows where the denominator is N, not N-1.\n * Periodic windows tile perfectly over consecutive FFT frames, giving better\n * frequency resolution in STFT/spectrogram computation. This matches the\n * convention used by Audacity, SciPy (sym=False), and MATLAB ('periodic').\n */\n\nexport function getWindowFunction(name: string, size: number, alpha?: number): Float32Array {\n const window = new Float32Array(size);\n const N = size;\n\n switch (name) {\n case 'rectangular':\n for (let i = 0; i < size; i++) window[i] = 1;\n break;\n\n case 'bartlett':\n for (let i = 0; i < size; i++) {\n window[i] = 1 - Math.abs((2 * i - N) / N);\n }\n break;\n\n case 'hann':\n for (let i = 0; i < size; i++) {\n window[i] = 0.5 * (1 - Math.cos((2 * Math.PI * i) / N));\n }\n break;\n\n case 'hamming':\n for (let i = 0; i < size; i++) {\n const a = alpha ?? 0.54;\n window[i] = a - (1 - a) * Math.cos((2 * Math.PI * i) / N);\n }\n break;\n\n case 'blackman': {\n const a0 = 0.42;\n const a1 = 0.5;\n const a2 = 0.08;\n for (let i = 0; i < size; i++) {\n window[i] =\n a0 - a1 * Math.cos((2 * Math.PI * i) / N) + a2 * Math.cos((4 * Math.PI * i) / N);\n }\n break;\n }\n\n case 'blackman-harris': {\n const c0 = 0.35875;\n const c1 = 0.48829;\n const c2 = 0.14128;\n const c3 = 0.01168;\n for (let i = 0; i < size; i++) {\n window[i] =\n c0 -\n c1 * Math.cos((2 * Math.PI * i) / N) +\n c2 * Math.cos((4 * Math.PI * i) / N) -\n c3 * Math.cos((6 * Math.PI * i) / N);\n }\n break;\n }\n\n default:\n console.warn(`[spectrogram] Unknown window function \"${name}\", falling back to hann`);\n for (let i = 0; i < size; i++) {\n window[i] = 0.5 * (1 - Math.cos((2 * Math.PI * i) / N));\n }\n }\n\n // Amplitude normalization: scale so a 0 dB sine produces a 0 dB spectrum peak.\n // Matches Audacity: scale = 2.0 / sum(window)\n let sum = 0;\n for (let i = 0; i < size; i++) sum += window[i];\n if (sum > 0) {\n const scale = 2.0 / sum;\n for (let i = 0; i < size; i++) window[i] *= scale;\n }\n\n return window;\n}\n","/**\n * Compute spectrogram data from an AudioBuffer.\n */\n\nimport type { SpectrogramConfig, SpectrogramData } from '@waveform-playlist/core';\nimport { fftMagnitudeDb } from './fft';\nimport { getWindowFunction } from './windowFunctions';\n\n/**\n * Compute spectrogram for a single channel of audio.\n *\n * @param audioBuffer - Source audio buffer\n * @param config - Spectrogram configuration\n * @param offsetSamples - Start offset into the audio buffer\n * @param durationSamples - Number of samples to process\n * @param channel - Channel index (0 = left, 1 = right). Default: 0\n */\nexport function computeSpectrogram(\n audioBuffer: AudioBuffer,\n config: SpectrogramConfig = {},\n offsetSamples: number = 0,\n durationSamples?: number,\n channel: number = 0\n): SpectrogramData {\n const windowSize = config.fftSize ?? 2048;\n const zeroPaddingFactor = config.zeroPaddingFactor ?? 2;\n const actualFftSize = windowSize * zeroPaddingFactor;\n const hopSize = config.hopSize ?? Math.floor(windowSize / 4);\n const windowName = config.windowFunction ?? 'hann';\n const gainDb = config.gainDb ?? 20;\n const rangeDb = config.rangeDb ?? 80;\n const alpha = config.alpha;\n\n const sampleRate = audioBuffer.sampleRate;\n const frequencyBinCount = actualFftSize >> 1;\n const totalSamples = durationSamples ?? audioBuffer.length - offsetSamples;\n\n // Get channel data\n const channelIdx = Math.min(channel, audioBuffer.numberOfChannels - 1);\n const channelData = audioBuffer.getChannelData(channelIdx);\n\n // Pre-compute window (at windowSize, not actualFftSize)\n const window = getWindowFunction(windowName, windowSize, alpha);\n\n // Calculate frame count (step by windowSize, not actualFftSize)\n const frameCount = Math.max(1, Math.floor((totalSamples - windowSize) / hopSize) + 1);\n\n // Output: frameCount × frequencyBinCount\n const data = new Float32Array(frameCount * frequencyBinCount);\n\n // Reusable buffers at actualFftSize\n const real = new Float32Array(actualFftSize);\n const dbBuf = new Float32Array(frequencyBinCount);\n\n for (let frame = 0; frame < frameCount; frame++) {\n const start = offsetSamples + frame * hopSize;\n\n // Fill first windowSize samples with windowed audio, rest stays zero\n for (let i = 0; i < windowSize; i++) {\n const sampleIdx = start + i;\n real[i] = sampleIdx < channelData.length ? channelData[sampleIdx] * window[i] : 0;\n }\n // Zero-pad the rest\n for (let i = windowSize; i < actualFftSize; i++) {\n real[i] = 0;\n }\n\n fftMagnitudeDb(real, dbBuf);\n data.set(dbBuf, frame * frequencyBinCount);\n }\n\n return {\n fftSize: actualFftSize,\n windowSize,\n frequencyBinCount,\n sampleRate,\n hopSize,\n frameCount,\n data,\n gainDb,\n rangeDb,\n };\n}\n\n/**\n * Compute a mono (mixed-down) spectrogram from all channels.\n */\nexport function computeSpectrogramMono(\n audioBuffer: AudioBuffer,\n config: SpectrogramConfig = {},\n offsetSamples: number = 0,\n durationSamples?: number\n): SpectrogramData {\n if (audioBuffer.numberOfChannels === 1) {\n return computeSpectrogram(audioBuffer, config, offsetSamples, durationSamples, 0);\n }\n\n // Mix down channels\n const windowSize = config.fftSize ?? 2048;\n const zeroPaddingFactor = config.zeroPaddingFactor ?? 2;\n const actualFftSize = windowSize * zeroPaddingFactor;\n const hopSize = config.hopSize ?? Math.floor(windowSize / 4);\n const windowName = config.windowFunction ?? 'hann';\n const gainDb = config.gainDb ?? 20;\n const rangeDb = config.rangeDb ?? 80;\n const alpha = config.alpha;\n\n const sampleRate = audioBuffer.sampleRate;\n const frequencyBinCount = actualFftSize >> 1;\n const totalSamples = durationSamples ?? audioBuffer.length - offsetSamples;\n const numChannels = audioBuffer.numberOfChannels;\n\n const window = getWindowFunction(windowName, windowSize, alpha);\n const frameCount = Math.max(1, Math.floor((totalSamples - windowSize) / hopSize) + 1);\n const data = new Float32Array(frameCount * frequencyBinCount);\n const real = new Float32Array(actualFftSize);\n const dbBuf = new Float32Array(frequencyBinCount);\n\n // Get all channel data\n const channels: Float32Array[] = [];\n for (let ch = 0; ch < numChannels; ch++) {\n channels.push(audioBuffer.getChannelData(ch));\n }\n\n for (let frame = 0; frame < frameCount; frame++) {\n const start = offsetSamples + frame * hopSize;\n\n // Mix channels and apply window\n for (let i = 0; i < windowSize; i++) {\n const sampleIdx = start + i;\n let sum = 0;\n for (let ch = 0; ch < numChannels; ch++) {\n sum += sampleIdx < channels[ch].length ? channels[ch][sampleIdx] : 0;\n }\n real[i] = (sum / numChannels) * window[i];\n }\n // Zero-pad the rest\n for (let i = windowSize; i < actualFftSize; i++) {\n real[i] = 0;\n }\n\n fftMagnitudeDb(real, dbBuf);\n data.set(dbBuf, frame * frequencyBinCount);\n }\n\n return {\n fftSize: actualFftSize,\n windowSize,\n frequencyBinCount,\n sampleRate,\n hopSize,\n frameCount,\n data,\n gainDb,\n rangeDb,\n };\n}\n","/**\n * Color maps for spectrogram rendering.\n * Each map is a 256-entry RGB lookup table (768 bytes).\n *\n * Viridis, Magma, Inferno: Perceptually uniform colormaps from matplotlib.\n * By Stéfan van der Walt, Nathaniel Smith, and Eric Firing. Released under CC0.\n * Data from https://github.com/BIDS/colormap\n *\n * Roseus: Perceptually uniform colormap from https://github.com/dofuuz/roseus\n * By dofuuz, licensed under CC0 1.0 Universal.\n */\n\nimport type { ColorMapValue } from '@waveform-playlist/core';\n\n// Pre-computed 256-entry LUT: Uint8Array of length 768 (256 * 3 RGB)\ntype ColorLUT = Uint8Array;\n\nfunction interpolateLUT(stops: number[][]): ColorLUT {\n const lut = new Uint8Array(256 * 3);\n const n = stops.length;\n for (let i = 0; i < 256; i++) {\n const t = i / 255;\n const pos = t * (n - 1);\n const lo = Math.floor(pos);\n const hi = Math.min(lo + 1, n - 1);\n const frac = pos - lo;\n lut[i * 3] = Math.round(stops[lo][0] * (1 - frac) + stops[hi][0] * frac);\n lut[i * 3 + 1] = Math.round(stops[lo][1] * (1 - frac) + stops[hi][1] * frac);\n lut[i * 3 + 2] = Math.round(stops[lo][2] * (1 - frac) + stops[hi][2] * frac);\n }\n return lut;\n}\n\n// prettier-ignore\nconst VIRIDIS_LUT = new Uint8Array([\n 68, 1, 84, 68, 2, 86, 69, 4, 87, 69, 5, 89, 70, 7, 90, 70, 8, 92, 70, 10, 93, 70, 11, 94,\n 71, 13, 96, 71, 14, 97, 71, 16, 99, 71, 17, 100, 71, 19, 101, 72, 20, 103, 72, 22, 104, 72, 23, 105,\n 72, 24, 106, 72, 26, 108, 72, 27, 109, 72, 28, 110, 72, 29, 111, 72, 31, 112, 72, 32, 113, 72, 33, 115,\n 72, 35, 116, 72, 36, 117, 72, 37, 118, 72, 38, 119, 72, 40, 120, 72, 41, 121, 71, 42, 122, 71, 44, 122,\n 71, 45, 123, 71, 46, 124, 71, 47, 125, 70, 48, 126, 70, 50, 126, 70, 51, 127, 70, 52, 128, 69, 53, 129,\n 69, 55, 129, 69, 56, 130, 68, 57, 131, 68, 58, 131, 68, 59, 132, 67, 61, 132, 67, 62, 133, 66, 63, 133,\n 66, 64, 134, 66, 65, 134, 65, 66, 135, 65, 68, 135, 64, 69, 136, 64, 70, 136, 63, 71, 136, 63, 72, 137,\n 62, 73, 137, 62, 74, 137, 62, 76, 138, 61, 77, 138, 61, 78, 138, 60, 79, 138, 60, 80, 139, 59, 81, 139,\n 59, 82, 139, 58, 83, 139, 58, 84, 140, 57, 85, 140, 57, 86, 140, 56, 88, 140, 56, 89, 140, 55, 90, 140,\n 55, 91, 141, 54, 92, 141, 54, 93, 141, 53, 94, 141, 53, 95, 141, 52, 96, 141, 52, 97, 141, 51, 98, 141,\n 51, 99, 141, 50, 100, 142, 50, 101, 142, 49, 102, 142, 49, 103, 142, 49, 104, 142, 48, 105, 142, 48, 106, 142,\n 47, 107, 142, 47, 108, 142, 46, 109, 142, 46, 110, 142, 46, 111, 142, 45, 112, 142, 45, 113, 142, 44, 113, 142,\n 44, 114, 142, 44, 115, 142, 43, 116, 142, 43, 117, 142, 42, 118, 142, 42, 119, 142, 42, 120, 142, 41, 121, 142,\n 41, 122, 142, 41, 123, 142, 40, 124, 142, 40, 125, 142, 39, 126, 142, 39, 127, 142, 39, 128, 142, 38, 129, 142,\n 38, 130, 142, 38, 130, 142, 37, 131, 142, 37, 132, 142, 37, 133, 142, 36, 134, 142, 36, 135, 142, 35, 136, 142,\n 35, 137, 142, 35, 138, 141, 34, 139, 141, 34, 140, 141, 34, 141, 141, 33, 142, 141, 33, 143, 141, 33, 144, 141,\n 33, 145, 140, 32, 146, 140, 32, 146, 140, 32, 147, 140, 31, 148, 140, 31, 149, 139, 31, 150, 139, 31, 151, 139,\n 31, 152, 139, 31, 153, 138, 31, 154, 138, 30, 155, 138, 30, 156, 137, 30, 157, 137, 31, 158, 137, 31, 159, 136,\n 31, 160, 136, 31, 161, 136, 31, 161, 135, 31, 162, 135, 32, 163, 134, 32, 164, 134, 33, 165, 133, 33, 166, 133,\n 34, 167, 133, 34, 168, 132, 35, 169, 131, 36, 170, 131, 37, 171, 130, 37, 172, 130, 38, 173, 129, 39, 173, 129,\n 40, 174, 128, 41, 175, 127, 42, 176, 127, 44, 177, 126, 45, 178, 125, 46, 179, 124, 47, 180, 124, 49, 181, 123,\n 50, 182, 122, 52, 182, 121, 53, 183, 121, 55, 184, 120, 56, 185, 119, 58, 186, 118, 59, 187, 117, 61, 188, 116,\n 63, 188, 115, 64, 189, 114, 66, 190, 113, 68, 191, 112, 70, 192, 111, 72, 193, 110, 74, 193, 109, 76, 194, 108,\n 78, 195, 107, 80, 196, 106, 82, 197, 105, 84, 197, 104, 86, 198, 103, 88, 199, 101, 90, 200, 100, 92, 200, 99,\n 94, 201, 98, 96, 202, 96, 99, 203, 95, 101, 203, 94, 103, 204, 92, 105, 205, 91, 108, 205, 90, 110, 206, 88,\n 112, 207, 87, 115, 208, 86, 117, 208, 84, 119, 209, 83, 122, 209, 81, 124, 210, 80, 127, 211, 78, 129, 211, 77,\n 132, 212, 75, 134, 213, 73, 137, 213, 72, 139, 214, 70, 142, 214, 69, 144, 215, 67, 147, 215, 65, 149, 216, 64,\n 152, 216, 62, 155, 217, 60, 157, 217, 59, 160, 218, 57, 162, 218, 55, 165, 219, 54, 168, 219, 52, 170, 220, 50,\n 173, 220, 48, 176, 221, 47, 178, 221, 45, 181, 222, 43, 184, 222, 41, 186, 222, 40, 189, 223, 38, 192, 223, 37,\n 194, 223, 35, 197, 224, 33, 200, 224, 32, 202, 225, 31, 205, 225, 29, 208, 225, 28, 210, 226, 27, 213, 226, 26,\n 216, 226, 25, 218, 227, 25, 221, 227, 24, 223, 227, 24, 226, 228, 24, 229, 228, 25, 231, 228, 25, 234, 229, 26,\n 236, 229, 27, 239, 229, 28, 241, 229, 29, 244, 230, 30, 246, 230, 32, 248, 230, 33, 251, 231, 35, 253, 231, 37,\n]);\n\n// prettier-ignore\nconst MAGMA_LUT = new Uint8Array([\n 0, 0, 4, 1, 0, 5, 1, 1, 6, 1, 1, 8, 2, 1, 9, 2, 2, 11, 2, 2, 13, 3, 3, 15,\n 3, 3, 18, 4, 4, 20, 5, 4, 22, 6, 5, 24, 6, 5, 26, 7, 6, 28, 8, 7, 30, 9, 7, 32,\n 10, 8, 34, 11, 9, 36, 12, 9, 38, 13, 10, 41, 14, 11, 43, 16, 11, 45, 17, 12, 47, 18, 13, 49,\n 19, 13, 52, 20, 14, 54, 21, 14, 56, 22, 15, 59, 24, 15, 61, 25, 16, 63, 26, 16, 66, 28, 16, 68,\n 29, 17, 71, 30, 17, 73, 32, 17, 75, 33, 17, 78, 34, 17, 80, 36, 18, 83, 37, 18, 85, 39, 18, 88,\n 41, 17, 90, 42, 17, 92, 44, 17, 95, 45, 17, 97, 47, 17, 99, 49, 17, 101, 51, 16, 103, 52, 16, 105,\n 54, 16, 107, 56, 16, 108, 57, 15, 110, 59, 15, 112, 61, 15, 113, 63, 15, 114, 64, 15, 116, 66, 15, 117,\n 68, 15, 118, 69, 16, 119, 71, 16, 120, 73, 16, 120, 74, 16, 121, 76, 17, 122, 78, 17, 123, 79, 18, 123,\n 81, 18, 124, 82, 19, 124, 84, 19, 125, 86, 20, 125, 87, 21, 126, 89, 21, 126, 90, 22, 126, 92, 22, 127,\n 93, 23, 127, 95, 24, 127, 96, 24, 128, 98, 25, 128, 100, 26, 128, 101, 26, 128, 103, 27, 128, 104, 28, 129,\n 106, 28, 129, 107, 29, 129, 109, 29, 129, 110, 30, 129, 112, 31, 129, 114, 31, 129, 115, 32, 129, 117, 33, 129,\n 118, 33, 129, 120, 34, 129, 121, 34, 130, 123, 35, 130, 124, 35, 130, 126, 36, 130, 128, 37, 130, 129, 37, 129,\n 131, 38, 129, 132, 38, 129, 134, 39, 129, 136, 39, 129, 137, 40, 129, 139, 41, 129, 140, 41, 129, 142, 42, 129,\n 144, 42, 129, 145, 43, 129, 147, 43, 128, 148, 44, 128, 150, 44, 128, 152, 45, 128, 153, 45, 128, 155, 46, 127,\n 156, 46, 127, 158, 47, 127, 160, 47, 127, 161, 48, 126, 163, 48, 126, 165, 49, 126, 166, 49, 125, 168, 50, 125,\n 170, 51, 125, 171, 51, 124, 173, 52, 124, 174, 52, 123, 176, 53, 123, 178, 53, 123, 179, 54, 122, 181, 54, 122,\n 183, 55, 121, 184, 55, 121, 186, 56, 120, 188, 57, 120, 189, 57, 119, 191, 58, 119, 192, 58, 118, 194, 59, 117,\n 196, 60, 117, 197, 60, 116, 199, 61, 115, 200, 62, 115, 202, 62, 114, 204, 63, 113, 205, 64, 113, 207, 64, 112,\n 208, 65, 111, 210, 66, 111, 211, 67, 110, 213, 68, 109, 214, 69, 108, 216, 69, 108, 217, 70, 107, 219, 71, 106,\n 220, 72, 105, 222, 73, 104, 223, 74, 104, 224, 76, 103, 226, 77, 102, 227, 78, 101, 228, 79, 100, 229, 80, 100,\n 231, 82, 99, 232, 83, 98, 233, 84, 98, 234, 86, 97, 235, 87, 96, 236, 88, 96, 237, 90, 95, 238, 91, 94,\n 239, 93, 94, 240, 95, 94, 241, 96, 93, 242, 98, 93, 242, 100, 92, 243, 101, 92, 244, 103, 92, 244, 105, 92,\n 245, 107, 92, 246, 108, 92, 246, 110, 92, 247, 112, 92, 247, 114, 92, 248, 116, 92, 248, 118, 92, 249, 120, 93,\n 249, 121, 93, 249, 123, 93, 250, 125, 94, 250, 127, 94, 250, 129, 95, 251, 131, 95, 251, 133, 96, 251, 135, 97,\n 252, 137, 97, 252, 138, 98, 252, 140, 99, 252, 142, 100, 252, 144, 101, 253, 146, 102, 253, 148, 103, 253, 150, 104,\n 253, 152, 105, 253, 154, 106, 253, 155, 107, 254, 157, 108, 254, 159, 109, 254, 161, 110, 254, 163, 111, 254, 165, 113,\n 254, 167, 114, 254, 169, 115, 254, 170, 116, 254, 172, 118, 254, 174, 119, 254, 176, 120, 254, 178, 122, 254, 180, 123,\n 254, 182, 124, 254, 183, 126, 254, 185, 127, 254, 187, 129, 254, 189, 130, 254, 191, 132, 254, 193, 133, 254, 194, 135,\n 254, 196, 136, 254, 198, 138, 254, 200, 140, 254, 202, 141, 254, 204, 143, 254, 205, 144, 254, 207, 146, 254, 209, 148,\n 254, 211, 149, 254, 213, 151, 254, 215, 153, 254, 216, 154, 253, 218, 156, 253, 220, 158, 253, 222, 160, 253, 224, 161,\n 253, 226, 163, 253, 227, 165, 253, 229, 167, 253, 231, 169, 253, 233, 170, 253, 235, 172, 252, 236, 174, 252, 238, 176,\n 252, 240, 178, 252, 242, 180, 252, 244, 182, 252, 246, 184, 252, 247, 185, 252, 249, 187, 252, 251, 189, 252, 253, 191,\n]);\n\n// prettier-ignore\nconst INFERNO_LUT = new Uint8Array([\n 0, 0, 4, 1, 0, 5, 1, 1, 6, 1, 1, 8, 2, 1, 10, 2, 2, 12, 2, 2, 14, 3, 2, 16,\n 4, 3, 18, 4, 3, 20, 5, 4, 23, 6, 4, 25, 7, 5, 27, 8, 5, 29, 9, 6, 31, 10, 7, 34,\n 11, 7, 36, 12, 8, 38, 13, 8, 41, 14, 9, 43, 16, 9, 45, 17, 10, 48, 18, 10, 50, 20, 11, 52,\n 21, 11, 55, 22, 11, 57, 24, 12, 60, 25, 12, 62, 27, 12, 65, 28, 12, 67, 30, 12, 69, 31, 12, 72,\n 33, 12, 74, 35, 12, 76, 36, 12, 79, 38, 12, 81, 40, 11, 83, 41, 11, 85, 43, 11, 87, 45, 11, 89,\n 47, 10, 91, 49, 10, 92, 50, 10, 94, 52, 10, 95, 54, 9, 97, 56, 9, 98, 57, 9, 99, 59, 9, 100,\n 61, 9, 101, 62, 9, 102, 64, 10, 103, 66, 10, 104, 68, 10, 104, 69, 10, 105, 71, 11, 106, 73, 11, 106,\n 74, 12, 107, 76, 12, 107, 77, 13, 108, 79, 13, 108, 81, 14, 108, 82, 14, 109, 84, 15, 109, 85, 15, 109,\n 87, 16, 110, 89, 16, 110, 90, 17, 110, 92, 18, 110, 93, 18, 110, 95, 19, 110, 97, 19, 110, 98, 20, 110,\n 100, 21, 110, 101, 21, 110, 103, 22, 110, 105, 22, 110, 106, 23, 110, 108, 24, 110, 109, 24, 110, 111, 25, 110,\n 113, 25, 110, 114, 26, 110, 116, 26, 110, 117, 27, 110, 119, 28, 109, 120, 28, 109, 122, 29, 109, 124, 29, 109,\n 125, 30, 109, 127, 30, 108, 128, 31, 108, 130, 32, 108, 132, 32, 107, 133, 33, 107, 135, 33, 107, 136, 34, 106,\n 138, 34, 106, 140, 35, 105, 141, 35, 105, 143, 36, 105, 144, 37, 104, 146, 37, 104, 147, 38, 103, 149, 38, 103,\n 151, 39, 102, 152, 39, 102, 154, 40, 101, 155, 41, 100, 157, 41, 100, 159, 42, 99, 160, 42, 99, 162, 43, 98,\n 163, 44, 97, 165, 44, 96, 166, 45, 96, 168, 46, 95, 169, 46, 94, 171, 47, 94, 173, 48, 93, 174, 48, 92,\n 176, 49, 91, 177, 50, 90, 179, 50, 90, 180, 51, 89, 182, 52, 88, 183, 53, 87, 185, 53, 86, 186, 54, 85,\n 188, 55, 84, 189, 56, 83, 191, 57, 82, 192, 58, 81, 193, 58, 80, 195, 59, 79, 196, 60, 78, 198, 61, 77,\n 199, 62, 76, 200, 63, 75, 202, 64, 74, 203, 65, 73, 204, 66, 72, 206, 67, 71, 207, 68, 70, 208, 69, 69,\n 210, 70, 68, 211, 71, 67, 212, 72, 66, 213, 74, 65, 215, 75, 63, 216, 76, 62, 217, 77, 61, 218, 78, 60,\n 219, 80, 59, 221, 81, 58, 222, 82, 56, 223, 83, 55, 224, 85, 54, 225, 86, 53, 226, 87, 52, 227, 89, 51,\n 228, 90, 49, 229, 92, 48, 230, 93, 47, 231, 94, 46, 232, 96, 45, 233, 97, 43, 234, 99, 42, 235, 100, 41,\n 235, 102, 40, 236, 103, 38, 237, 105, 37, 238, 106, 36, 239, 108, 35, 239, 110, 33, 240, 111, 32, 241, 113, 31,\n 241, 115, 29, 242, 116, 28, 243, 118, 27, 243, 120, 25, 244, 121, 24, 245, 123, 23, 245, 125, 21, 246, 126, 20,\n 246, 128, 19, 247, 130, 18, 247, 132, 16, 248, 133, 15, 248, 135, 14, 248, 137, 12, 249, 139, 11, 249, 140, 10,\n 249, 142, 9, 250, 144, 8, 250, 146, 7, 250, 148, 7, 251, 150, 6, 251, 151, 6, 251, 153, 6, 251, 155, 6,\n 251, 157, 7, 252, 159, 7, 252, 161, 8, 252, 163, 9, 252, 165, 10, 252, 166, 12, 252, 168, 13, 252, 170, 15,\n 252, 172, 17, 252, 174, 18, 252, 176, 20, 252, 178, 22, 252, 180, 24, 251, 182, 26, 251, 184, 29, 251, 186, 31,\n 251, 188, 33, 251, 190, 35, 250, 192, 38, 250, 194, 40, 250, 196, 42, 250, 198, 45, 249, 199, 47, 249, 201, 50,\n 249, 203, 53, 248, 205, 55, 248, 207, 58, 247, 209, 61, 247, 211, 64, 246, 213, 67, 246, 215, 70, 245, 217, 73,\n 245, 219, 76, 244, 221, 79, 244, 223, 83, 244, 225, 86, 243, 227, 90, 243, 229, 93, 242, 230, 97, 242, 232, 101,\n 242, 234, 105, 241, 236, 109, 241, 237, 113, 241, 239, 117, 241, 241, 121, 242, 242, 125, 242, 244, 130, 243, 245, 134,\n 243, 246, 138, 244, 248, 142, 245, 249, 146, 246, 250, 150, 248, 251, 154, 249, 252, 157, 250, 253, 161, 252, 255, 164,\n]);\n\n// prettier-ignore\nconst ROSEUS_LUT = new Uint8Array([\n 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 3, 3, 2, 3, 4, 2, 4, 5, 2, 5, 6, 3, 6, 7,\n 3, 7, 8, 3, 8, 10, 3, 9, 12, 3, 10, 14, 3, 12, 16, 3, 13, 17, 3, 14, 19, 2, 15, 21,\n 2, 16, 23, 2, 17, 25, 2, 18, 27, 2, 19, 30, 1, 20, 32, 1, 21, 34, 1, 22, 36, 1, 23, 38,\n 1, 24, 40, 0, 25, 43, 0, 26, 45, 0, 27, 47, 0, 27, 50, 0, 28, 52, 0, 29, 54, 0, 30, 57,\n 0, 30, 59, 1, 31, 62, 1, 32, 64, 1, 32, 67, 2, 33, 69, 3, 33, 72, 4, 34, 74, 5, 35, 77,\n 6, 35, 79, 8, 35, 82, 9, 36, 84, 11, 36, 86, 13, 37, 89, 15, 37, 91, 17, 37, 94, 19, 37, 96,\n 21, 38, 99, 23, 38, 101, 25, 38, 104, 27, 38, 106, 29, 38, 108, 31, 38, 111, 33, 38, 113, 35, 38, 115,\n 38, 38, 118, 40, 38, 120, 42, 38, 122, 44, 38, 124, 46, 38, 126, 49, 38, 128, 51, 38, 130, 53, 37, 132,\n 55, 37, 134, 58, 37, 136, 60, 36, 138, 62, 36, 139, 65, 36, 141, 67, 35, 143, 69, 35, 144, 72, 35, 146,\n 74, 34, 147, 76, 34, 149, 79, 33, 150, 81, 33, 151, 84, 32, 152, 86, 32, 153, 88, 31, 154, 91, 31, 155,\n 93, 30, 156, 95, 29, 157, 98, 29, 158, 100, 28, 159, 103, 28, 159, 105, 27, 160, 107, 27, 160, 110, 26, 161,\n 112, 26, 161, 114, 25, 161, 117, 25, 162, 119, 24, 162, 121, 24, 162, 124, 23, 162, 126, 23, 162, 128, 23, 162,\n 131, 22, 161, 133, 22, 161, 135, 22, 161, 137, 22, 161, 140, 22, 160, 142, 22, 160, 144, 22, 159, 146, 22, 159,\n 148, 22, 158, 150, 22, 157, 153, 22, 157, 155, 23, 156, 157, 23, 155, 159, 23, 154, 161, 24, 153, 163, 24, 152,\n 165, 25, 151, 167, 26, 150, 169, 26, 149, 171, 27, 148, 173, 28, 147, 175, 29, 146, 177, 29, 145, 179, 30, 144,\n 181, 31, 142, 183, 32, 141, 184, 33, 140, 186, 34, 139, 188, 35, 137, 190, 36, 136, 192, 37, 135, 193, 39, 133,\n 195, 40, 132, 197, 41, 130, 198, 42, 129, 200, 43, 128, 202, 45, 126, 203, 46, 125, 205, 47, 123, 206, 48, 122,\n 208, 50, 120, 209, 51, 119, 211, 52, 117, 212, 54, 116, 214, 55, 114, 215, 57, 113, 217, 58, 111, 218, 60, 110,\n 219, 61, 109, 221, 63, 107, 222, 64, 106, 223, 66, 104, 225, 67, 103, 226, 69, 101, 227, 70, 100, 228, 72, 99,\n 229, 73, 97, 230, 75, 96, 231, 77, 94, 233, 78, 93, 234, 80, 92, 235, 82, 91, 236, 83, 89, 237, 85, 88,\n 237, 87, 87, 238, 89, 86, 239, 90, 84, 240, 92, 83, 241, 94, 82, 242, 96, 81, 242, 97, 80, 243, 99, 79,\n 244, 101, 78, 245, 103, 77, 245, 105, 76, 246, 107, 75, 246, 108, 74, 247, 110, 74, 248, 112, 73, 248, 114, 72,\n 248, 116, 72, 249, 118, 71, 249, 120, 71, 250, 122, 70, 250, 124, 70, 250, 126, 70, 251, 128, 70, 251, 130, 69,\n 251, 132, 70, 251, 134, 70, 251, 136, 70, 252, 138, 70, 252, 140, 70, 252, 142, 71, 252, 144, 72, 252, 146, 72,\n 252, 148, 73, 252, 150, 74, 251, 152, 75, 251, 154, 76, 251, 156, 77, 251, 158, 78, 251, 160, 80, 251, 162, 81,\n 250, 164, 83, 250, 166, 85, 250, 168, 87, 249, 170, 88, 249, 172, 90, 248, 174, 93, 248, 176, 95, 248, 178, 97,\n 247, 180, 99, 247, 182, 102, 246, 184, 104, 246, 186, 107, 245, 188, 110, 244, 190, 112, 244, 192, 115, 243, 194, 118,\n 243, 195, 121, 242, 197, 124, 242, 199, 127, 241, 201, 131, 240, 203, 134, 240, 205, 137, 239, 207, 140, 239, 208, 144,\n 238, 210, 147, 238, 212, 151, 237, 213, 154, 237, 215, 158, 236, 217, 161, 236, 218, 165, 236, 220, 169, 236, 222, 172,\n 235, 223, 176, 235, 225, 180, 235, 226, 183, 235, 228, 187, 235, 229, 191, 235, 230, 194, 236, 232, 198, 236, 233, 201,\n 236, 234, 205, 237, 236, 208, 237, 237, 212, 238, 238, 215, 239, 239, 219, 240, 240, 222, 241, 242, 225, 242, 243, 228,\n 243, 244, 231, 244, 245, 234, 246, 246, 237, 247, 247, 240, 249, 248, 242, 251, 249, 245, 253, 250, 247, 254, 251, 249,\n]);\n\nconst lutCache = new Map<string, ColorLUT>();\n\nfunction grayscaleLUT(): ColorLUT {\n let lut = lutCache.get('grayscale');\n if (!lut) {\n lut = new Uint8Array(256 * 3);\n for (let i = 0; i < 256; i++) {\n lut[i * 3] = lut[i * 3 + 1] = lut[i * 3 + 2] = i;\n }\n lutCache.set('grayscale', lut);\n }\n return lut;\n}\n\nfunction igrayLUT(): ColorLUT {\n let lut = lutCache.get('igray');\n if (!lut) {\n lut = new Uint8Array(256 * 3);\n for (let i = 0; i < 256; i++) {\n const v = 255 - i;\n lut[i * 3] = lut[i * 3 + 1] = lut[i * 3 + 2] = v;\n }\n lutCache.set('igray', lut);\n }\n return lut;\n}\n\n/**\n * Get a 256-entry RGB LUT for the given color map.\n */\nexport function getColorMap(value: ColorMapValue): ColorLUT {\n if (Array.isArray(value)) {\n return interpolateLUT(value);\n }\n\n switch (value) {\n case 'viridis':\n return VIRIDIS_LUT;\n case 'magma':\n return MAGMA_LUT;\n case 'inferno':\n return INFERNO_LUT;\n case 'roseus':\n return ROSEUS_LUT;\n case 'grayscale':\n return grayscaleLUT();\n case 'igray':\n return igrayLUT();\n default:\n return VIRIDIS_LUT;\n }\n}\n","/**\n * Frequency scale mapping functions.\n * Each maps a frequency (Hz) to a normalized position [0, 1].\n */\n\nfunction linearScale(f: number, minF: number, maxF: number): number {\n if (maxF === minF) return 0;\n return (f - minF) / (maxF - minF);\n}\n\nfunction logarithmicScale(f: number, minF: number, maxF: number): number {\n const logMin = Math.log2(Math.max(minF, 1));\n const logMax = Math.log2(maxF);\n if (logMax === logMin) return 0;\n return (Math.log2(Math.max(f, 1)) - logMin) / (logMax - logMin);\n}\n\nfunction hzToMel(f: number): number {\n return 2595 * Math.log10(1 + f / 700);\n}\n\nfunction melScale(f: number, minF: number, maxF: number): number {\n const melMin = hzToMel(minF);\n const melMax = hzToMel(maxF);\n if (melMax === melMin) return 0;\n return (hzToMel(f) - melMin) / (melMax - melMin);\n}\n\nfunction hzToBark(f: number): number {\n return 13 * Math.atan(0.00076 * f) + 3.5 * Math.atan((f / 7500) ** 2);\n}\n\nfunction barkScale(f: number, minF: number, maxF: number): number {\n const barkMin = hzToBark(minF);\n const barkMax = hzToBark(maxF);\n if (barkMax === barkMin) return 0;\n return (hzToBark(f) - barkMin) / (barkMax - barkMin);\n}\n\nfunction hzToErb(f: number): number {\n return 21.4 * Math.log10(1 + 0.00437 * f);\n}\n\nfunction erbScale(f: number, minF: number, maxF: number): number {\n const erbMin = hzToErb(minF);\n const erbMax = hzToErb(maxF);\n if (erbMax === erbMin) return 0;\n return (hzToErb(f) - erbMin) / (erbMax - erbMin);\n}\n\nexport type FrequencyScaleName = 'linear' | 'logarithmic' | 'mel' | 'bark' | 'erb';\n\n/**\n * Returns a mapping function: (frequencyHz, minFrequency, maxFrequency) → [0, 1]\n */\nexport function getFrequencyScale(\n name: FrequencyScaleName\n): (f: number, minF: number, maxF: number) => number {\n switch (name) {\n case 'logarithmic':\n return logarithmicScale;\n case 'mel':\n return melScale;\n case 'bark':\n return barkScale;\n case 'erb':\n return erbScale;\n case 'linear':\n return linearScale;\n default:\n console.warn(`[spectrogram] Unknown frequency scale \"${name}\", falling back to linear`);\n return linearScale;\n }\n}\n","import React from 'react';\nimport styled from 'styled-components';\nimport type { RenderMode } from '@waveform-playlist/core';\nimport type { TrackMenuItem } from './types';\n\nconst SectionLabel = styled.div`\n font-size: 0.65rem;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.05em;\n opacity: 0.5;\n margin-bottom: 0.25rem;\n`;\n\nconst RadioLabel = styled.label`\n display: flex;\n align-items: center;\n gap: 0.4rem;\n padding: 0.2rem 0;\n font-size: 0.8rem;\n cursor: pointer;\n\n &:hover {\n opacity: 0.8;\n }\n`;\n\nconst SettingsButton = styled.button`\n background: none;\n border: none;\n color: inherit;\n cursor: pointer;\n font-size: 0.8rem;\n padding: 0.35rem 0.75rem;\n width: 100%;\n text-align: left;\n\n &:hover {\n background: rgba(128, 128, 128, 0.15);\n }\n`;\n\nconst DropdownSection = styled.div`\n padding: 0.25rem 0.75rem;\n`;\n\nconst RENDER_MODES: { value: RenderMode; label: string }[] = [\n { value: 'waveform', label: 'Waveform' },\n { value: 'spectrogram', label: 'Spectrogram' },\n { value: 'both', label: 'Both' },\n];\n\nexport interface SpectrogramMenuItemsProps {\n renderMode: RenderMode;\n onRenderModeChange: (mode: RenderMode) => void;\n onOpenSettings: () => void;\n onClose?: () => void;\n}\n\n/**\n * Returns TrackMenuItem[] for the spectrogram display mode radios and settings button.\n */\nexport function SpectrogramMenuItems({\n renderMode,\n onRenderModeChange,\n onOpenSettings,\n onClose,\n}: SpectrogramMenuItemsProps): TrackMenuItem[] {\n return [\n {\n id: 'spectrogram-display',\n label: 'Display',\n content: (\n <DropdownSection>\n <SectionLabel>Display</SectionLabel>\n {RENDER_MODES.map(({ value, label }) => (\n <RadioLabel key={value}>\n <input\n type=\"radio\"\n name=\"render-mode\"\n checked={renderMode === value}\n onChange={() => {\n onRenderModeChange(value);\n onClose?.();\n }}\n />\n {label}\n </RadioLabel>\n ))}\n </DropdownSection>\n ),\n },\n {\n id: 'spectrogram-settings',\n content: (\n <SettingsButton\n onClick={(e) => {\n e.stopPropagation();\n onClose?.();\n onOpenSettings();\n }}\n onMouseDown={(e) => e.stopPropagation()}\n >\n Spectrogram Settings...\n </SettingsButton>\n ),\n },\n ];\n}\n","import React, { useRef, useEffect, useState } from 'react';\nimport styled from 'styled-components';\nimport type {\n SpectrogramConfig,\n ColorMapValue,\n ColorMapName,\n FFTSize,\n} from '@waveform-playlist/core';\n\nexport interface SpectrogramSettingsModalProps {\n open: boolean;\n onClose: () => void;\n config: SpectrogramConfig;\n colorMap: ColorMapValue;\n onApply: (config: SpectrogramConfig, colorMap: ColorMapValue) => void;\n}\n\nconst StyledDialog = styled.dialog`\n border: 1px solid rgba(128, 128, 128, 0.4);\n border-radius: 8px;\n padding: 1.5rem;\n background: ${(p) => p.theme.timescaleBackgroundColor ?? '#222'};\n color: ${(p) => p.theme.textColor ?? 'inherit'};\n min-width: 380px;\n max-width: 500px;\n\n &::backdrop {\n background: rgba(0, 0, 0, 0.5);\n }\n`;\n\nconst Title = styled.h3`\n margin: 0 0 1rem;\n font-size: 1rem;\n`;\n\nconst FormGrid = styled.div`\n display: grid;\n grid-template-columns: 1fr 1fr;\n gap: 0.75rem;\n`;\n\nconst Field = styled.div<{ $span?: boolean }>`\n display: flex;\n flex-direction: column;\n gap: 0.2rem;\n grid-column: ${(p) => (p.$span ? '1 / -1' : 'auto')};\n`;\n\nconst Label = styled.label`\n font-size: 0.7rem;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.05em;\n opacity: 0.6;\n`;\n\nconst Select = styled.select`\n padding: 0.3rem 0.4rem;\n border: 1px solid rgba(128, 128, 128, 0.4);\n border-radius: 4px;\n background: rgba(128, 128, 128, 0.15);\n color: inherit;\n font-size: 0.85rem;\n`;\n\nconst NumberInput = styled.input`\n padding: 0.3rem 0.4rem;\n border: 1px solid rgba(128, 128, 128, 0.4);\n border-radius: 4px;\n background: rgba(128, 128, 128, 0.15);\n color: inherit;\n font-size: 0.85rem;\n width: 100%;\n box-sizing: border-box;\n`;\n\nconst CheckboxLabel = styled.label`\n display: flex;\n align-items: center;\n gap: 0.4rem;\n font-size: 0.85rem;\n cursor: pointer;\n`;\n\nconst ButtonRow = styled.div`\n display: flex;\n justify-content: flex-end;\n gap: 0.5rem;\n margin-top: 1.25rem;\n`;\n\nconst ModalButton = styled.button<{ $primary?: boolean }>`\n padding: 0.4rem 1rem;\n border: 1px solid rgba(128, 128, 128, 0.4);\n border-radius: 4px;\n cursor: pointer;\n font-size: 0.85rem;\n background: ${(p) => (p.$primary ? 'var(--ifm-color-primary, #4a9)' : 'transparent')};\n color: ${(p) => (p.$primary ? '#fff' : 'inherit')};\n\n &:hover {\n opacity: 0.85;\n }\n`;\n\nconst FFT_SIZES = [256, 512, 1024, 2048, 4096, 8192];\nconst WINDOW_FUNCTIONS = [\n 'hann',\n 'hamming',\n 'blackman',\n 'blackman-harris',\n 'bartlett',\n 'rectangular',\n] as const;\nconst FREQ_SCALES = ['linear', 'logarithmic', 'mel', 'bark', 'erb'] as const;\nconst COLOR_MAPS: ColorMapName[] = ['viridis', 'magma', 'inferno', 'grayscale', 'igray', 'roseus'];\n\nexport const SpectrogramSettingsModal: React.FC<SpectrogramSettingsModalProps> = ({\n open,\n onClose,\n config,\n colorMap,\n onApply,\n}) => {\n const dialogRef = useRef<HTMLDialogElement>(null);\n\n // Local form state\n const [fftSize, setFftSize] = useState(config.fftSize ?? 2048);\n const [windowFn, setWindowFn] = useState(config.windowFunction ?? 'hann');\n const [freqScale, setFreqScale] = useState(config.frequencyScale ?? 'mel');\n const [localColorMap, setLocalColorMap] = useState<ColorMapName>(\n typeof colorMap === 'string' ? colorMap : 'viridis'\n );\n const [minFreq, setMinFreq] = useState(config.minFrequency ?? 0);\n const [maxFreq, setMaxFreq] = useState(config.maxFrequency ?? 20000);\n const [gainDb, setGainDb] = useState(config.gainDb ?? 20);\n const [rangeDb, setRangeDb] = useState(config.rangeDb ?? 80);\n const [zeroPadding, setZeroPadding] = useState(config.zeroPaddingFactor ?? 2);\n const [hopSize, setHopSize] = useState(\n config.hopSize ?? Math.floor((config.fftSize ?? 2048) / 4)\n );\n const [showLabels, setShowLabels] = useState(config.labels ?? false);\n\n // Sync local state when props change\n useEffect(() => {\n setFftSize(config.fftSize ?? 2048);\n setWindowFn(config.windowFunction ?? 'hann');\n setFreqScale(config.frequencyScale ?? 'mel');\n setLocalColorMap(typeof colorMap === 'string' ? colorMap : 'viridis');\n setMinFreq(config.minFrequency ?? 0);\n setMaxFreq(config.maxFrequency ?? 20000);\n setGainDb(config.gainDb ?? 20);\n setRangeDb(config.rangeDb ?? 80);\n setZeroPadding(config.zeroPaddingFactor ?? 2);\n setHopSize(config.hopSize ?? Math.floor((config.fftSize ?? 2048) / 4));\n setShowLabels(config.labels ?? false);\n }, [config, colorMap]);\n\n // Open/close dialog + handle native close (Escape key)\n useEffect(() => {\n const dialog = dialogRef.current;\n if (!dialog) return;\n\n if (open && !dialog.open) {\n dialog.showModal();\n } else if (!open && dialog.open) {\n dialog.close();\n }\n\n const handleClose = () => {\n // Only call onClose if dialog was open (avoids double-fire)\n if (open) {\n onClose();\n }\n };\n dialog.addEventListener('close', handleClose);\n return () => dialog.removeEventListener('close', handleClose);\n }, [open, onClose]);\n\n const handleApply = () => {\n onApply(\n {\n fftSize,\n windowFunction: windowFn as SpectrogramConfig['windowFunction'],\n frequencyScale: freqScale as SpectrogramConfig['frequencyScale'],\n minFrequency: minFreq,\n maxFrequency: maxFreq,\n gainDb,\n rangeDb,\n zeroPaddingFactor: zeroPadding,\n hopSize,\n labels: showLabels,\n },\n localColorMap\n );\n onClose();\n };\n\n return (\n <StyledDialog ref={dialogRef}>\n <Title>Spectrogram Settings</Title>\n <FormGrid>\n <Field>\n <Label>FFT Size</Label>\n <Select\n value={fftSize}\n onChange={(e) => {\n const v = Number(e.target.value) as FFTSize;\n setFftSize(v);\n setHopSize(Math.floor(v / 4));\n }}\n >\n {FFT_SIZES.map((s) => (\n <option key={s} value={s}>\n {s}\n </option>\n ))}\n </Select>\n </Field>\n\n <Field>\n <Label>Hop Size</Label>\n <Select value={hopSize} onChange={(e) => setHopSize(Number(e.target.value))}>\n {[\n { label: `${fftSize} (no overlap)`, value: fftSize },\n { label: `${Math.floor(fftSize / 2)} (50%)`, value: Math.floor(fftSize / 2) },\n { label: `${Math.floor(fftSize / 4)} (75%)`, value: Math.floor(fftSize / 4) },\n { label: `${Math.floor(fftSize / 8)} (87.5%)`, value: Math.floor(fftSize / 8) },\n ].map((o) => (\n <option key={o.value} value={o.value}>\n {o.label}\n </option>\n ))}\n </Select>\n </Field>\n\n <Field>\n <Label>Zero Padding</Label>\n <Select value={zeroPadding} onChange={(e) => setZeroPadding(Number(e.target.value))}>\n {[1, 2, 4, 8, 16].map((v) => (\n <option key={v} value={v}>\n {v}\n </option>\n ))}\n </Select>\n </Field>\n\n <Field>\n <Label>Window Function</Label>\n <Select value={windowFn} onChange={(e) => setWindowFn(e.target.value as typeof windowFn)}>\n {WINDOW_FUNCTIONS.map((w) => (\n <option key={w} value={w}>\n {w}\n </option>\n ))}\n </Select>\n </Field>\n\n <Field>\n <Label>Frequency Scale</Label>\n <Select\n value={freqScale}\n onChange={(e) => setFreqScale(e.target.value as typeof freqScale)}\n >\n {FREQ_SCALES.map((s) => (\n <option key={s} value={s}>\n {s}\n </option>\n ))}\n </Select>\n </Field>\n\n <Field>\n <Label>Color Map</Label>\n <Select\n value={localColorMap}\n onChange={(e) => setLocalColorMap(e.target.value as ColorMapName)}\n >\n {COLOR_MAPS.map((c) => (\n <option key={c} value={c}>\n {c}\n </option>\n ))}\n </Select>\n </Field>\n\n <Field>\n <Label>Min Frequency (Hz)</Label>\n <NumberInput\n type=\"number\"\n min={0}\n max={5000}\n step={50}\n value={minFreq}\n onChange={(e) => setMinFreq(Number(e.target.value))}\n />\n </Field>\n\n <Field>\n <Label>Max Frequency (Hz)</Label>\n <NumberInput\n type=\"number\"\n min={1000}\n max={22050}\n step={50}\n value={maxFreq}\n onChange={(e) => setMaxFreq(Number(e.target.value))}\n />\n </Field>\n\n <Field>\n <Label>Range (dB)</Label>\n <NumberInput\n type=\"number\"\n min={1}\n max={120}\n step={1}\n value={rangeDb}\n onChange={(e) => setRangeDb(Number(e.target.value))}\n />\n </Field>\n\n <Field>\n <Label>Gain (dB)</Label>\n <NumberInput\n type=\"number\"\n min={-20}\n max={60}\n step={1}\n value={gainDb}\n onChange={(e) => setGainDb(Number(e.target.value))}\n />\n </Field>\n\n <Field $span>\n <CheckboxLabel>\n <input\n type=\"checkbox\"\n checked={showLabels}\n onChange={(e) => setShowLabels(e.target.checked)}\n />\n Show Frequency Labels\n </CheckboxLabel>\n </Field>\n </FormGrid>\n\n <ButtonRow>\n <ModalButton onClick={onClose}>Cancel</ModalButton>\n <ModalButton $primary onClick={handleApply}>\n Apply\n </ModalButton>\n </ButtonRow>\n </StyledDialog>\n );\n};\n","import type { SpectrogramConfig } from '@waveform-playlist/core';\n\n/**\n * Error thrown when a spectrogram computation is aborted due to a generation change.\n * Use `instanceof SpectrogramAbortError` instead of string matching on error messages.\n */\nexport class SpectrogramAbortError extends Error {\n constructor() {\n super('aborted');\n this.name = 'SpectrogramAbortError';\n }\n}\n\nexport interface SpectrogramWorkerFFTParams {\n clipId: string;\n channelDataArrays: Float32Array[];\n config: SpectrogramConfig;\n sampleRate: number;\n offsetSamples: number;\n durationSamples: number;\n mono: boolean;\n sampleRange?: { start: number; end: number };\n /** If set, compute only this channel index (used by worker pool). */\n channelFilter?: number;\n}\n\nexport interface SpectrogramWorkerRenderChunksParams {\n cacheKey: string;\n canvasIds: string[];\n canvasWidths: number[];\n globalPixelOffsets: number[];\n canvasHeight: number;\n devicePixelRatio: number;\n samplesPerPixel: number;\n colorLUT: Uint8Array;\n frequencyScale: string;\n minFrequency: number;\n maxFrequency: number;\n gainDb: number;\n rangeDb: number;\n channelIndex: number;\n}\n\ntype ComputeResponse =\n | { id: string; type: 'cache-key'; cacheKey: string }\n | { id: string; type: 'done' }\n | { id: string; type: 'aborted' }\n | { id: string; type: 'error'; error: string };\n\n/** Union of all values that worker resolve callbacks receive. */\ntype PendingResolveValue = { cacheKey: string } | void;\n\ninterface PendingEntry {\n resolve: (value: PendingResolveValue) => void;\n reject: (reason: unknown) => void;\n}\n\n/** Add a pending promise entry, centralizing the single unavoidable resolve cast. */\nfunction addPending<T>(\n map: Map<string, PendingEntry>,\n id: string,\n resolve: (value: T) => void,\n reject: (reason: unknown) => void\n): void {\n map.set(id, { resolve: resolve as PendingEntry['resolve'], reject });\n}\n\nexport interface SpectrogramWorkerApi {\n computeFFT(\n params: SpectrogramWorkerFFTParams,\n generation?: number\n ): Promise<{ cacheKey: string }>;\n renderChunks(params: SpectrogramWorkerRenderChunksParams, generation?: number): Promise<void>;\n abortGeneration(generation: number): void;\n registerCanvas(canvasId: string, canvas: OffscreenCanvas): void;\n unregisterCanvas(canvasId: string): void;\n registerAudioData(clipId: string, channelDataArrays: Float32Array[], sampleRate: number): void;\n unregisterAudioData(clipId: string): void;\n terminate(): void;\n}\n\nlet idCounter = 0;\n\n/**\n * Wraps a Web Worker running `spectrogram.worker.ts` with a promise-based API.\n *\n * The caller is responsible for creating the Worker, e.g.:\n * ```ts\n * const worker = new Worker(\n * new URL('@waveform-playlist/spectrogram/worker/spectrogram.worker', import.meta.url),\n * { type: 'module' }\n * );\n * const api = createSpectrogramWorker(worker);\n * ```\n */\nexport function createSpectrogramWorker(worker: Worker): SpectrogramWorkerApi {\n const pending = new Map<string, PendingEntry>();\n\n // Track which clipIds have pre-registered audio data in the worker\n const registeredClipIds = new Set<string>();\n let terminated = false;\n\n worker.onmessage = (e: MessageEvent<ComputeResponse>) => {\n const msg = e.data;\n const entry = pending.get(msg.id);\n if (entry) {\n pending.delete(msg.id);\n switch (msg.type) {\n case 'error':\n entry.reject(new Error(msg.error));\n break;\n case 'aborted':\n entry.reject(new SpectrogramAbortError());\n break;\n case 'cache-key':\n entry.resolve({ cacheKey: msg.cacheKey });\n break;\n case 'done':\n entry.resolve(undefined);\n break;\n }\n } else if (msg.id) {\n console.warn(`[spectrogram] Received response for unknown message ID: ${msg.id}`);\n }\n };\n\n worker.onerror = (e: ErrorEvent) => {\n terminated = true;\n for (const [, entry] of pending) {\n entry.reject(e.error ?? new Error(e.message));\n }\n pending.clear();\n };\n\n return {\n computeFFT(params: SpectrogramWorkerFFTParams, generation = 0): Promise<{ cacheKey: string }> {\n if (terminated) return Promise.reject(new Error('Worker terminated'));\n const id = String(++idCounter);\n\n return new Promise<{ cacheKey: string }>((resolve, reject) => {\n addPending(pending, id, resolve, reject);\n\n // Skip transfer if audio data is pre-registered in the worker\n const isPreRegistered = registeredClipIds.has(params.clipId);\n const transferableArrays = isPreRegistered\n ? []\n : params.channelDataArrays.map((arr) => arr.slice());\n const transferables = transferableArrays.map((arr) => arr.buffer);\n\n worker.postMessage(\n {\n type: 'compute-fft',\n id,\n generation,\n clipId: params.clipId,\n channelDataArrays: transferableArrays,\n config: params.config,\n sampleRate: params.sampleRate,\n offsetSamples: params.offsetSamples,\n durationSamples: params.durationSamples,\n mono: params.mono,\n ...(params.sampleRange ? { sampleRange: params.sampleRange } : {}),\n ...(params.channelFilter !== undefined ? { channelFilter: params.channelFilter } : {}),\n },\n transferables\n );\n });\n },\n\n renderChunks(params: SpectrogramWorkerRenderChunksParams, generation = 0): Promise<void> {\n if (terminated) return Promise.reject(new Error('Worker terminated'));\n const id = String(++idCounter);\n\n return new Promise<void>((resolve, reject) => {\n addPending(pending, id, resolve, reject);\n\n worker.postMessage({\n type: 'render-chunks',\n id,\n generation,\n cacheKey: params.cacheKey,\n canvasIds: params.canvasIds,\n canvasWidths: params.canvasWidths,\n globalPixelOffsets: params.globalPixelOffsets,\n canvasHeight: params.canvasHeight,\n devicePixelRatio: params.devicePixelRatio,\n samplesPerPixel: params.samplesPerPixel,\n colorLUT: params.colorLUT,\n frequencyScale: params.frequencyScale,\n minFrequency: params.minFrequency,\n maxFrequency: params.maxFrequency,\n gainDb: params.gainDb,\n rangeDb: params.rangeDb,\n channelIndex: params.channelIndex,\n });\n });\n },\n\n abortGeneration(generation: number): void {\n if (terminated) return;\n worker.postMessage({ type: 'abort-generation', generation });\n },\n\n registerCanvas(canvasId: string, canvas: OffscreenCanvas): void {\n worker.postMessage({ type: 'register-canvas', canvasId, canvas }, [canvas]);\n },\n\n unregisterCanvas(canvasId: string): void {\n worker.postMessage({ type: 'unregister-canvas', canvasId });\n },\n\n registerAudioData(clipId: string, channelDataArrays: Float32Array[], sampleRate: number): void {\n const transferableArrays = channelDataArrays.map((arr) => arr.slice());\n const transferables = transferableArrays.map((arr) => arr.buffer);\n worker.postMessage(\n { type: 'register-audio-data', clipId, channelDataArrays: transferableArrays, sampleRate },\n transferables\n );\n registeredClipIds.add(clipId);\n },\n\n unregisterAudioData(clipId: string): void {\n worker.postMessage({ type: 'unregister-audio-data', clipId });\n registeredClipIds.delete(clipId);\n },\n\n terminate() {\n terminated = true;\n worker.terminate();\n for (const [, entry] of pending) {\n entry.reject(new Error('Worker terminated'));\n }\n pending.clear();\n },\n };\n}\n","import {\n createSpectrogramWorker,\n type SpectrogramWorkerApi,\n type SpectrogramWorkerFFTParams,\n type SpectrogramWorkerRenderChunksParams,\n} from './createSpectrogramWorker';\n\n/**\n * Parse the channel index from a canvas ID like \"clipId-ch0-chunk5\" → 0.\n */\nfunction parseChannelFromCanvasId(canvasId: string): number {\n const match = canvasId.match(/-ch(\\d+)-/);\n return match ? parseInt(match[1], 10) : 0;\n}\n\n/**\n * Creates a pool of spectrogram workers that parallelize FFT computation\n * across channels. Each worker handles a subset of channels, so stereo\n * audio computes ch0 and ch1 FFTs in parallel (~1.5s instead of ~2.9s).\n *\n * The pool exposes the same `SpectrogramWorkerApi` interface, so it's\n * a drop-in replacement for a single worker in SpectrogramProvider.\n *\n * Audio data is registered in ALL workers (each needs full data for mono\n * mode). Canvases are routed to the worker for their channel. computeFFT\n * fans out with channelFilter so each worker computes only its channel.\n */\n/**\n * Default pool size: 2 workers (one per channel for stereo).\n * Most web audio is mono or stereo, so 2 is sufficient.\n * Configurable via `<SpectrogramProvider workerPoolSize={N}>` for\n * multi-channel audio (e.g., 5.1 surround).\n */\nfunction defaultPoolSize(): number {\n return 2;\n}\n\nexport function createSpectrogramWorkerPool(\n createWorker: () => Worker,\n poolSize = defaultPoolSize()\n): SpectrogramWorkerApi {\n const workers: SpectrogramWorkerApi[] = [];\n try {\n for (let i = 0; i < poolSize; i++) {\n workers.push(createSpectrogramWorker(createWorker()));\n }\n } catch (err) {\n for (const w of workers) {\n w.terminate();\n }\n throw err;\n }\n\n function getWorkerForChannel(channelIndex: number): SpectrogramWorkerApi {\n return workers[channelIndex % workers.length];\n }\n\n return {\n computeFFT(params: SpectrogramWorkerFFTParams, generation = 0): Promise<{ cacheKey: string }> {\n // Mono: single worker computes the mono mix (needs all channel data)\n if (params.mono) {\n return workers[0].computeFFT(params, generation);\n }\n\n // Multi-channel: fan out with channelFilter, one worker per channel.\n // Pool may have more workers than channels (e.g., 3 workers for stereo) —\n // only use workers up to the channel count.\n const channelCount = params.channelDataArrays.length;\n const activeWorkers = workers.slice(0, channelCount);\n const promises = activeWorkers.map((w, i) =>\n w.computeFFT({ ...params, channelFilter: i }, generation)\n );\n // Wait for all workers, return any cacheKey (all are identical)\n return Promise.all(promises).then((results) => results[0]);\n },\n\n renderChunks(params: SpectrogramWorkerRenderChunksParams, generation = 0): Promise<void> {\n const worker = getWorkerForChannel(params.channelIndex);\n // Remap channelIndex to 0 — each worker stores its channel at index 0\n return worker.renderChunks({ ...params, channelIndex: 0 }, generation);\n },\n\n abortGeneration(generation: number): void {\n for (const w of workers) {\n w.abortGeneration(generation);\n }\n },\n\n registerCanvas(canvasId: string, canvas: OffscreenCanvas): void {\n const ch = parseChannelFromCanvasId(canvasId);\n getWorkerForChannel(ch).registerCanvas(canvasId, canvas);\n },\n\n unregisterCanvas(canvasId: string): void {\n const ch = parseChannelFromCanvasId(canvasId);\n getWorkerForChannel(ch).unregisterCanvas(canvasId);\n },\n\n registerAudioData(clipId: string, channelDataArrays: Float32Array[], sampleRate: number): void {\n // All workers get full audio data (needed for mono computation)\n for (const w of workers) {\n w.registerAudioData(clipId, channelDataArrays, sampleRate);\n }\n },\n\n unregisterAudioData(clipId: string): void {\n for (const w of workers) {\n w.unregisterAudioData(clipId);\n }\n },\n\n terminate(): void {\n for (const w of workers) {\n w.terminate();\n }\n },\n };\n}\n","import React, { useState, useEffect, useRef, useCallback, useMemo, type ReactNode } from 'react';\nimport {\n MAX_CANVAS_WIDTH,\n type SpectrogramConfig,\n type SpectrogramComputeConfig,\n type ColorMapValue,\n type RenderMode,\n type TrackSpectrogramOverrides,\n} from '@waveform-playlist/core';\nimport { getColorMap, getFrequencyScale } from './computation';\nimport {\n createSpectrogramWorkerPool,\n SpectrogramAbortError,\n type SpectrogramWorkerApi,\n} from './worker';\nimport { SpectrogramMenuItems } from './components';\nimport { SpectrogramSettingsModal } from './components';\nimport {\n SpectrogramIntegrationProvider,\n type SpectrogramIntegration,\n} from '@waveform-playlist/browser';\nimport { usePlaylistData, usePlaylistControls } from '@waveform-playlist/browser';\n\n/** Extract the chunk number from a canvas ID like \"clipId-ch0-chunk5\" → 5 */\nfunction extractChunkNumber(canvasId: string): number {\n const match = canvasId.match(/chunk(\\d+)$/);\n if (!match) {\n console.warn(`[spectrogram] Unexpected canvas ID format: ${canvasId}`);\n return 0;\n }\n return parseInt(match[1], 10);\n}\n\nexport interface SpectrogramProviderProps {\n config?: SpectrogramConfig;\n colorMap?: ColorMapValue;\n /** Number of Web Workers for parallel FFT computation. Defaults to 2 (one per stereo channel). */\n workerPoolSize?: number;\n children: ReactNode;\n}\n\nexport const SpectrogramProvider: React.FC<SpectrogramProviderProps> = ({\n config: spectrogramConfig,\n colorMap: spectrogramColorMap,\n workerPoolSize,\n children,\n}) => {\n const { tracks, waveHeight, samplesPerPixel, isReady, mono } = usePlaylistData();\n const { scrollContainerRef } = usePlaylistControls();\n\n // State\n const [trackSpectrogramOverrides, setTrackSpectrogramOverrides] = useState<\n Map<string, TrackSpectrogramOverrides>\n >(new Map());\n\n // OffscreenCanvas registry for worker-rendered spectrograms\n const spectrogramCanvasRegistryRef = useRef<\n Map<string, Map<number, { canvasIds: string[]; canvasWidths: number[] }>>\n >(new Map());\n const [spectrogramCanvasVersion, setSpectrogramCanvasVersion] = useState(0);\n\n // Spectrogram refs\n const prevSpectrogramConfigRef = useRef<Map<string, string>>(new Map());\n const prevSpectrogramFFTKeyRef = useRef<Map<string, string>>(new Map());\n const spectrogramWorkerRef = useRef<SpectrogramWorkerApi | null>(null);\n const spectrogramGenerationRef = useRef(0);\n const prevCanvasVersionRef = useRef(0);\n const [spectrogramWorkerReady, setSpectrogramWorkerReady] = useState(false);\n const renderedClipIdsRef = useRef<Set<string>>(new Set());\n const backgroundRenderAbortRef = useRef<{ aborted: boolean } | null>(null);\n const registeredAudioClipIdsRef = useRef<Set<string>>(new Set());\n\n // Terminate worker on unmount\n useEffect(() => {\n return () => {\n spectrogramWorkerRef.current?.terminate();\n spectrogramWorkerRef.current = null;\n };\n }, []);\n\n // Eagerly transfer audio data to worker when tracks load\n useEffect(() => {\n if (!isReady || tracks.length === 0) return;\n\n let workerApi = spectrogramWorkerRef.current;\n if (!workerApi) {\n try {\n workerApi = createSpectrogramWorkerPool(\n () =>\n new Worker(\n new URL('@waveform-playlist/spectrogram/worker/spectrogram.worker', import.meta.url),\n { type: 'module' }\n ),\n workerPoolSize\n );\n spectrogramWorkerRef.current = workerApi;\n setSpectrogramWorkerReady(true);\n } catch (err) {\n console.warn(\n `[waveform-playlist] Spectrogram Web Worker unavailable for pre-transfer: ${err instanceof Error ? err.message : String(err)}`\n );\n return;\n }\n }\n\n const currentClipIds = new Set<string>();\n\n for (const track of tracks) {\n for (const clip of track.clips) {\n if (!clip.audioBuffer) continue;\n currentClipIds.add(clip.id);\n\n if (!registeredAudioClipIdsRef.current.has(clip.id)) {\n const channelDataArrays: Float32Array[] = [];\n for (let ch = 0; ch < clip.audioBuffer.numberOfChannels; ch++) {\n channelDataArrays.push(clip.audioBuffer.getChannelData(ch));\n }\n workerApi.registerAudioData(clip.id, channelDataArrays, clip.audioBuffer.sampleRate);\n registeredAudioClipIdsRef.current.add(clip.id);\n }\n }\n }\n\n for (const clipId of registeredAudioClipIdsRef.current) {\n if (!currentClipIds.has(clipId)) {\n workerApi.unregisterAudioData(clipId);\n registeredAudioClipIdsRef.current.delete(clipId);\n }\n }\n // workerPoolSize intentionally omitted — pool is created once via spectrogramWorkerRef guard\n }, [isReady, tracks]); // eslint-disable-line react-hooks/exhaustive-deps\n\n // Main spectrogram computation effect\n useEffect(() => {\n if (tracks.length === 0) return;\n\n const currentKeys = new Map<string, string>();\n const currentFFTKeys = new Map<string, string>();\n tracks.forEach((track) => {\n const mode =\n trackSpectrogramOverrides.get(track.id)?.renderMode ?? track.renderMode ?? 'waveform';\n if (mode === 'waveform') return;\n const cfg =\n trackSpectrogramOverrides.get(track.id)?.config ??\n track.spectrogramConfig ??\n spectrogramConfig;\n const cm =\n trackSpectrogramOverrides.get(track.id)?.colorMap ??\n track.spectrogramColorMap ??\n spectrogramColorMap;\n currentKeys.set(track.id, JSON.stringify({ mode, cfg, cm, mono }));\n const computeConfig: SpectrogramComputeConfig = {\n fftSize: cfg?.fftSize,\n hopSize: cfg?.hopSize,\n windowFunction: cfg?.windowFunction,\n alpha: cfg?.alpha,\n zeroPaddingFactor: cfg?.zeroPaddingFactor,\n };\n currentFFTKeys.set(track.id, JSON.stringify({ mode, mono, ...computeConfig }));\n });\n\n const prevKeys = prevSpectrogramConfigRef.current;\n const prevFFTKeys = prevSpectrogramFFTKeyRef.current;\n\n let configChanged = currentKeys.size !== prevKeys.size;\n if (!configChanged) {\n for (const [idx, key] of currentKeys) {\n if (prevKeys.get(idx) !== key) {\n configChanged = true;\n break;\n }\n }\n }\n\n let fftKeyChanged = currentFFTKeys.size !== prevFFTKeys.size;\n if (!fftKeyChanged) {\n for (const [idx, key] of currentFFTKeys) {\n if (prevFFTKeys.get(idx) !== key) {\n fftKeyChanged = true;\n break;\n }\n }\n }\n\n const canvasVersionChanged = spectrogramCanvasVersion !== prevCanvasVersionRef.current;\n prevCanvasVersionRef.current = spectrogramCanvasVersion;\n\n if (!configChanged && !canvasVersionChanged) return;\n\n if (configChanged) {\n prevSpectrogramConfigRef.current = currentKeys;\n prevSpectrogramFFTKeyRef.current = currentFFTKeys;\n }\n\n if (backgroundRenderAbortRef.current) {\n backgroundRenderAbortRef.current.aborted = true;\n }\n\n const generation = ++spectrogramGenerationRef.current;\n\n // Tell the worker to abort any in-flight FFT from previous generations\n if (spectrogramWorkerRef.current) {\n spectrogramWorkerRef.current.abortGeneration(generation);\n }\n\n let workerApi = spectrogramWorkerRef.current;\n if (!workerApi) {\n try {\n workerApi = createSpectrogramWorkerPool(\n () =>\n new Worker(\n new URL('@waveform-playlist/spectrogram/worker/spectrogram.worker', import.meta.url),\n { type: 'module' }\n ),\n workerPoolSize\n );\n spectrogramWorkerRef.current = workerApi;\n setSpectrogramWorkerReady(true);\n } catch (err) {\n console.error(\n `[waveform-playlist] Spectrogram Web Worker required but unavailable: ${err instanceof Error ? err.message : String(err)}`\n );\n return;\n }\n }\n\n const clipsNeedingFFT: Array<{\n clipId: string;\n trackIndex: number;\n channelDataArrays: Float32Array[];\n config: SpectrogramConfig;\n sampleRate: number;\n offsetSamples: number;\n durationSamples: number;\n clipStartSample: number;\n monoFlag: boolean;\n colorMap: ColorMapValue;\n }> = [];\n const clipsNeedingDisplayOnly: Array<{\n clipId: string;\n trackIndex: number;\n channelDataArrays: Float32Array[];\n config: SpectrogramConfig;\n sampleRate: number;\n offsetSamples: number;\n durationSamples: number;\n clipStartSample: number;\n monoFlag: boolean;\n colorMap: ColorMapValue;\n numChannels: number;\n }> = [];\n\n tracks.forEach((track, i) => {\n const mode =\n trackSpectrogramOverrides.get(track.id)?.renderMode ?? track.renderMode ?? 'waveform';\n if (mode === 'waveform') return;\n\n const trackConfigChanged =\n configChanged && currentKeys.get(track.id) !== prevKeys.get(track.id);\n const trackFFTChanged =\n fftKeyChanged && currentFFTKeys.get(track.id) !== prevFFTKeys.get(track.id);\n const hasRegisteredCanvases =\n canvasVersionChanged &&\n track.clips.some((clip) => spectrogramCanvasRegistryRef.current.has(clip.id));\n if (!trackConfigChanged && !hasRegisteredCanvases) return;\n\n const cfg =\n trackSpectrogramOverrides.get(track.id)?.config ??\n track.spectrogramConfig ??\n spectrogramConfig ??\n {};\n const cm =\n trackSpectrogramOverrides.get(track.id)?.colorMap ??\n track.spectrogramColorMap ??\n spectrogramColorMap ??\n 'viridis';\n\n for (const clip of track.clips) {\n if (!clip.audioBuffer) continue;\n\n const monoFlag = mono || clip.audioBuffer.numberOfChannels === 1;\n\n if (!trackFFTChanged && !hasRegisteredCanvases && renderedClipIdsRef.current.has(clip.id)) {\n const channelDataArrays: Float32Array[] = [];\n for (let ch = 0; ch < clip.audioBuffer.numberOfChannels; ch++) {\n channelDataArrays.push(clip.audioBuffer.getChannelData(ch));\n }\n clipsNeedingDisplayOnly.push({\n clipId: clip.id,\n trackIndex: i,\n channelDataArrays,\n config: cfg,\n sampleRate: clip.audioBuffer.sampleRate,\n offsetSamples: clip.offsetSamples,\n durationSamples: clip.durationSamples,\n clipStartSample: clip.startSample,\n monoFlag,\n colorMap: cm,\n numChannels: monoFlag ? 1 : clip.audioBuffer.numberOfChannels,\n });\n continue;\n }\n\n const channelDataArrays: Float32Array[] = [];\n for (let ch = 0; ch < clip.audioBuffer.numberOfChannels; ch++) {\n channelDataArrays.push(clip.audioBuffer.getChannelData(ch));\n }\n\n clipsNeedingFFT.push({\n clipId: clip.id,\n trackIndex: i,\n channelDataArrays,\n config: cfg,\n sampleRate: clip.audioBuffer.sampleRate,\n offsetSamples: clip.offsetSamples,\n durationSamples: clip.durationSamples,\n clipStartSample: clip.startSample,\n monoFlag,\n colorMap: cm,\n });\n }\n });\n\n if (clipsNeedingFFT.length === 0 && clipsNeedingDisplayOnly.length === 0) return;\n\n // Three-tier chunk classification:\n // - viewportIndices: chunks intersecting the exact viewport (phase 1a — fast first paint)\n // - bufferIndices: chunks in the 1.5× overscan buffer but outside viewport (phase 1b)\n // - remainingIndices: chunks outside the buffer (phase 2 — background batches)\n const getVisibleChunkRange = (\n channelInfo: { canvasIds: string[]; canvasWidths: number[] },\n clipPixelOffset = 0\n ): { viewportIndices: number[]; bufferIndices: number[]; remainingIndices: number[] } => {\n const container = scrollContainerRef.current;\n if (!container) {\n return {\n viewportIndices: channelInfo.canvasWidths.map((_, i) => i),\n bufferIndices: [],\n remainingIndices: [],\n };\n }\n\n const scrollLeft = container.scrollLeft;\n const viewportWidth = container.clientWidth;\n // Match the 1.5× overscan buffer used by useVisibleChunkIndices\n // (ScrollViewport.tsx) so spectrogram FFT covers all mounted canvases.\n const buffer = viewportWidth * 1.5;\n const bufferStart = Math.max(0, scrollLeft - buffer);\n const bufferEnd = scrollLeft + viewportWidth + buffer;\n\n const viewportIndices: number[] = [];\n const bufferIndices: number[] = [];\n const remainingIndices: number[] = [];\n\n for (let i = 0; i < channelInfo.canvasWidths.length; i++) {\n const chunkNumber = extractChunkNumber(channelInfo.canvasIds[i]);\n const chunkLeft = chunkNumber * MAX_CANVAS_WIDTH + clipPixelOffset;\n const chunkRight = chunkLeft + channelInfo.canvasWidths[i];\n if (chunkRight > scrollLeft && chunkLeft < scrollLeft + viewportWidth) {\n viewportIndices.push(i);\n } else if (chunkRight > bufferStart && chunkLeft < bufferEnd) {\n bufferIndices.push(i);\n } else {\n remainingIndices.push(i);\n }\n }\n\n return { viewportIndices, bufferIndices, remainingIndices };\n };\n\n const renderChunkSubset = async (\n api: SpectrogramWorkerApi,\n cacheKey: string,\n channelInfo: { canvasIds: string[]; canvasWidths: number[] },\n indices: number[],\n item: { config: SpectrogramConfig; colorMap: ColorMapValue },\n channelIndex: number,\n gen: number\n ) => {\n if (indices.length === 0) return;\n\n const canvasIds = indices.map((i) => channelInfo.canvasIds[i]);\n const canvasWidths = indices.map((i) => channelInfo.canvasWidths[i]);\n\n // Compute correct global pixel offsets by extracting chunk numbers from\n // canvas IDs. With virtual scrolling, the registry may contain non-consecutive\n // chunks (e.g., chunks 50-55), so summing widths from index 0 gives wrong offsets.\n const globalPixelOffsets: number[] = [];\n for (const idx of indices) {\n const chunkNumber = extractChunkNumber(channelInfo.canvasIds[idx]);\n globalPixelOffsets.push(chunkNumber * MAX_CANVAS_WIDTH);\n }\n\n const colorLUT = getColorMap(item.colorMap);\n\n await api.renderChunks(\n {\n cacheKey,\n canvasIds,\n canvasWidths,\n globalPixelOffsets,\n canvasHeight: waveHeight,\n devicePixelRatio: typeof window !== 'undefined' ? window.devicePixelRatio : 1,\n samplesPerPixel,\n colorLUT,\n frequencyScale: item.config.frequencyScale ?? 'mel',\n minFrequency: item.config.minFrequency ?? 0,\n maxFrequency: item.config.maxFrequency ?? 0,\n gainDb: item.config.gainDb ?? 20,\n rangeDb: item.config.rangeDb ?? 80,\n channelIndex,\n },\n gen\n );\n };\n\n // Compute FFT for the sample range covered by a set of chunk indices.\n // Returns the cache key (data covers all channels).\n // This avoids computing a single full-clip FFT (which OOMs on 1hr+ files)\n // by computing per-batch ranges on demand.\n const computeFFTForChunks = async (\n api: SpectrogramWorkerApi,\n channelInfo: { canvasIds: string[]; canvasWidths: number[] },\n indices: number[],\n item: {\n clipId: string;\n channelDataArrays: Float32Array[];\n config: SpectrogramConfig;\n sampleRate: number;\n offsetSamples: number;\n durationSamples: number;\n monoFlag: boolean;\n },\n gen: number\n ): Promise<string> => {\n // Determine the sample range these chunks cover\n const chunkNumbers = indices.map((i) => extractChunkNumber(channelInfo.canvasIds[i]));\n const minChunk = Math.min(...chunkNumbers);\n const maxChunk = Math.max(...chunkNumbers);\n const maxChunkIdx = indices[chunkNumbers.indexOf(maxChunk)];\n const lastChunkWidth = channelInfo.canvasWidths[maxChunkIdx];\n\n const startPx = minChunk * MAX_CANVAS_WIDTH;\n const endPx = maxChunk * MAX_CANVAS_WIDTH + lastChunkWidth;\n\n const windowSize = item.config.fftSize ?? 2048;\n const rangeStartSample = item.offsetSamples + Math.floor(startPx * samplesPerPixel);\n const rangeEndSample = Math.min(\n item.offsetSamples + item.durationSamples,\n item.offsetSamples + Math.ceil(endPx * samplesPerPixel)\n );\n\n // Pad by windowSize to avoid edge artifacts\n const paddedStart = Math.max(item.offsetSamples, rangeStartSample - windowSize);\n const paddedEnd = Math.min(\n item.offsetSamples + item.durationSamples,\n rangeEndSample + windowSize\n );\n\n const { cacheKey } = await api.computeFFT(\n {\n clipId: item.clipId,\n channelDataArrays: item.channelDataArrays,\n config: item.config,\n sampleRate: item.sampleRate,\n offsetSamples: item.offsetSamples,\n durationSamples: item.durationSamples,\n mono: item.monoFlag,\n sampleRange: { start: paddedStart, end: paddedEnd },\n },\n gen\n );\n\n return cacheKey;\n };\n\n // Split indices into contiguous groups based on chunk numbers.\n // E.g., remaining=[0,1,4,5] → [[0,1],[4,5]] — prevents computing\n // an FFT range spanning the gap between 1 and 4.\n const groupContiguousIndices = (\n channelInfo: { canvasIds: string[] },\n indices: number[]\n ): number[][] => {\n if (indices.length === 0) return [];\n const groups: number[][] = [];\n let currentGroup = [indices[0]];\n let prevChunk = extractChunkNumber(channelInfo.canvasIds[indices[0]]);\n for (let i = 1; i < indices.length; i++) {\n const chunk = extractChunkNumber(channelInfo.canvasIds[indices[i]]);\n if (chunk === prevChunk + 1) {\n currentGroup.push(indices[i]);\n } else {\n groups.push(currentGroup);\n currentGroup = [indices[i]];\n }\n prevChunk = chunk;\n }\n groups.push(currentGroup);\n return groups;\n };\n\n const computeAsync = async () => {\n const abortToken = { aborted: false };\n backgroundRenderAbortRef.current = abortToken;\n\n // Render off-screen chunks in idle-callback batches, computing FFT\n // per contiguous group to avoid allocating one giant Float32Array for the\n // full clip (which OOMs on 1hr+ files — e.g., 310K frames × 2048 bins = 2.5GB).\n // Groups remaining indices into contiguous runs (e.g., [0,1,4,5] → [0,1]+[4,5])\n // so each FFT only covers the sample range actually needed.\n // Returns true if aborted (caller should return early).\n const renderBackgroundBatches = async (\n channelRanges: Array<{\n ch: number;\n channelInfo: { canvasIds: string[]; canvasWidths: number[] };\n remainingIndices: number[];\n }>,\n item: {\n clipId: string;\n channelDataArrays: Float32Array[];\n config: SpectrogramConfig;\n sampleRate: number;\n offsetSamples: number;\n durationSamples: number;\n monoFlag: boolean;\n colorMap: ColorMapValue;\n }\n ): Promise<boolean> => {\n // Collect all contiguous groups across channels, then render\n // each group for ALL channels before moving to the next group\n // (multi-channel fairness — avoids ch1 starvation).\n const allGroups: Array<{\n group: number[];\n channelRangeEntries: Array<{\n ch: number;\n channelInfo: { canvasIds: string[]; canvasWidths: number[] };\n }>;\n }> = [];\n\n // Build contiguous groups from the first channel's remaining indices\n // (all channels have the same chunk layout).\n if (channelRanges.length > 0) {\n const { channelInfo, remainingIndices } = channelRanges[0];\n const groups = groupContiguousIndices(channelInfo, remainingIndices);\n for (const group of groups) {\n allGroups.push({\n group,\n channelRangeEntries: channelRanges.map(({ ch, channelInfo: ci }) => ({\n ch,\n channelInfo: ci,\n })),\n });\n }\n }\n\n for (const { group, channelRangeEntries } of allGroups) {\n if (spectrogramGenerationRef.current !== generation || abortToken.aborted) return true;\n\n await new Promise<void>((resolve) => {\n if (typeof requestIdleCallback === 'function') {\n requestIdleCallback(() => resolve());\n } else {\n setTimeout(resolve, 0);\n }\n });\n\n if (spectrogramGenerationRef.current !== generation || abortToken.aborted) return true;\n\n // Compute FFT once for this contiguous group (covers all channels)\n const { channelInfo: firstChannelInfo } = channelRangeEntries[0];\n const cacheKey = await computeFFTForChunks(\n workerApi!,\n firstChannelInfo,\n group,\n item,\n generation\n );\n\n // Render all channels from the cached FFT data\n for (const { ch, channelInfo: ci } of channelRangeEntries) {\n if (spectrogramGenerationRef.current !== generation || abortToken.aborted) return true;\n await renderChunkSubset(workerApi!, cacheKey, ci, group, item, ch, generation);\n }\n }\n return false;\n };\n\n for (const item of clipsNeedingFFT) {\n if (spectrogramGenerationRef.current !== generation || abortToken.aborted) return;\n\n try {\n const clipCanvasInfo = spectrogramCanvasRegistryRef.current.get(item.clipId);\n if (clipCanvasInfo && clipCanvasInfo.size > 0) {\n const numChannels = item.monoFlag ? 1 : item.channelDataArrays.length;\n const clipPixelOffset = Math.floor(item.clipStartSample / samplesPerPixel);\n\n // Three-phase rendering:\n // Phase 1a: viewport-only chunks (fast first paint)\n // Phase 1b: buffer-zone chunks (prevents black chunks on scroll)\n // Phase 2: off-screen chunks (background batches)\n const channelRanges: Array<{\n ch: number;\n channelInfo: { canvasIds: string[]; canvasWidths: number[] };\n viewportIndices: number[];\n bufferIndices: number[];\n remainingIndices: number[];\n }> = [];\n\n for (let ch = 0; ch < numChannels; ch++) {\n const channelInfo = clipCanvasInfo.get(ch);\n if (!channelInfo) continue;\n const range = getVisibleChunkRange(channelInfo, clipPixelOffset);\n channelRanges.push({ ch, channelInfo, ...range });\n }\n\n // Phase 1a: Compute FFT for viewport chunks only, render all channels\n if (channelRanges.length > 0 && channelRanges[0].viewportIndices.length > 0) {\n const cacheKey = await computeFFTForChunks(\n workerApi!,\n channelRanges[0].channelInfo,\n channelRanges[0].viewportIndices,\n item,\n generation\n );\n\n if (spectrogramGenerationRef.current !== generation || abortToken.aborted) return;\n\n for (const { ch, channelInfo, viewportIndices } of channelRanges) {\n await renderChunkSubset(\n workerApi!,\n cacheKey,\n channelInfo,\n viewportIndices,\n item,\n ch,\n generation\n );\n }\n }\n\n if (spectrogramGenerationRef.current !== generation || abortToken.aborted) return;\n\n // Phase 1b: Compute FFT for buffer-zone chunks, render all channels.\n // Buffer indices may be non-contiguous (e.g., chunks [10,14,15] from\n // indices [0,3,4,5]), so group them to avoid spanning a huge FFT range.\n if (channelRanges.length > 0 && channelRanges[0].bufferIndices.length > 0) {\n const bufferGroups = groupContiguousIndices(\n channelRanges[0].channelInfo,\n channelRanges[0].bufferIndices\n );\n\n for (const group of bufferGroups) {\n if (spectrogramGenerationRef.current !== generation || abortToken.aborted) return;\n\n const cacheKey = await computeFFTForChunks(\n workerApi!,\n channelRanges[0].channelInfo,\n group,\n item,\n generation\n );\n\n if (spectrogramGenerationRef.current !== generation || abortToken.aborted) return;\n\n for (const { ch, channelInfo } of channelRanges) {\n await renderChunkSubset(\n workerApi!,\n cacheKey,\n channelInfo,\n group,\n item,\n ch,\n generation\n );\n }\n }\n }\n\n renderedClipIdsRef.current.add(item.clipId);\n\n if (spectrogramGenerationRef.current !== generation || abortToken.aborted) return;\n\n // Phase 2: Render off-screen chunks in background batches\n // (each batch computes its own bounded FFT range).\n if (await renderBackgroundBatches(channelRanges, item)) return;\n }\n } catch (err) {\n if (err instanceof SpectrogramAbortError) return;\n console.warn(\n `[waveform-playlist] Spectrogram worker error for clip ${item.clipId}: ${err instanceof Error ? err.message : String(err)}`\n );\n }\n }\n\n for (const item of clipsNeedingDisplayOnly) {\n if (spectrogramGenerationRef.current !== generation || abortToken.aborted) return;\n\n const clipCanvasInfo = spectrogramCanvasRegistryRef.current.get(item.clipId);\n if (!clipCanvasInfo || clipCanvasInfo.size === 0) continue;\n\n try {\n const clipPixelOffset = Math.floor(item.clipStartSample / samplesPerPixel);\n\n // Three-phase rendering with per-batch FFT (same as FFT path above).\n // Worker cache provides instant hits for previously computed ranges.\n const channelRanges: Array<{\n ch: number;\n channelInfo: { canvasIds: string[]; canvasWidths: number[] };\n viewportIndices: number[];\n bufferIndices: number[];\n remainingIndices: number[];\n }> = [];\n for (let ch = 0; ch < item.numChannels; ch++) {\n const channelInfo = clipCanvasInfo.get(ch);\n if (!channelInfo) continue;\n const range = getVisibleChunkRange(channelInfo, clipPixelOffset);\n channelRanges.push({ ch, channelInfo, ...range });\n }\n\n // Phase 1a: viewport chunks\n if (channelRanges.length > 0 && channelRanges[0].viewportIndices.length > 0) {\n const cacheKey = await computeFFTForChunks(\n workerApi!,\n channelRanges[0].channelInfo,\n channelRanges[0].viewportIndices,\n item,\n generation\n );\n if (spectrogramGenerationRef.current !== generation || abortToken.aborted) return;\n for (const { ch, channelInfo, viewportIndices } of channelRanges) {\n await renderChunkSubset(\n workerApi!,\n cacheKey,\n channelInfo,\n viewportIndices,\n item,\n ch,\n generation\n );\n }\n }\n\n if (spectrogramGenerationRef.current !== generation || abortToken.aborted) return;\n\n // Phase 1b: buffer-zone chunks (grouped for contiguous FFT ranges)\n if (channelRanges.length > 0 && channelRanges[0].bufferIndices.length > 0) {\n const bufferGroups = groupContiguousIndices(\n channelRanges[0].channelInfo,\n channelRanges[0].bufferIndices\n );\n for (const group of bufferGroups) {\n if (spectrogramGenerationRef.current !== generation || abortToken.aborted) return;\n const cacheKey = await computeFFTForChunks(\n workerApi!,\n channelRanges[0].channelInfo,\n group,\n item,\n generation\n );\n if (spectrogramGenerationRef.current !== generation || abortToken.aborted) return;\n for (const { ch, channelInfo } of channelRanges) {\n await renderChunkSubset(\n workerApi!,\n cacheKey,\n channelInfo,\n group,\n item,\n ch,\n generation\n );\n }\n }\n }\n\n if (spectrogramGenerationRef.current !== generation || abortToken.aborted) return;\n\n // Phase 2: Render off-screen chunks in background batches.\n if (await renderBackgroundBatches(channelRanges, item)) return;\n } catch (err) {\n if (err instanceof SpectrogramAbortError) return;\n console.warn(\n `[waveform-playlist] Spectrogram display re-render error for clip ${item.clipId}: ${err instanceof Error ? err.message : String(err)}`\n );\n }\n }\n };\n\n computeAsync().catch((err) => {\n console.error(\n `[waveform-playlist] Spectrogram computation failed: ${err instanceof Error ? err.message : String(err)}`\n );\n });\n // eslint-disable-next-line react-hooks/exhaustive-deps -- workerPoolSize intentionally omitted, pool created once via spectrogramWorkerRef guard\n }, [\n tracks,\n mono,\n spectrogramConfig,\n spectrogramColorMap,\n trackSpectrogramOverrides,\n waveHeight,\n samplesPerPixel,\n spectrogramCanvasVersion,\n scrollContainerRef,\n ]);\n\n // Setters\n const setTrackRenderMode = useCallback((trackId: string, mode: RenderMode) => {\n setTrackSpectrogramOverrides((prev) => {\n const next = new Map(prev);\n const existing = next.get(trackId);\n next.set(trackId, { ...existing, renderMode: mode });\n return next;\n });\n }, []);\n\n const setTrackSpectrogramConfig = useCallback(\n (trackId: string, config: SpectrogramConfig, colorMap?: ColorMapValue) => {\n setTrackSpectrogramOverrides((prev) => {\n const next = new Map(prev);\n const existing = next.get(trackId);\n next.set(trackId, {\n renderMode: existing?.renderMode ?? 'waveform',\n config,\n ...(colorMap !== undefined ? { colorMap } : { colorMap: existing?.colorMap }),\n });\n return next;\n });\n },\n []\n );\n\n const registerSpectrogramCanvases = useCallback(\n (clipId: string, channelIndex: number, canvasIds: string[], canvasWidths: number[]) => {\n const registry = spectrogramCanvasRegistryRef.current;\n if (!registry.has(clipId)) {\n registry.set(clipId, new Map());\n }\n // Replace: SpectrogramChannel passes ALL currently-registered canvas IDs\n // (not just new ones), so replacing gives the correct full set.\n registry.get(clipId)!.set(channelIndex, { canvasIds, canvasWidths });\n setSpectrogramCanvasVersion((v) => v + 1);\n },\n []\n );\n\n const unregisterSpectrogramCanvases = useCallback((clipId: string, channelIndex: number) => {\n const registry = spectrogramCanvasRegistryRef.current;\n const clipChannels = registry.get(clipId);\n if (clipChannels) {\n clipChannels.delete(channelIndex);\n if (clipChannels.size === 0) {\n registry.delete(clipId);\n }\n }\n }, []);\n\n const renderMenuItems = useCallback(\n (props: {\n renderMode: string;\n onRenderModeChange: (mode: RenderMode) => void;\n onOpenSettings: () => void;\n onClose?: () => void;\n }) => {\n return SpectrogramMenuItems({\n renderMode: props.renderMode as RenderMode,\n onRenderModeChange: props.onRenderModeChange,\n onOpenSettings: props.onOpenSettings,\n onClose: props.onClose,\n });\n },\n []\n );\n\n const value: SpectrogramIntegration = useMemo(\n () => ({\n trackSpectrogramOverrides,\n spectrogramWorkerApi: spectrogramWorkerReady ? spectrogramWorkerRef.current : null,\n spectrogramConfig,\n spectrogramColorMap,\n setTrackRenderMode,\n setTrackSpectrogramConfig,\n registerSpectrogramCanvases,\n unregisterSpectrogramCanvases,\n renderMenuItems,\n SettingsModal: SpectrogramSettingsModal,\n getColorMap,\n getFrequencyScale: getFrequencyScale as (\n name: string\n ) => (f: number, minF: number, maxF: number) => number,\n }),\n [\n trackSpectrogramOverrides,\n spectrogramWorkerReady,\n spectrogramConfig,\n spectrogramColorMap,\n setTrackRenderMode,\n setTrackSpectrogramConfig,\n registerSpectrogramCanvases,\n unregisterSpectrogramCanvases,\n renderMenuItems,\n ]\n );\n\n return <SpectrogramIntegrationProvider value={value}>{children}</SpectrogramIntegrationProvider>;\n};\n"],"mappings":"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AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EACnG;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EACnG;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EACnG;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EACnG;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EACnG;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EACnG;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EACnG;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EACnG;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAC1G;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAC3G;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAC3G;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAC3G;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAC3G;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAC3G;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAC3G;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAC3G;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAC3G;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAC3G;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAC3G;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAC3G;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAC3G;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAC3G;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EACzG;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAC5G;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAC5G;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAC5G;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAC5G;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAC5G;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAC5G;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAC9G,CAAC;AAGD,IAAM,YAAY,IAAI,WAAW;AAAA,EAC/B;AAAA,EAAG;AAAA,EAAG;AAAA,EAAG;AAAA,EAAG;AAAA,EAAG;AAAA,EAAG;AAAA,EAAG;AAAA,EAAG;AAAA,EAAG;AAAA,EAAG;AAAA,EAAG;AAAA,EAAG;AAAA,EAAG;AAAA,EAAG;AAAA,EAAG;AAAA,EAAG;AAAA,EAAG;AAAA,EAAI;AAAA,EAAG;AAAA,EAAG;AAAA,EAAI;AAAA,EAAG;AAAA,EAAG;AAAA,EACvE;AAAA,EAAG;AAAA,EAAG;AAAA,EAAI;AAAA,EAAG;AAAA,EAAG;AAAA,EAAI;AAAA,EAAG;AAAA,EAAG;AAAA,EAAI;AAAA,EAAG;AAAA,EAAG;AAAA,EAAI;AAAA,EAAG;AAAA,EAAG;AAAA,EAAI;AAAA,EAAG;AAAA,EAAG;AAAA,EAAI;AAAA,EAAG;AAAA,EAAG;AAAA,EAAI;AAAA,EAAG;AAAA,EAAG;AAAA,EAC5E;AAAA,EAAI;AAAA,EAAG;AAAA,EAAI;AAAA,EAAI;AAAA,EAAG;AAAA,EAAI;AAAA,EAAI;AAAA,EAAG;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EACzF;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAC5F;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAC5F;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAC9F;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EACnG;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EACnG;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EACnG;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EACvG;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAC3G;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAC3G;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAC3G;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAC3G;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAC3G;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAC3G;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAC3G;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAC3G;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAC3G;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAC3G;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EACpG;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EACxG;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAC5G;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAC5G;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAChH;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EACnH;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EACnH;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EACnH;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EACnH;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EACnH;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EACnH;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AACrH,CAAC;AAGD,IAAM,cAAc,IAAI,WAAW;AAAA,EACjC;AAAA,EAAG;AAAA,EAAG;AAAA,EAAG;AAAA,EAAG;AAAA,EAAG;AAAA,EAAG;AAAA,EAAG;AAAA,EAAG;AAAA,EAAG;AAAA,EAAG;AAAA,EAAG;AAAA,EAAG;AAAA,EAAG;AAAA,EAAG;AAAA,EAAI;AAAA,EAAG;AAAA,EAAG;AAAA,EAAI;AAAA,EAAG;AAAA,EAAG;AAAA,EAAI;AAAA,EAAG;AAAA,EAAG;AAAA,EACxE;AAAA,EAAG;AAAA,EAAG;AAAA,EAAI;AAAA,EAAG;AAAA,EAAG;AAAA,EAAI;AAAA,EAAG;AAAA,EAAG;AAAA,EAAI;AAAA,EAAG;AAAA,EAAG;AAAA,EAAI;AAAA,EAAG;AAAA,EAAG;AAAA,EAAI;AAAA,EAAG;AAAA,EAAG;AAAA,EAAI;AAAA,EAAG;AAAA,EAAG;AAAA,EAAI;AAAA,EAAI;AAAA,EAAG;AAAA,EAC7E;AAAA,EAAI;AAAA,EAAG;AAAA,EAAI;AAAA,EAAI;AAAA,EAAG;AAAA,EAAI;AAAA,EAAI;AAAA,EAAG;AAAA,EAAI;AAAA,EAAI;AAAA,EAAG;AAAA,EAAI;AAAA,EAAI;AAAA,EAAG;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EACvF;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAC5F;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAC5F;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAG;AAAA,EAAI;AAAA,EAAI;AAAA,EAAG;AAAA,EAAI;AAAA,EAAI;AAAA,EAAG;AAAA,EAAI;AAAA,EAAI;AAAA,EAAG;AAAA,EACxF;AAAA,EAAI;AAAA,EAAG;AAAA,EAAK;AAAA,EAAI;AAAA,EAAG;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EACjG;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EACnG;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EACnG;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAC3G;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAC3G;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAC3G;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAC3G;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EACzG;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EACpG;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EACpG;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EACpG;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EACpG;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EACpG;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EACpG;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EACrG;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAC5G;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAC5G;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAC5G;AAAA,EAAK;AAAA,EAAK;AAAA,EAAG;AAAA,EAAK;AAAA,EAAK;AAAA,EAAG;AAAA,EAAK;AAAA,EAAK;AAAA,EAAG;AAAA,EAAK;AAAA,EAAK;AAAA,EAAG;AAAA,EAAK;AAAA,EAAK;AAAA,EAAG;AAAA,EAAK;AAAA,EAAK;AAAA,EAAG;AAAA,EAAK;AAAA,EAAK;AAAA,EAAG;AAAA,EAAK;AAAA,EAAK;AAAA,EACrG;AAAA,EAAK;AAAA,EAAK;AAAA,EAAG;AAAA,EAAK;AAAA,EAAK;AAAA,EAAG;AAAA,EAAK;AAAA,EAAK;AAAA,EAAG;AAAA,EAAK;AAAA,EAAK;AAAA,EAAG;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EACxG;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAC5G;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAC5G;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAC5G;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAC5G;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EACnH;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AACrH,CAAC;AAGD,IAAM,aAAa,IAAI,WAAW;AAAA,EAChC;AAAA,EAAG;AAAA,EAAG;AAAA,EAAG;AAAA,EAAG;AAAA,EAAG;AAAA,EAAG;AAAA,EAAG;AAAA,EAAG;AAAA,EAAG;AAAA,EAAG;AAAA,EAAG;AAAA,EAAG;AAAA,EAAG;AAAA,EAAG;AAAA,EAAG;AAAA,EAAG;AAAA,EAAG;AAAA,EAAG;AAAA,EAAG;AAAA,EAAG;AAAA,EAAG;AAAA,EAAG;AAAA,EAAG;AAAA,EACrE;AAAA,EAAG;AAAA,EAAG;AAAA,EAAG;AAAA,EAAG;AAAA,EAAG;AAAA,EAAI;AAAA,EAAG;AAAA,EAAG;AAAA,EAAI;AAAA,EAAG;AAAA,EAAI;AAAA,EAAI;AAAA,EAAG;AAAA,EAAI;AAAA,EAAI;AAAA,EAAG;AAAA,EAAI;AAAA,EAAI;AAAA,EAAG;AAAA,EAAI;AAAA,EAAI;AAAA,EAAG;AAAA,EAAI;AAAA,EAChF;AAAA,EAAG;AAAA,EAAI;AAAA,EAAI;AAAA,EAAG;AAAA,EAAI;AAAA,EAAI;AAAA,EAAG;AAAA,EAAI;AAAA,EAAI;AAAA,EAAG;AAAA,EAAI;AAAA,EAAI;AAAA,EAAG;AAAA,EAAI;AAAA,EAAI;AAAA,EAAG;AAAA,EAAI;AAAA,EAAI;AAAA,EAAG;AAAA,EAAI;AAAA,EAAI;AAAA,EAAG;AAAA,EAAI;AAAA,EACpF;AAAA,EAAG;AAAA,EAAI;AAAA,EAAI;AAAA,EAAG;AAAA,EAAI;AAAA,EAAI;AAAA,EAAG;AAAA,EAAI;AAAA,EAAI;AAAA,EAAG;AAAA,EAAI;AAAA,EAAI;AAAA,EAAG;AAAA,EAAI;AAAA,EAAI;AAAA,EAAG;AAAA,EAAI;AAAA,EAAI;AAAA,EAAG;AAAA,EAAI;AAAA,EAAI;AAAA,EAAG;AAAA,EAAI;AAAA,EACpF;AAAA,EAAG;AAAA,EAAI;AAAA,EAAI;AAAA,EAAG;AAAA,EAAI;AAAA,EAAI;AAAA,EAAG;AAAA,EAAI;AAAA,EAAI;AAAA,EAAG;AAAA,EAAI;AAAA,EAAI;AAAA,EAAG;AAAA,EAAI;AAAA,EAAI;AAAA,EAAG;AAAA,EAAI;AAAA,EAAI;AAAA,EAAG;AAAA,EAAI;AAAA,EAAI;AAAA,EAAG;AAAA,EAAI;AAAA,EACpF;AAAA,EAAG;AAAA,EAAI;AAAA,EAAI;AAAA,EAAG;AAAA,EAAI;AAAA,EAAI;AAAA,EAAG;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EACzF;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAClG;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EACnG;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EACnG;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EACnG;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EACxG;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAC3G;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAC3G;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAC3G;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAC3G;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAC3G;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAC3G;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAC3G;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAC3G;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EACpG;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EAAI;AAAA,EAAK;AAAA,EAAI;AAAA,EACpG;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAC5G;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAC5G;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAC5G;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAC5G;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAC5G;AAAA,EAAK;AAAA,EAAK;AAAA,EAAI;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAClH;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EACnH;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EACnH;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EACnH;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAA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","names":["FFT","window","window","styled","import_styled_components","import_jsx_runtime","styled","import_react","import_browser","import_jsx_runtime","channelDataArrays"]}