@ozdemirburak/morse-code-translator 6.0.0 → 8.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.
@@ -1 +1 @@
1
- {"version":3,"file":"morse-code-translator.es.js","sources":["../src/characters.ts","../src/options.ts","../src/audio.ts","../src/index.ts"],"sourcesContent":["import type { Characters, Options } from './types.js';\n\nconst baseCharacters: Characters = {\n '1': { // Latin => https://en.wikipedia.org/wiki/Morse_code\n 'A': '01', 'B': '1000', 'C': '1010', 'D': '100', 'E': '0', 'F': '0010',\n 'G': '110', 'H': '0000', 'I': '00', 'J': '0111', 'K': '101', 'L': '0100',\n 'M': '11', 'N': '10', 'O': '111', 'P': '0110', 'Q': '1101', 'R': '010',\n 'S': '000', 'T': '1', 'U': '001', 'V': '0001', 'W': '011', 'X': '1001',\n 'Y': '1011', 'Z': '1100'\n },\n '2': { // Numbers\n '0': '11111', '1': '01111', '2': '00111', '3': '00011', '4': '00001',\n '5': '00000', '6': '10000', '7': '11000', '8': '11100', '9': '11110'\n },\n '3': { // Punctuation\n '.': '010101', ',': '110011', '?': '001100', '\\'': '011110', '!': '101011', '/': '10010',\n '(': '10110', ')': '101101', '&': '01000', ':': '111000', ';': '101010', '=': '10001',\n '+': '01010', '-': '100001', '_': '001101', '\"': '010010', '$': '0001001', '@': '011010',\n '¿': '00101', '¡': '110001'\n },\n '4': { // Latin Extended => https://ham.stackexchange.com/questions/1379/international-characters-in-morse-code\n 'Ã': '01101', 'Á': '01101', 'Å': '01101', 'À': '01101', 'Â': '01101', 'Ä': '0101',\n 'Ą': '0101', 'Æ': '0101', 'Ç': '10100', 'Ć': '10100', 'Ĉ': '10100', 'Č': '110',\n 'Ð': '00110', 'È': '01001', 'Ę': '00100', 'Ë': '00100', 'É': '00100',\n 'Ê': '10010', 'Ğ': '11010', 'Ĝ': '11010', 'Ĥ': '1111', 'İ': '01001', 'Ï': '10011',\n 'Ì': '01110', 'Ĵ': '01110', 'Ł': '01001', 'Ń': '11011', 'Ñ': '11011', 'Ó': '1110',\n 'Ò': '1110', 'Ö': '1110', 'Ô': '1110', 'Ø': '1110', 'Ś': '0001000', 'Ş': '01100',\n 'Ș': '1111', 'Š': '1111', 'Ŝ': '00010', 'ß': '000000', 'Þ': '01100', 'Ü': '0011',\n 'Ù': '0011', 'Ŭ': '0011', 'Ž': '11001', 'Ź': '110010', 'Ż': '11001'\n },\n '5': { // Cyrillic Alphabet => https://en.wikipedia.org/wiki/Russian_Morse_code\n 'А': '01', 'Б': '1000', 'В': '011', 'Г': '110', 'Д': '100', 'Е': '0',\n 'Ж': '0001', 'З': '1100', 'И': '00', 'Й': '0111', 'К': '101', 'Л': '0100',\n 'М': '11', 'Н': '10', 'О': '111', 'П': '0110', 'Р': '010', 'С': '000',\n 'Т': '1', 'У': '001', 'Ф': '0010', 'Х': '0000', 'Ц': '1010', 'Ч': '1110',\n 'Ш': '1111', 'Щ': '1101', 'Ъ': '11011', 'Ы': '1011', 'Ь': '1001', 'Э': '00100',\n 'Ю': '0011', 'Я': '0101', 'Ї': '01110', 'Є': '00100', 'І': '00', 'Ґ': '110'\n },\n '6': { // Greek Alphabet => https://en.wikipedia.org/wiki/Morse_code_for_non-Latin_alphabets\n 'Α': '01', 'Β': '1000', 'Γ': '110', 'Δ': '100', 'Ε': '0', 'Ζ': '1100',\n 'Η': '0000', 'Θ': '1010', 'Ι': '00', 'Κ': '101', 'Λ': '0100', 'Μ': '11',\n 'Ν': '10', 'Ξ': '1001', 'Ο': '111', 'Π': '0110', 'Ρ': '010', 'Σ': '000',\n 'Τ': '1', 'Υ': '1011', 'Φ': '0010', 'Χ': '1111', 'Ψ': '1101', 'Ω': '011'\n },\n '7': { // Hebrew Alphabet => https://en.wikipedia.org/wiki/Morse_code_for_non-Latin_alphabets\n 'א': '01', 'ב': '1000', 'ג': '110', 'ד': '100', 'ה': '111', 'ו': '0',\n 'ז': '1100', 'ח': '0000', 'ט': '001', 'י': '00', 'כ': '101', 'ל': '0100',\n 'מ': '11', 'נ': '10', 'ס': '1010', 'ע': '0111', 'פ': '0110', 'צ': '011',\n 'ק': '1101', 'ר': '010', 'ש': '000', 'ת': '1'\n },\n '8': { // Arabic Alphabet => https://en.wikipedia.org/wiki/Morse_code_for_non-Latin_alphabets\n 'ا': '01', 'ب': '1000', 'ت': '1', 'ث': '1010', 'ج': '0111', 'ح': '0000',\n 'خ': '111', 'د': '100', 'ذ': '1100', 'ر': '010', 'ز': '1110', 'س': '000',\n 'ش': '1111', 'ص': '1001', 'ض': '0001', 'ط': '001', 'ظ': '1011', 'ع': '0101',\n 'غ': '110', 'ف': '0010', 'ق': '1101', 'ك': '101', 'ل': '0100', 'م': '11',\n 'ن': '10', 'ه': '00100', 'و': '011', 'ي': '00', 'ﺀ': '0'\n },\n '9': { // Persian Alphabet => https://en.wikipedia.org/wiki/Morse_code_for_non-Latin_alphabets\n 'ا': '01', 'ب': '1000', 'پ': '0110', 'ت': '1', 'ث': '1010', 'ج': '0111',\n 'چ': '1110', 'ح': '0000', 'خ': '1001', 'د': '100', 'ذ': '0001', 'ر': '010',\n 'ز': '1100', 'ژ': '110', 'س': '000', 'ش': '1111', 'ص': '0101', 'ض': '00100',\n 'ط': '001', 'ظ': '1011', 'ع': '111', 'غ': '0011', 'ف': '0010', 'ق': '111000',\n 'ک': '101', 'گ': '1101', 'ل': '0100', 'م': '11', 'ن': '10', 'و': '011',\n 'ه': '0', 'ی': '00'\n },\n '10': { // Japanese Alphabet => https://ja.wikipedia.org/wiki/%E3%83%A2%E3%83%BC%E3%83%AB%E3%82%B9%E7%AC%A6%E5%8F%B7#%E5%92%8C%E6%96%87%E3%83%A2%E3%83%BC%E3%83%AB%E3%82%B9%E7%AC%A6%E5%8F%B7\n 'ア': '11011', 'カ': '0100', 'サ': '10101', 'タ': '10', 'ナ': '010', 'ハ': '1000',\n 'マ': '1001', 'ヤ': '011', 'ラ': '000', 'ワ': '101', 'イ': '01', 'キ': '10100',\n 'シ': '11010', 'チ': '0010', 'ニ': '1010', 'ヒ': '11001', 'ミ': '00101', 'リ': '110',\n 'ヰ': '01001', 'ウ': '001', 'ク': '0001', 'ス': '11101', 'ツ': '0110', 'ヌ': '0000',\n 'フ': '1100', 'ム': '1', 'ユ': '10011', 'ル': '10110', 'ン': '01010', 'エ': '10111',\n 'ケ': '1011', 'セ': '01110', 'テ': '01011', 'ネ': '1101', 'ヘ': '0', 'メ': '10001',\n 'レ': '111', 'ヱ': '01100', 'オ': '01000', 'コ': '1111', 'ソ': '1110', 'ト': '00100',\n 'ノ': '0011', 'ホ': '100', 'モ': '10010', 'ヨ': '11', 'ロ': '0101', 'ヲ': '0111',\n '゛': '00', '゜': '00110', '。': '010100', 'ー': '01101', '、': '010101',\n '(': '101101', ')': '010010'\n },\n '11': { // Korean Alphabet => https://ko.wikipedia.org/wiki/%EB%AA%A8%EC%8A%A4_%EB%B6%80%ED%98%B8\n 'ㄱ': '0100', 'ㄴ': '0010', 'ㄷ': '1000', 'ㄹ': '0001', 'ㅁ': '11', 'ㅂ': '011',\n 'ㅅ': '110', 'ㅇ': '101', 'ㅈ': '0110', 'ㅊ': '1010', 'ㅋ': '1001', 'ㅌ': '1100',\n 'ㅍ': '111', 'ㅎ': '0111', 'ㅏ': '0', 'ㅑ': '00', 'ㅓ': '1', 'ㅕ': '000',\n 'ㅗ': '01', 'ㅛ': '10', 'ㅜ': '0000', 'ㅠ': '010', 'ㅡ': '100', 'ㅣ': '001',\n 'ㅐ': '1101', 'ㅔ': '1011'\n },\n '12': { // Thai Alphabet => https://th.wikipedia.org/wiki/รหัสมอร์ส\n 'ก': '110', 'ข': '1010', 'ค': '101', 'ง': '10110', 'จ': '10010',\n 'ฉ': '1111', 'ช': '1001', 'ซ': '1100', 'ญ': '0111', 'ด': '100',\n 'ต': '1', 'ถ': '10100', 'ท': '10011', 'น': '10', 'บ': '1000',\n 'ป': '0110', 'ผ': '1101', 'ฝ': '10101', 'พ': '01100', 'ฟ': '0010',\n 'ม': '11', 'ย': '1011', 'ร': '010', 'ล': '0100', 'ว': '011',\n 'ส': '000', 'ห': '0000', 'อ': '10001', 'ฮ': '11011', 'ฤ': '01011',\n 'ะ': '01000', 'า': '01', 'ิ': '00100', 'ี': '00', 'ึ': '00110',\n 'ื': '0011', 'ุ': '00101', 'ู': '1110', 'เ': '0', 'แ': '0101',\n 'ไ': '01001', 'โ': '111', 'ำ': '00010', '่': '001', '้': '0001',\n '๊': '11000', '๋': '01010', 'ั': '01101', '็': '11100', '์': '11001',\n 'ๆ': '10111', 'ฯ': '11010'\n }\n};\n\nconst getCharacters = (options: Options) => ({\n ...baseCharacters,\n '0': baseCharacters[options.priority],\n '1': {\n ...baseCharacters['1'],\n [options.separator]: options.space\n }\n});\n\nconst getMappedCharacters = (options: Options, usePriority: boolean) => {\n const mapped: Characters = {};\n const characters = getCharacters(options);\n for (const set in characters) {\n mapped[set] = {};\n const charSet = characters[set as keyof typeof characters];\n if (charSet) {\n for (const key in charSet) {\n mapped[set][key] = charSet[key].replace(/0/g, options.dot).replace(/1/g, options.dash);\n }\n }\n }\n if (!usePriority) {\n delete mapped['0'];\n }\n return mapped;\n};\n\nconst swapCharacters = (options: Options) => {\n const swapped: Record<string, string> = {};\n const mappedCharacters = getMappedCharacters(options, true);\n for (const set in mappedCharacters) {\n for (const key in mappedCharacters[set]) {\n if (typeof swapped[mappedCharacters[set][key]] === 'undefined') {\n swapped[mappedCharacters[set][key]] = key;\n }\n }\n }\n return swapped;\n};\n\nexport {\n getCharacters,\n getMappedCharacters,\n swapCharacters\n};\n","import type { Options } from './types.js';\n\nconst getOptions = (opts: Partial<Options> = {}): Options => {\n const options: Options = {\n ...opts,\n dash: opts.dash || '-',\n dot: opts.dot || '.',\n space: opts.space || '/',\n separator: opts.separator || ' ',\n invalid: opts.invalid || '#',\n priority: opts.priority || 1,\n wpm: opts.wpm, // words per minute - PARIS method used in favour of unit/fwUnit options\n unit: opts.unit || 0.08, // period of one unit, in seconds, 1.2 / c where c is speed of transmission, in words per minute\n fwUnit: opts.fwUnit || opts.unit || 0.08, // Farnsworth unit to control intercharacter and interword gaps\n volume: opts.volume || 100,\n oscillator: {\n ...opts.oscillator,\n type: opts.oscillator?.type || 'sine', // sine, square, sawtooth, triangle\n frequency: opts.oscillator?.frequency || 500, // value in hertz\n onended: opts.oscillator?.onended || null // event that fires when the tone has stopped playing\n }\n };\n return options;\n};\n\nexport default getOptions;\n","import type { Options, AudioResult, AudioState, AudioEvents } from './types.js';\n\n// Audio constants\nconst SAMPLE_RATE = 44100;\nconst CHANNELS = 1;\nconst BITS_PER_SAMPLE = 16;\n\n// Morse timing constants (in units)\nconst DOT_DURATION = 1;\nconst DASH_DURATION = 3;\nconst INTRA_CHARACTER_GAP = 1;\nconst INTER_CHARACTER_GAP = 3;\nconst WORD_GAP = 7;\n\n// WPM calculation constant (PARIS method)\nconst WPM_UNIT_DIVISOR = 50;\n\ntype GainTiming = [number, number];\ntype GainTimings = [GainTiming[], number];\n\nconst getGainTimings = (morse: string, opts: Options, currentTime = 0): GainTimings => {\n const timings: GainTiming[] = [];\n let { unit, fwUnit } = opts;\n let time = 0;\n\n if (opts.wpm) {\n // WPM mode uses standardized units (PARIS method)\n unit = fwUnit = 60 / (opts.wpm * WPM_UNIT_DIVISOR);\n }\n\n timings.push([0, time]);\n\n const addTiming = (gainValue: number, duration: number, useUnit = true) => {\n timings.push([gainValue, currentTime + time]);\n time += duration * (useUnit ? unit : fwUnit);\n };\n\n const tone = (duration: number) => addTiming(opts.volume / 100.0, duration);\n const silence = (duration: number) => addTiming(0, duration);\n const gap = (duration: number) => addTiming(0, duration, false);\n\n for (let i = 0, needsSilence = false; i <= morse.length; i++) {\n const char = morse[i];\n const nextChar = morse[i + 1];\n const prevChar = morse[i - 1];\n\n if (char === opts.space) {\n gap(WORD_GAP);\n needsSilence = false;\n } else if (char === opts.dot) {\n if (needsSilence) silence(INTRA_CHARACTER_GAP);\n tone(DOT_DURATION);\n needsSilence = true;\n } else if (char === opts.dash) {\n if (needsSilence) silence(INTRA_CHARACTER_GAP);\n tone(DASH_DURATION);\n needsSilence = true;\n } else if (\n nextChar !== undefined && nextChar !== opts.space &&\n prevChar !== undefined && prevChar !== opts.space\n ) {\n // Inter-character gap (separator between characters)\n gap(INTER_CHARACTER_GAP);\n needsSilence = false;\n }\n }\n\n return [timings, time];\n};\n\n/**\n * Encodes audio samples to WAV format\n * Based on: https://github.com/mattdiamond/Recorderjs/blob/master/src/recorder.js#L155\n */\nconst encodeWAV = (sampleRate: number, samples: Float32Array): DataView => {\n const bytesPerSample = BITS_PER_SAMPLE / 8;\n const blockAlign = CHANNELS * bytesPerSample;\n const byteRate = sampleRate * blockAlign;\n const dataSize = samples.length * bytesPerSample;\n const bufferSize = 44 + dataSize; // WAV header is 44 bytes\n\n const buffer = new ArrayBuffer(bufferSize);\n const view = new DataView(buffer);\n\n const writeString = (offset: number, text: string) => {\n for (let i = 0; i < text.length; i++) {\n view.setUint8(offset + i, text.charCodeAt(i));\n }\n };\n\n const floatTo16BitPCM = (offset: number, input: Float32Array) => {\n for (let i = 0; i < input.length; i++, offset += bytesPerSample) {\n const sample = Math.max(-1, Math.min(1, input[i]));\n const value = sample < 0 ? sample * 0x8000 : sample * 0x7FFF;\n view.setInt16(offset, value, true);\n }\n };\n\n // RIFF chunk descriptor\n writeString(0, 'RIFF');\n view.setUint32(4, bufferSize - 8, true); // File size - 8\n writeString(8, 'WAVE');\n\n // fmt sub-chunk\n writeString(12, 'fmt ');\n view.setUint32(16, 16, true); // Subchunk1Size (16 for PCM)\n view.setUint16(20, 1, true); // AudioFormat (1 = PCM)\n view.setUint16(22, CHANNELS, true);\n view.setUint32(24, sampleRate, true);\n view.setUint32(28, byteRate, true);\n view.setUint16(32, blockAlign, true);\n view.setUint16(34, BITS_PER_SAMPLE, true);\n\n // data sub-chunk\n writeString(36, 'data');\n view.setUint32(40, dataSize, true);\n floatTo16BitPCM(44, samples);\n\n return view;\n};\n\nconst audio = (morse: string, options: Options): AudioResult => {\n const AudioContextClass = window.AudioContext || (window as any).webkitAudioContext;\n const OfflineAudioContextClass = window.OfflineAudioContext || (window as any).webkitOfflineAudioContext;\n\n if (!AudioContextClass || !OfflineAudioContextClass) {\n throw new Error('Web Audio API is not supported in this browser. Please use a modern browser with Web Audio API support.');\n }\n\n const context = new AudioContextClass();\n const [gainValues, totalTime] = getGainTimings(morse, options);\n const bufferLength = Math.ceil(SAMPLE_RATE * totalTime);\n const offlineContext = new OfflineAudioContextClass(CHANNELS, bufferLength, SAMPLE_RATE);\n\n const oscillator = offlineContext.createOscillator();\n const gainNode = offlineContext.createGain();\n\n oscillator.type = options.oscillator.type as OscillatorType;\n oscillator.frequency.value = options.oscillator.frequency ?? 500;\n\n gainValues.forEach(([value, time]) => {\n gainNode.gain.setValueAtTime(value, time);\n });\n\n oscillator.connect(gainNode);\n gainNode.connect(offlineContext.destination);\n\n // State management\n let source: AudioBufferSourceNode | null = null;\n let renderedBuffer: AudioBuffer | null = null;\n let state: AudioState = 'ready';\n let pausedAt = 0;\n let startTime = 0;\n let timeout: number | null = null;\n\n const events: AudioEvents = options.events || {};\n\n // Backwards compatibility: support old onended in oscillator options\n if (options.oscillator.onended && !events.onended) {\n events.onended = options.oscillator.onended as any;\n }\n\n // Render the audio buffer\n const render = new Promise<void>((resolve, reject) => {\n oscillator.start(0);\n offlineContext.startRendering();\n offlineContext.oncomplete = (e) => {\n try {\n renderedBuffer = e.renderedBuffer;\n state = 'ready';\n events.onready?.();\n resolve();\n } catch (err) {\n reject(err);\n }\n };\n offlineContext.addEventListener('error', (err) => {\n reject(err);\n });\n });\n\n // Helper: Create a new audio source\n const createSource = (): AudioBufferSourceNode => {\n const newSource = context.createBufferSource();\n newSource.buffer = renderedBuffer;\n newSource.connect(context.destination);\n newSource.onended = () => {\n const currentTime = getCurrentTime();\n // Only fire onended if playback completed naturally (not stopped/paused)\n if (state === 'playing' && currentTime >= totalTime - 0.01) {\n state = 'stopped';\n pausedAt = 0;\n events.onended?.();\n }\n };\n return newSource;\n };\n\n const play = async () => {\n await render;\n\n // Resume audio context if suspended\n if (context.state === 'suspended') {\n await context.resume();\n }\n\n // If already playing, do nothing\n if (state === 'playing') {\n return;\n }\n\n // Create new source if needed\n if (!source || source.buffer === null) {\n source = createSource();\n }\n\n // Start playback from pausedAt position\n source.start(context.currentTime, pausedAt);\n startTime = context.currentTime - pausedAt;\n state = 'playing';\n events.onstarted?.();\n\n // Set up auto-stop when playback completes\n const remainingTime = (totalTime - pausedAt) * 1000;\n timeout = window.setTimeout(() => {\n if (state === 'playing') {\n stop();\n }\n }, remainingTime);\n };\n\n const pause = () => {\n if (state !== 'playing') {\n return;\n }\n\n if (timeout !== null) {\n clearTimeout(timeout);\n timeout = null;\n }\n\n pausedAt = Math.min(context.currentTime - startTime, totalTime);\n\n if (source) {\n source.stop(0);\n source = null;\n }\n\n state = 'paused';\n events.onpaused?.();\n };\n\n const stop = (dispose = false) => {\n if (timeout !== null) {\n clearTimeout(timeout);\n timeout = null;\n }\n\n if (source) {\n try {\n source.stop(0);\n } catch (e) {\n // Ignore if already stopped\n }\n source = null;\n }\n\n const wasPlaying = state === 'playing';\n state = 'stopped';\n pausedAt = 0;\n startTime = 0;\n\n if (wasPlaying) {\n events.onstopped?.();\n }\n\n if (dispose) {\n renderedBuffer = null;\n }\n };\n\n const seek = async (time: number) => {\n const wasPlaying = state === 'playing';\n const clampedTime = Math.max(0, Math.min(time, totalTime));\n\n // Stop current playback\n if (source) {\n if (timeout !== null) {\n clearTimeout(timeout);\n timeout = null;\n }\n try {\n source.stop(0);\n } catch (e) {\n // Ignore\n }\n source = null;\n }\n\n pausedAt = clampedTime;\n events.onseeked?.(clampedTime);\n\n // Resume playback if was playing\n if (wasPlaying) {\n state = 'paused'; // Set to paused so play() will work\n await play();\n }\n };\n\n const dispose = () => {\n stop(true);\n if (context.state !== 'closed') {\n context.close();\n }\n };\n\n const getCurrentTime = (): number => {\n if (state === 'playing') {\n return Math.min(context.currentTime - startTime, totalTime);\n }\n return pausedAt;\n };\n\n const getTotalTime = (): number => {\n return totalTime;\n };\n\n const getState = (): AudioState => {\n return state;\n };\n\n const getWaveBlob = async (): Promise<Blob> => {\n await render;\n if (!renderedBuffer) {\n throw new Error('Audio buffer not available');\n }\n const waveData = encodeWAV(offlineContext.sampleRate, renderedBuffer.getChannelData(0));\n // Create a proper Uint8Array copy for Blob\n const uint8Array = new Uint8Array(waveData.byteLength);\n for (let i = 0; i < waveData.byteLength; i++) {\n uint8Array[i] = waveData.getUint8(i);\n }\n return new Blob([uint8Array], { type: 'audio/wav' });\n };\n\n const getWaveUrl = async () => {\n const audioBlob = await getWaveBlob();\n return URL.createObjectURL(audioBlob);\n };\n\n const exportWave = async (filename: string = 'morse.wav') => {\n const waveUrl = await getWaveUrl();\n const anchor = document.createElement('a');\n anchor.href = waveUrl;\n anchor.target = '_blank';\n anchor.download = filename;\n anchor.click();\n };\n\n return {\n // Playback control\n play,\n pause,\n stop,\n seek,\n dispose,\n\n // Playback information\n getCurrentTime,\n getTotalTime,\n getState,\n\n // Export functionality\n getWaveBlob,\n getWaveUrl,\n exportWave,\n\n // Context access (for advanced users)\n context,\n oscillator,\n gainNode,\n };\n};\n\nexport default audio;\n","import { getCharacters, getMappedCharacters, swapCharacters } from './characters.js';\nimport getOptions from './options.js';\nimport getAudio from './audio.js';\nimport type { Options, Characters, AudioResult } from './types.js';\n\nexport const encode = (text: string, opts?: Partial<Options>): string => {\n const options = getOptions(opts);\n const characters = getCharacters(options);\n return [...text.replace(/\\s+/g, options.separator).trim().toLocaleUpperCase()]\n .map((character) => {\n for (const set in characters) {\n const charSet = characters[set as keyof typeof characters];\n if (charSet && charSet[character]) {\n return charSet[character];\n }\n }\n return options.invalid;\n })\n .join(options.separator)\n .replace(/0/g, options.dot)\n .replace(/1/g, options.dash);\n};\n\nexport const decode = (morse: string, opts?: Partial<Options>): string => {\n const options = getOptions(opts);\n const swapped = swapCharacters(options);\n return morse\n .replace(/\\s+/g, options.separator)\n .trim()\n .split(options.separator)\n .map((characters) => {\n if (typeof swapped[characters] !== 'undefined') {\n return swapped[characters];\n }\n return options.invalid;\n })\n .join('');\n};\n\nexport const characters = (options?: Partial<Options>, usePriority: boolean = false): Characters => {\n return getMappedCharacters(getOptions(options), usePriority);\n};\n\nexport const audio = (text: string, opts?: Partial<Options>, morseString?: string): AudioResult => {\n const morse = morseString || encode(text, opts);\n const options = getOptions(opts);\n return getAudio(morse, options);\n};\n\n// Export types\nexport type { Options, Characters, AudioResult, Oscillator, AudioState, AudioEvents } from './types.js';\n\nexport default {\n encode,\n decode,\n characters,\n audio,\n};\n"],"names":["baseCharacters","getCharacters","options","getMappedCharacters","usePriority","mapped","characters","set","charSet","key","swapCharacters","swapped","mappedCharacters","getOptions","opts","SAMPLE_RATE","CHANNELS","BITS_PER_SAMPLE","DOT_DURATION","DASH_DURATION","INTRA_CHARACTER_GAP","INTER_CHARACTER_GAP","WORD_GAP","WPM_UNIT_DIVISOR","getGainTimings","morse","currentTime","timings","unit","fwUnit","time","addTiming","gainValue","duration","useUnit","tone","silence","gap","i","needsSilence","char","nextChar","prevChar","encodeWAV","sampleRate","samples","bytesPerSample","blockAlign","byteRate","dataSize","bufferSize","buffer","view","writeString","offset","text","floatTo16BitPCM","input","sample","value","audio","AudioContextClass","OfflineAudioContextClass","context","gainValues","totalTime","bufferLength","offlineContext","oscillator","gainNode","source","renderedBuffer","state","pausedAt","startTime","timeout","events","render","resolve","reject","e","err","createSource","newSource","getCurrentTime","play","remainingTime","stop","pause","dispose","wasPlaying","seek","clampedTime","getTotalTime","getState","getWaveBlob","waveData","uint8Array","getWaveUrl","audioBlob","filename","waveUrl","anchor","encode","character","decode","morseString","getAudio","index"],"mappings":"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"}
1
+ {"version":3,"file":"morse-code-translator.es.js","names":["audio","getAudio","baseCharacters","\"A\"","\"B\"","\"C\"","\"D\"","\"E\"","\"F\"","\"G\"","\"H\"","\"I\"","\"J\"","\"K\"","\"L\"","\"M\"","\"N\"","\"O\"","\"P\"","\"Q\"","\"R\"","\"S\"","\"T\"","\"U\"","\"V\"","\"W\"","\"X\"","\"Y\"","\"Z\"","\"_\"","\"$\"","\"Ã\"","\"Á\"","\"Å\"","\"À\"","\"Â\"","\"Ä\"","\"Ą\"","\"Æ\"","\"Ç\"","\"Ć\"","\"Ĉ\"","\"Č\"","\"Ð\"","\"È\"","\"É\"","\"Ę\"","\"Ë\"","\"Ê\"","\"Ğ\"","\"Ĝ\"","\"Ĥ\"","\"İ\"","\"Ï\"","\"Ì\"","\"Ĵ\"","\"Ł\"","\"Ń\"","\"Ñ\"","\"Ó\"","\"Ò\"","\"Ö\"","\"Ô\"","\"Ø\"","\"Ś\"","\"Ş\"","\"Ș\"","\"Š\"","\"Ŝ\"","\"Þ\"","\"Ü\"","\"Ù\"","\"Ŭ\"","\"Ž\"","\"Ź\"","\"Ż\"","\"А\"","\"Б\"","\"В\"","\"Г\"","\"Д\"","\"Е\"","\"Ж\"","\"З\"","\"И\"","\"Й\"","\"К\"","\"Л\"","\"М\"","\"Н\"","\"О\"","\"П\"","\"Р\"","\"С\"","\"Т\"","\"У\"","\"Ф\"","\"Х\"","\"Ц\"","\"Ч\"","\"Ш\"","\"Щ\"","\"Ъ\"","\"Ы\"","\"Ь\"","\"Э\"","\"Ю\"","\"Я\"","\"Ї\"","\"Є\"","\"І\"","\"Ґ\"","\"Ё\"","\"Α\"","\"Β\"","\"Γ\"","\"Δ\"","\"Ε\"","\"Ζ\"","\"Η\"","\"Θ\"","\"Ι\"","\"Κ\"","\"Λ\"","\"Μ\"","\"Ν\"","\"Ξ\"","\"Ο\"","\"Π\"","\"Ρ\"","\"Σ\"","\"Τ\"","\"Υ\"","\"Φ\"","\"Χ\"","\"Ψ\"","\"Ω\"","\"א\"","\"ב\"","\"ג\"","\"ד\"","\"ה\"","\"ו\"","\"ז\"","\"ח\"","\"ט\"","\"י\"","\"כ\"","\"ל\"","\"מ\"","\"נ\"","\"ס\"","\"ע\"","\"פ\"","\"צ\"","\"ק\"","\"ר\"","\"ש\"","\"ת\"","\"ך\"","\"ם\"","\"ן\"","\"ף\"","\"ץ\"","\"ا\"","\"ب\"","\"ت\"","\"ث\"","\"ج\"","\"ح\"","\"خ\"","\"د\"","\"ذ\"","\"ر\"","\"ز\"","\"س\"","\"ش\"","\"ص\"","\"ض\"","\"ط\"","\"ظ\"","\"ع\"","\"غ\"","\"ف\"","\"ق\"","\"ك\"","\"ل\"","\"م\"","\"ن\"","\"ه\"","\"و\"","\"ي\"","\"ء\"","\"ﺀ\"","\"پ\"","\"چ\"","\"ژ\"","\"ک\"","\"گ\"","\"ی\"","\"ア\"","\"カ\"","\"サ\"","\"タ\"","\"ナ\"","\"ハ\"","\"マ\"","\"ヤ\"","\"ラ\"","\"ワ\"","\"イ\"","\"キ\"","\"シ\"","\"チ\"","\"ニ\"","\"ヒ\"","\"ミ\"","\"リ\"","\"ヰ\"","\"ウ\"","\"ク\"","\"ス\"","\"ツ\"","\"ヌ\"","\"フ\"","\"ム\"","\"ユ\"","\"ル\"","\"ン\"","\"エ\"","\"ケ\"","\"セ\"","\"テ\"","\"ネ\"","\"ヘ\"","\"メ\"","\"レ\"","\"ヱ\"","\"オ\"","\"コ\"","\"ソ\"","\"ト\"","\"ノ\"","\"ホ\"","\"モ\"","\"ヨ\"","\"ロ\"","\"ヲ\"","\"゛\"","\"゜\"","\"ー\"","\"ㄱ\"","\"ㄴ\"","\"ㄷ\"","\"ㄹ\"","\"ㅁ\"","\"ㅂ\"","\"ㅅ\"","\"ㅇ\"","\"ㅈ\"","\"ㅊ\"","\"ㅋ\"","\"ㅌ\"","\"ㅍ\"","\"ㅎ\"","\"ㅏ\"","\"ㅑ\"","\"ㅓ\"","\"ㅕ\"","\"ㅗ\"","\"ㅛ\"","\"ㅜ\"","\"ㅠ\"","\"ㅡ\"","\"ㅣ\"","\"ㅐ\"","\"ㅔ\"","\"ก\"","\"ข\"","\"ค\"","\"ง\"","\"จ\"","\"ฉ\"","\"ช\"","\"ซ\"","\"ญ\"","\"ด\"","\"ต\"","\"ถ\"","\"ท\"","\"น\"","\"บ\"","\"ป\"","\"ผ\"","\"ฝ\"","\"พ\"","\"ฟ\"","\"ม\"","\"ย\"","\"ร\"","\"ล\"","\"ว\"","\"ส\"","\"ห\"","\"อ\"","\"ฮ\"","\"ฤ\"","\"ะ\"","\"า\"","\"เ\"","\"แ\"","\"ไ\"","\"โ\"","\"ำ\"","\"ๆ\"","\"ฯ\"","\"ฃ\"","\"ฅ\"","\"ฆ\"","\"ศ\"","\"ษ\"","\"ฌ\"","\"ฎ\"","\"ฏ\"","\"ฐ\"","\"ฑ\"","\"ฒ\"","\"ธ\"","\"ณ\"","\"ภ\"","\"ฬ\"","\"ใ\"","CACHE_SIZE","cache","getTables","key","options","cached","mapped","sets","set","character","c","swapped","tables","getEncodeCharacters","swapCharacters","getMappedCharacters","copy","usePriority","tokenize","tokens","token","morse","o","index","part","MAX_FREQUENCY","SYMBOL_DEFAULTS","isPositiveNumber","value","isCharacterKey","symbol","isCodeLike","i","dot","dash","assertString","name","getSymbol","opts","getPriority","priority","validateSymbols","getOptions","input","unit","fwUnit","wpm","requestedFrequency","frequency","volume","requestedType","oscillatorType","SAMPLE_RATE","CHANNELS","BITS_PER_SAMPLE","WAV_HEADER_BYTES","MAX_WAV_DATA_BYTES","DOT_DURATION","DASH_DURATION","INTRA_CHARACTER_GAP","INTER_CHARACTER_GAP","WORD_GAP","WPM_UNIT_DIVISOR","RAMP_SECONDS","CACHED_CHUNKS","LIVE_FADE_SECONDS","MAX_PLAYBACK_RENDERS","PREFETCH_SECONDS","CANCELLED","getUnits","getToneSchedule","symbolOrder","tones","time","wordGapPending","durations","position","matched","duration","phaseDelay","tolerance","sampleRate","offset","createChunkPlan","count","startFrame","endFrame","guard","firstToneEndingAfter","low","high","mid","frame","boundaryAt","target","k","targetFrames","totalFrames","limit","tone","candidate","start","renderFrames","length","offlineContext","OfflineAudioContextClass","oscillator","gainNode","end","envelope","ramp","first","gain","initial","points","p","ramped","previousTime","previousValue","writeString","text","encodeWAVHeader","view","dataSize","floatTo16BitPCM","sample","safeCall","args","err","audio$1","scope","AudioContextClass","totalTime","plan","renderChunk","context","sources","fader","faderStartedAt","fadeEndsAt","scheduledEnd","renderingAhead","state","pausedAt","startTime","pendingPlay","shownState","epoch","getContext","events","chunks","queued","jobs","rendering","safeRender","forget","job","pump","wanted","enqueue","resolve","reject","getChunk","buffer","pending","ready","whenReady","stopSources","ctx","fading","stopAt","now","level","source","finish","scheduleChunk","when","fadeIn","myEpoch","scheduleAhead","failedStart","current","stop","play","needsResume","resuming","load","chunk","next","playing","following","renders","rendered","pause","wasActive","dispose","seek","requested","clampedTime","seekEpoch","getState","close","fadeLeft","getCurrentTime","getTotalTime","exporting","getWaveBlob","exportWav","parts","render","getWaveUrl","audioBlob","result","waveUrl","anchor","filename","HANGUL_BASE","HANGUL_END","CHOSEONG","JUNGSEONG","JONGSEONG","COMPOUND_JAMO","\"ㄲ\"","\"ㄸ\"","\"ㅃ\"","\"ㅆ\"","\"ㅉ\"","\"ㄳ\"","\"ㄵ\"","\"ㄶ\"","\"ㄺ\"","\"ㄻ\"","\"ㄼ\"","\"ㄽ\"","\"ㄾ\"","\"ㄿ\"","\"ㅀ\"","\"ㅄ\"","\"ㅒ\"","\"ㅖ\"","\"ㅘ\"","\"ㅙ\"","\"ㅚ\"","\"ㅝ\"","\"ㅞ\"","\"ㅟ\"","\"ㅢ\"","splitJamo","jamo","decomposeHangul","code","SMALL_KANA","\"ァ\"","\"ィ\"","\"ゥ\"","\"ェ\"","\"ォ\"","\"ッ\"","\"ャ\"","\"ュ\"","\"ョ\"","\"ヮ\"","\"ヵ\"","\"ヶ\"","HIRAGANA","KATAKANA","KATAKANA_ITERATION","WIDTH_VARIANTS","COMBINING_KANA_MARK","KANA_THEN_MARK","toStandaloneMark","mark","HEBREW_MARKS","ARABIC_MARKS","EASTERN_DIGITS","toDigit","digit","THAI_SARA_AM","PUNCTUATION","GREEK_WITH_MARKS","COMBINING_MARKS","foldKatakana","foldCharacter","normalizeText","run","letter","segmenter","clusters","segment","INVISIBLE","WHITESPACE","encode","characters","lookup","codes","push","unknown","decode","audio","morseString","src_default"],"sources":["../src/characters.ts","../src/tokenize.ts","../src/options.ts","../src/audio.ts","../src/normalize.ts","../src/index.ts"],"sourcesContent":["import type { Characters, Options } from './types.js';\n\nconst baseCharacters: Characters = {\n '1': { // Latin => https://en.wikipedia.org/wiki/Morse_code\n 'A': '01', 'B': '1000', 'C': '1010', 'D': '100', 'E': '0', 'F': '0010',\n 'G': '110', 'H': '0000', 'I': '00', 'J': '0111', 'K': '101', 'L': '0100',\n 'M': '11', 'N': '10', 'O': '111', 'P': '0110', 'Q': '1101', 'R': '010',\n 'S': '000', 'T': '1', 'U': '001', 'V': '0001', 'W': '011', 'X': '1001',\n 'Y': '1011', 'Z': '1100'\n },\n '2': { // Numbers\n '0': '11111', '1': '01111', '2': '00111', '3': '00011', '4': '00001',\n '5': '00000', '6': '10000', '7': '11000', '8': '11100', '9': '11110'\n },\n '3': { // Punctuation\n '.': '010101', ',': '110011', '?': '001100', '\\'': '011110', '!': '101011', '/': '10010',\n '(': '10110', ')': '101101', '&': '01000', ':': '111000', ';': '101010', '=': '10001',\n '+': '01010', '-': '100001', '_': '001101', '\"': '010010', '$': '0001001', '@': '011010',\n '¿': '00101', '¡': '110001'\n },\n '4': { // Latin Extended => https://ham.stackexchange.com/questions/1379/international-characters-in-morse-code\n 'Ã': '01101', 'Á': '01101', 'Å': '01101', 'À': '01101', 'Â': '01101', 'Ä': '0101',\n 'Ą': '0101', 'Æ': '0101', 'Ç': '10100', 'Ć': '10100', 'Ĉ': '10100', 'Č': '110',\n 'Ð': '00110', 'È': '01001', 'É': '00100', 'Ę': '00100', 'Ë': '00100',\n 'Ê': '10010', 'Ğ': '11010', 'Ĝ': '11010', 'Ĥ': '1111', 'İ': '01001', 'Ï': '10011',\n 'Ì': '01110', 'Ĵ': '01110', 'Ł': '01001', 'Ń': '11011', 'Ñ': '11011', 'Ó': '1110',\n 'Ò': '1110', 'Ö': '1110', 'Ô': '1110', 'Ø': '1110', 'Ś': '0001000', 'Ş': '01100',\n 'Ș': '1111', 'Š': '1111', 'Ŝ': '00010', 'Þ': '01100', 'Ü': '0011',\n 'Ù': '0011', 'Ŭ': '0011', 'Ž': '11001', 'Ź': '110010', 'Ż': '11001'\n },\n '5': { // Cyrillic Alphabet => https://en.wikipedia.org/wiki/Russian_Morse_code\n 'А': '01', 'Б': '1000', 'В': '011', 'Г': '110', 'Д': '100', 'Е': '0',\n 'Ж': '0001', 'З': '1100', 'И': '00', 'Й': '0111', 'К': '101', 'Л': '0100',\n 'М': '11', 'Н': '10', 'О': '111', 'П': '0110', 'Р': '010', 'С': '000',\n 'Т': '1', 'У': '001', 'Ф': '0010', 'Х': '0000', 'Ц': '1010', 'Ч': '1110',\n 'Ш': '1111', 'Щ': '1101', 'Ъ': '11011', 'Ы': '1011', 'Ь': '1001', 'Э': '00100',\n 'Ю': '0011', 'Я': '0101', 'Ї': '01110', 'Є': '00100', 'І': '00', 'Ґ': '110',\n 'Ё': '0' // sent as Е\n },\n '6': { // Greek Alphabet => https://en.wikipedia.org/wiki/Morse_code_for_non-Latin_alphabets\n 'Α': '01', 'Β': '1000', 'Γ': '110', 'Δ': '100', 'Ε': '0', 'Ζ': '1100',\n 'Η': '0000', 'Θ': '1010', 'Ι': '00', 'Κ': '101', 'Λ': '0100', 'Μ': '11',\n 'Ν': '10', 'Ξ': '1001', 'Ο': '111', 'Π': '0110', 'Ρ': '010', 'Σ': '000',\n 'Τ': '1', 'Υ': '1011', 'Φ': '0010', 'Χ': '1111', 'Ψ': '1101', 'Ω': '011'\n },\n '7': { // Hebrew Alphabet => https://en.wikipedia.org/wiki/Morse_code_for_non-Latin_alphabets\n 'א': '01', 'ב': '1000', 'ג': '110', 'ד': '100', 'ה': '111', 'ו': '0',\n 'ז': '1100', 'ח': '0000', 'ט': '001', 'י': '00', 'כ': '101', 'ל': '0100',\n 'מ': '11', 'נ': '10', 'ס': '1010', 'ע': '0111', 'פ': '0110', 'צ': '011',\n 'ק': '1101', 'ר': '010', 'ש': '000', 'ת': '1',\n // Final forms are positional variants of the same letters\n 'ך': '101', 'ם': '11', 'ן': '10', 'ף': '0110', 'ץ': '011'\n },\n '8': { // Arabic Alphabet => https://en.wikipedia.org/wiki/Morse_code_for_non-Latin_alphabets\n 'ا': '01', 'ب': '1000', 'ت': '1', 'ث': '1010', 'ج': '0111', 'ح': '0000',\n 'خ': '111', 'د': '100', 'ذ': '1100', 'ر': '010', 'ز': '1110', 'س': '000',\n 'ش': '1111', 'ص': '1001', 'ض': '0001', 'ط': '001', 'ظ': '1011', 'ع': '0101',\n 'غ': '110', 'ف': '0010', 'ق': '1101', 'ك': '101', 'ل': '0100', 'م': '11',\n 'ن': '10', 'ه': '00100', 'و': '011', 'ي': '00', 'ء': '0',\n 'ﺀ': '0' // isolated presentation form of ء, as listed on Wikipedia\n },\n '9': { // Persian Alphabet => https://en.wikipedia.org/wiki/Morse_code_for_non-Latin_alphabets\n 'ا': '01', 'ب': '1000', 'پ': '0110', 'ت': '1', 'ث': '1010', 'ج': '0111',\n 'چ': '1110', 'ح': '0000', 'خ': '1001', 'د': '100', 'ذ': '0001', 'ر': '010',\n 'ز': '1100', 'ژ': '110', 'س': '000', 'ش': '1111', 'ص': '0101', 'ض': '00100',\n 'ط': '001', 'ظ': '1011', 'ع': '111', 'غ': '0011', 'ف': '0010', 'ق': '111000',\n 'ک': '101', 'گ': '1101', 'ل': '0100', 'م': '11', 'ن': '10', 'و': '011',\n 'ه': '0', 'ی': '00'\n },\n '10': { // Japanese Alphabet => https://ja.wikipedia.org/wiki/%E3%83%A2%E3%83%BC%E3%83%AB%E3%82%B9%E7%AC%A6%E5%8F%B7#%E5%92%8C%E6%96%87%E3%83%A2%E3%83%BC%E3%83%AB%E3%82%B9%E7%AC%A6%E5%8F%B7\n 'ア': '11011', 'カ': '0100', 'サ': '10101', 'タ': '10', 'ナ': '010', 'ハ': '1000',\n 'マ': '1001', 'ヤ': '011', 'ラ': '000', 'ワ': '101', 'イ': '01', 'キ': '10100',\n 'シ': '11010', 'チ': '0010', 'ニ': '1010', 'ヒ': '11001', 'ミ': '00101', 'リ': '110',\n 'ヰ': '01001', 'ウ': '001', 'ク': '0001', 'ス': '11101', 'ツ': '0110', 'ヌ': '0000',\n 'フ': '1100', 'ム': '1', 'ユ': '10011', 'ル': '10110', 'ン': '01010', 'エ': '10111',\n 'ケ': '1011', 'セ': '01110', 'テ': '01011', 'ネ': '1101', 'ヘ': '0', 'メ': '10001',\n 'レ': '111', 'ヱ': '01100', 'オ': '01000', 'コ': '1111', 'ソ': '1110', 'ト': '00100',\n 'ノ': '0011', 'ホ': '100', 'モ': '10010', 'ヨ': '11', 'ロ': '0101', 'ヲ': '0111',\n '゛': '00', '゜': '00110', '。': '010100', 'ー': '01101', '、': '010101',\n '(': '101101', ')': '010010'\n },\n '11': { // Korean Alphabet => https://ko.wikipedia.org/wiki/%EB%AA%A8%EC%8A%A4_%EB%B6%80%ED%98%B8\n 'ㄱ': '0100', 'ㄴ': '0010', 'ㄷ': '1000', 'ㄹ': '0001', 'ㅁ': '11', 'ㅂ': '011',\n 'ㅅ': '110', 'ㅇ': '101', 'ㅈ': '0110', 'ㅊ': '1010', 'ㅋ': '1001', 'ㅌ': '1100',\n 'ㅍ': '111', 'ㅎ': '0111', 'ㅏ': '0', 'ㅑ': '00', 'ㅓ': '1', 'ㅕ': '000',\n 'ㅗ': '01', 'ㅛ': '10', 'ㅜ': '0000', 'ㅠ': '010', 'ㅡ': '100', 'ㅣ': '001',\n 'ㅐ': '1101', 'ㅔ': '1011'\n },\n '12': { // Thai Alphabet => https://th.wikipedia.org/wiki/รหัสมอร์ส\n 'ก': '110', 'ข': '1010', 'ค': '101', 'ง': '10110', 'จ': '10010',\n 'ฉ': '1111', 'ช': '1001', 'ซ': '1100', 'ญ': '0111', 'ด': '100',\n 'ต': '1', 'ถ': '10100', 'ท': '10011', 'น': '10', 'บ': '1000',\n 'ป': '0110', 'ผ': '1101', 'ฝ': '10101', 'พ': '01100', 'ฟ': '0010',\n 'ม': '11', 'ย': '1011', 'ร': '010', 'ล': '0100', 'ว': '011',\n 'ส': '000', 'ห': '0000', 'อ': '10001', 'ฮ': '11011', 'ฤ': '01011',\n 'ะ': '01000', 'า': '01', 'ิ': '00100', 'ี': '00', 'ึ': '00110',\n 'ื': '0011', 'ุ': '00101', 'ู': '1110', 'เ': '0', 'แ': '0101',\n 'ไ': '01001', 'โ': '111', 'ำ': '00010', '่': '001', '้': '0001',\n '๊': '11000', '๋': '01010', 'ั': '01101', '็': '11100', '์': '11001',\n 'ๆ': '10111', 'ฯ': '11010',\n // Letters sharing a code with a letter above (same sound)\n 'ฃ': '1010', 'ฅ': '101', 'ฆ': '101', 'ศ': '000', 'ษ': '000', 'ฌ': '1001',\n 'ฎ': '100', 'ฏ': '1', 'ฐ': '10100', 'ฑ': '10011', 'ฒ': '10011', 'ธ': '10011',\n 'ณ': '10', 'ภ': '01100', 'ฬ': '0100', 'ใ': '01001'\n }\n};\n\ntype Tables = {\n // Every set with '0' = the priority set, codes already in dot/dash symbols.\n mapped: Characters;\n // Morse code -> character, first key wins in set order ('0' first).\n swapped: Record<string, string>;\n};\n\n// encode()/decode() run per keystroke in typical UIs, so the derived tables are\n// cached per symbol/priority combination (bounded, oldest entry evicted first).\nconst CACHE_SIZE = 16;\nconst cache = new Map<string, Tables>();\n\nconst getTables = (options: Options): Tables => {\n const key = JSON.stringify([options.dot, options.dash, options.space, options.priority]);\n const cached = cache.get(key);\n if (cached) {\n return cached;\n }\n const mapped: Characters = {};\n const sets: Characters = { ...baseCharacters, '0': baseCharacters[options.priority] };\n for (const set in sets) {\n mapped[set] = {};\n for (const character in sets[set]) {\n // Substitute the internal 0/1 sentinels per code so dot/dash symbols that\n // themselves contain '0'/'1' are not re-scanned.\n mapped[set][character] = sets[set][character].replace(/[01]/g, (c) => (c === '0' ? options.dot : options.dash));\n }\n }\n // Null-prototype map so user-supplied tokens can never resolve to inherited\n // Object.prototype members (e.g. \"constructor\") during decoding.\n const swapped: Record<string, string> = Object.create(null);\n for (const set in mapped) {\n for (const character in mapped[set]) {\n swapped[mapped[set][character]] ??= character;\n }\n }\n // The word-gap symbol always decodes to a literal space. Validation keeps it\n // from looking like a code, so it never shadows a real character.\n swapped[options.space] = ' ';\n if (cache.size >= CACHE_SIZE) {\n cache.delete(cache.keys().next().value as string);\n }\n const tables = { mapped, swapped };\n cache.set(key, tables);\n return tables;\n};\n\n// Internal: the cached tables must be treated as read-only.\nconst getEncodeCharacters = (options: Options): Characters => getTables(options).mapped;\nconst swapCharacters = (options: Options): Record<string, string> => getTables(options).swapped;\n\n// Public copy for characters(); callers may mutate it freely.\nconst getMappedCharacters = (options: Options, usePriority: boolean): Characters => {\n const copy: Characters = {};\n const { mapped } = getTables(options);\n for (const set in mapped) {\n if (set !== '0' || usePriority) {\n copy[set] = { ...mapped[set] };\n }\n }\n return copy;\n};\n\nexport {\n baseCharacters,\n getEncodeCharacters,\n getMappedCharacters,\n swapCharacters\n};\n","import type { Options } from './types.js';\n\n// Splits Morse text into character codes and word-gap symbols. Shared by decode()\n// and the audio scheduler so both read the same input the same way: any\n// whitespace separates codes, runs of separators collapse, and a word-gap symbol\n// may touch its neighbours ('.-/-...').\nexport const tokenize = (morse: string, o: Options): string[] => {\n const tokens: string[] = [];\n for (const token of morse.trim().replace(/\\s+/g, o.separator).split(o.separator)) {\n // Validation guarantees dot/dash/invalid never contain the space symbol, so\n // splitting on it cannot tear a code apart.\n token.split(o.space).forEach((part, index) => {\n if (index > 0) tokens.push(o.space);\n if (part !== '') tokens.push(part);\n });\n }\n return tokens;\n};\n","import type { MorseOptions, Options } from './types.js';\nimport { baseCharacters } from './characters.js';\n\n// Highest frequency a 44.1 kHz render can represent (Nyquist); above it the\n// oscillator renders pure silence.\nconst MAX_FREQUENCY = 22050;\nconst SYMBOL_DEFAULTS = { dash: '-', dot: '.', space: '/', separator: ' ', invalid: '#' } as const;\n\nconst isPositiveNumber = (value: unknown): value is number =>\n typeof value === 'number' && Number.isFinite(value) && value > 0;\n\n// True if the symbol is an encodable character in any character set (so it\n// cannot safely double as a delimiter — input occurrences would be ambiguous).\nconst isCharacterKey = (symbol: string): boolean =>\n Object.values(baseCharacters).some((set) => Object.prototype.hasOwnProperty.call(set, symbol));\n\n// A symbol is \"code-like\" if it can be tokenized entirely into dot/dash, which\n// would make it indistinguishable from a real character code.\nconst isCodeLike = (symbol: string, dot: string, dash: string): boolean => {\n if (symbol === '') return false;\n let i = 0;\n while (i < symbol.length) {\n if (symbol.startsWith(dot, i)) i += dot.length;\n else if (symbol.startsWith(dash, i)) i += dash.length;\n else return false;\n }\n return true;\n};\n\nexport function assertString(value: unknown, name: string): asserts value is string {\n if (typeof value !== 'string') {\n throw new TypeError(`morse-code-translator: ${name} must be a string.`);\n }\n}\n\n// Symbols must be strings; a missing value falls back to the default, and so\n// does '' for every symbol except invalid ('' there means \"drop unknown\").\nconst getSymbol = (opts: MorseOptions, name: keyof typeof SYMBOL_DEFAULTS): string => {\n const value: unknown = opts[name];\n if (value === undefined || value === null) {\n return SYMBOL_DEFAULTS[name];\n }\n assertString(value, `\"${name}\"`);\n return value === '' && name !== 'invalid' ? SYMBOL_DEFAULTS[name] : value;\n};\n\n// priority must be an integer in [1, 12] given as a number or a plain decimal\n// string (e.g. an HTML <select> value); anything else selects Latin.\nconst getPriority = (value: unknown): number => {\n const priority = typeof value === 'string' && /^\\d+$/.test(value) ? Number(value) : value;\n return Number.isInteger(priority) && (priority as number) >= 1 && (priority as number) <= 12 ? (priority as number) : 1;\n};\n\nconst validateSymbols = (o: Options): void => {\n if (o.dot === o.dash) {\n throw new Error('morse-code-translator: \"dot\" and \"dash\" symbols must be different.');\n }\n // A prefix pair makes codes ambiguous (dot '.' + dash '..': T and I both\n // become '..'), so one symbol must never start with the other.\n if (o.dot.startsWith(o.dash) || o.dash.startsWith(o.dot)) {\n throw new Error('morse-code-translator: \"dot\" and \"dash\" must not be a prefix of each other.');\n }\n if (o.separator === o.space) {\n throw new Error('morse-code-translator: \"separator\" and \"space\" symbols must be different.');\n }\n for (const [name, value] of [['separator', o.separator], ['space', o.space]] as const) {\n // encode() spreads text per code point, so a multi-character separator/space\n // cannot be matched as a single delimiter — require exactly one code point.\n if ([...value].length !== 1) {\n throw new Error(`morse-code-translator: \"${name}\" must be a single character.`);\n }\n if (value === o.dot || value === o.dash) {\n throw new Error(`morse-code-translator: \"${name}\" must differ from the \"dot\" and \"dash\" symbols.`);\n }\n if (isCodeLike(value, o.dot, o.dash)) {\n throw new Error(`morse-code-translator: \"${name}\" must not be composed solely of \"dot\"/\"dash\" symbols.`);\n }\n // The word-gap (space) symbol cannot be whitespace: decode collapses all\n // whitespace runs into the separator, which would obliterate it. (The\n // separator itself may be a single whitespace character — it is the\n // normalization target.)\n if (name === 'space' && /\\s/.test(value)) {\n throw new Error('morse-code-translator: \"space\" must not be a whitespace character.');\n }\n }\n // The tokenizer splits on whitespace and the space/separator symbols, so a\n // dot/dash that contains any of them would be torn apart.\n for (const [name, value] of [['dot', o.dot], ['dash', o.dash]] as const) {\n if (value.includes(o.space) || value.includes(o.separator) || /\\s/.test(value)) {\n throw new Error(`morse-code-translator: \"${name}\" must not contain whitespace or the \"space\"/\"separator\" symbol.`);\n }\n }\n // The separator stands in for whitespace in the input, so it must not also be\n // an encodable character (that would make input occurrences ambiguous).\n if (isCharacterKey(o.separator)) {\n throw new Error('morse-code-translator: \"separator\" must not be an encodable character.');\n }\n if (o.invalid !== '') {\n // A non-empty invalid marker must not look like a code, or it would be\n // re-tokenized into audible tones by the audio renderer.\n if (isCodeLike(o.invalid, o.dot, o.dash)) {\n throw new Error('morse-code-translator: \"invalid\" must not be composed solely of \"dot\"/\"dash\" symbols.');\n }\n // ...nor contain a delimiter (whitespace, space, separator), or decode\n // would read it as a word gap or split it.\n if (o.invalid.includes(o.space) || o.invalid.includes(o.separator) || /\\s/.test(o.invalid)) {\n throw new Error('morse-code-translator: \"invalid\" must not contain whitespace or the \"space\"/\"separator\" symbol.');\n }\n }\n};\n\nconst getOptions = (input?: MorseOptions | null): Options => {\n const opts: MorseOptions = input ?? {};\n // unit/fwUnit/wpm/frequency must be positive finite; zero, negative, NaN and\n // Infinity are degenerate (they produce empty/negative/infinite buffers or\n // throw in real browsers).\n const unit = isPositiveNumber(opts.unit) ? opts.unit : 0.08;\n const fwUnit = isPositiveNumber(opts.fwUnit) ? opts.fwUnit : unit;\n const wpm = isPositiveNumber(opts.wpm) ? opts.wpm : undefined;\n const requestedFrequency = opts.oscillator?.frequency;\n const frequency = isPositiveNumber(requestedFrequency) && requestedFrequency <= MAX_FREQUENCY ? requestedFrequency : 500;\n // volume is 0-100 (clamped); 0 is a legitimate value (mute), only\n // non-finite/missing fall back.\n const volume = typeof opts.volume === 'number' && Number.isFinite(opts.volume) ? Math.min(100, Math.max(0, opts.volume)) : 100;\n const priority = getPriority(opts.priority);\n // oscillator.type must be a valid OscillatorType, or it throws in real browsers.\n const requestedType: unknown = opts.oscillator?.type;\n const oscillatorType: Options['oscillator']['type'] =\n requestedType === 'sine' || requestedType === 'square' || requestedType === 'sawtooth' || requestedType === 'triangle'\n ? requestedType\n : 'sine';\n\n const options: Options = {\n ...opts,\n dash: getSymbol(opts, 'dash'),\n dot: getSymbol(opts, 'dot'),\n space: getSymbol(opts, 'space'),\n separator: getSymbol(opts, 'separator'),\n invalid: getSymbol(opts, 'invalid'), // '' is legitimate: drop unknown characters\n priority,\n wpm, // words per minute - PARIS method used in favour of unit/fwUnit options\n unit, // period of one unit, in seconds, 1.2 / c where c is speed of transmission, in words per minute\n fwUnit, // Farnsworth unit to control intercharacter and interword gaps\n volume,\n oscillator: {\n type: oscillatorType, // sine, square, sawtooth, triangle\n frequency // value in hertz\n },\n events: opts.events ? { ...opts.events } : opts.events\n };\n\n validateSymbols(options);\n return options;\n};\n\nexport default getOptions;\n","import type { Options, AudioResult, AudioState, AudioEvents } from './types.js';\nimport { tokenize } from './tokenize.js';\n\n// Audio constants\nconst SAMPLE_RATE = 44100;\nconst CHANNELS = 1;\nconst BITS_PER_SAMPLE = 16;\nconst WAV_HEADER_BYTES = 44;\n// RIFF stores sizes as uint32 (about 13.5 hours of 16-bit mono at 44.1 kHz).\nconst MAX_WAV_DATA_BYTES = 0xffffffff - (WAV_HEADER_BYTES - 8);\n\n// Morse timing constants (in units)\nconst DOT_DURATION = 1;\nconst DASH_DURATION = 3;\nconst INTRA_CHARACTER_GAP = 1;\nconst INTER_CHARACTER_GAP = 3;\nconst WORD_GAP = 7;\n\n// WPM calculation constant (PARIS method)\nconst WPM_UNIT_DIVISOR = 50;\n\n// Longest attack/release ramp at tone edges. The ramps sit inside each tone, so\n// timing is unchanged; they remove the click of a hard gain step.\nconst RAMP_SECONDS = 0.005;\n\n// Audio is rendered in chunks of about this length, each in its own\n// OfflineAudioContext, so long texts never need one huge buffer.\nexport const CHUNK_SECONDS = 30;\n// Rendered chunks kept for playback (the current one and its neighbours).\nconst CACHED_CHUNKS = 3;\n// Fade applied by the live player when playback starts or stops mid-tone\n// (play/pause/seek/stop), so cutting into a tone does not click.\nconst LIVE_FADE_SECONDS = 0.005;\n// Playback renders in flight at most (the playing chunk and the next one).\nconst MAX_PLAYBACK_RENDERS = 2;\n// play() also waits for the next chunk when the position is this close to it.\nconst PREFETCH_SECONDS = 2;\n// Rejection of a queued render that was superseded before it started.\nconst CANCELLED = new Error('morse-code-translator: render cancelled.');\n\ntype ToneSchedule = {\n // Flat [start, duration, start, duration, ...] in seconds, sorted by start.\n tones: Float64Array;\n totalTime: number;\n};\n\nconst getUnits = (opts: Options): [number, number] => {\n if (opts.wpm) {\n // WPM mode uses standardized units (PARIS method)\n const unit = 60 / (opts.wpm * WPM_UNIT_DIVISOR);\n return [unit, unit];\n }\n return [opts.unit, opts.fwUnit];\n};\n\nexport const getToneSchedule = (morse: string, opts: Options): ToneSchedule => {\n const [unit, fwUnit] = getUnits(opts);\n // Try the longer symbol first. (Validation already rejects a dot/dash that is\n // a prefix of the other, so the order only matters for speed.)\n const symbolOrder: Array<[string, number]> =\n opts.dot.length >= opts.dash.length\n ? [[opts.dot, DOT_DURATION], [opts.dash, DASH_DURATION]]\n : [[opts.dash, DASH_DURATION], [opts.dot, DOT_DURATION]];\n\n const tones: number[] = [];\n let time = 0;\n let wordGapPending = false;\n for (const token of tokenize(morse, opts)) {\n if (token === opts.space) {\n wordGapPending = tones.length > 0;\n continue;\n }\n // An unknown character adds no tones and no gaps, even if its marker\n // happens to contain a dot/dash symbol.\n if (token === opts.invalid) {\n continue;\n }\n const durations: number[] = [];\n for (let position = 0; position < token.length; ) {\n const matched = symbolOrder.find(([symbol]) => token.startsWith(symbol, position));\n if (matched) {\n durations.push(matched[1]);\n position += matched[0].length;\n } else {\n // Skip any unexpected symbol (e.g. the invalid-character marker).\n position += 1;\n }\n }\n // A token without tones (e.g. the invalid marker) adds no gaps either.\n if (durations.length === 0) {\n continue;\n }\n if (tones.length > 0) {\n time += (wordGapPending ? WORD_GAP : INTER_CHARACTER_GAP) * fwUnit;\n }\n wordGapPending = false;\n durations.forEach((duration, index) => {\n if (index > 0) {\n time += INTRA_CHARACTER_GAP * unit;\n }\n tones.push(time, duration * unit);\n time += duration * unit;\n });\n }\n\n if (!Number.isFinite(time)) {\n throw new RangeError('morse-code-translator: audio duration is not finite; use a smaller unit/fwUnit.');\n }\n return { tones: Float64Array.from(tones), totalTime: time };\n};\n\n/**\n * Delay in seconds from `offset` to the oscillator's next zero-phase point, so\n * every chunk's oscillator is in phase with absolute time. Half a frame of\n * tolerance (plus float slack) lets a boundary placed on a zero-phase point\n * start at once instead of one period late.\n */\nexport const phaseDelay = (offset: number, frequency: number, sampleRate: number): number => {\n const tolerance = (0.5 * frequency) / sampleRate + 1e-6;\n return Math.max(0, Math.ceil(offset * frequency - tolerance) / frequency - offset);\n};\n\ntype ChunkPlan = {\n // Start frame of the chunk that contains `frame`.\n startFor: (frame: number) => number;\n // Start frame of the chunk after the one starting at `start` (>= totalFrames: none).\n next: (start: number) => number;\n};\n\n/**\n * Splits [0, totalFrames) into chunks of one to two target lengths. Boundary k\n * is computed from k alone (no walk from the start), so seeking anywhere is\n * cheap and the plan works for any duration. A boundary goes in silence when a\n * gap is near (at least one oscillator period before the next tone, so the\n * phase-aligned oscillator start below never clips a tone); otherwise (tones\n * longer than a chunk) it goes on a zero-phase point of the oscillator.\n */\nexport const createChunkPlan = (\n tones: Float64Array,\n totalFrames: number,\n sampleRate: number,\n frequency: number,\n targetFrames: number = CHUNK_SECONDS * sampleRate\n): ChunkPlan => {\n const count = tones.length / 2;\n const startFrame = (i: number) => Math.floor(tones[i * 2] * sampleRate);\n const endFrame = (i: number) => Math.ceil((tones[i * 2] + tones[i * 2 + 1]) * sampleRate);\n const guard = Math.ceil(sampleRate / frequency) + 1;\n\n // First tone whose end frame is after `frame` (count if none).\n const firstToneEndingAfter = (frame: number): number => {\n let low = 0;\n let high = count;\n while (low < high) {\n const mid = (low + high) >> 1;\n if (endFrame(mid) <= frame) low = mid + 1;\n else high = mid;\n }\n return low;\n };\n\n const boundaryAt = (k: number): number => {\n const target = k * targetFrames;\n if (k === 0 || target >= totalFrames) {\n return Math.min(target, totalFrames);\n }\n const limit = target + targetFrames;\n for (let tone = firstToneEndingAfter(target); tone <= count; tone++) {\n // The gap before `tone` (the tail after the last tone has no next tone).\n const candidate = tone === 0 ? target : Math.max(target, endFrame(tone - 1));\n if (candidate >= limit || candidate >= totalFrames) {\n break;\n }\n if (tone === count || startFrame(tone) - candidate >= guard) {\n return candidate;\n }\n }\n // No usable gap: if the rest of the audio fits, the chunk runs to the end\n // (so the final tone is never split); else split on a zero-phase point.\n if (totalFrames <= limit) {\n return totalFrames;\n }\n return Math.min(Math.round((Math.ceil((target / sampleRate) * frequency) / frequency) * sampleRate), totalFrames);\n };\n\n return {\n startFor: (frame) => {\n const k = Math.floor(frame / targetFrames);\n const start = boundaryAt(k);\n return start <= frame ? start : boundaryAt(k - 1);\n },\n next: (start) => boundaryAt(Math.floor(start / targetFrames) + 1),\n };\n};\n\n// Chunk start frames in order (for tests and diagnostics).\nexport const getChunkStarts = (\n tones: Float64Array,\n totalFrames: number,\n sampleRate: number,\n targetFrames: number = CHUNK_SECONDS * sampleRate,\n frequency = 500\n): number[] => {\n const plan = createChunkPlan(tones, totalFrames, sampleRate, frequency, targetFrames);\n const starts: number[] = [];\n for (let start = 0; start < Math.max(1, totalFrames); start = plan.next(start)) {\n starts.push(start);\n }\n return starts;\n};\n\n\n/**\n * Renders frames [startFrame, endFrame) of the schedule in its own\n * OfflineAudioContext. The oscillator starts in phase with absolute time and the\n * gain envelope starts at its value at startFrame, so consecutive renders join\n * into exactly the audio of one long render.\n */\nexport const renderFrames = (\n OfflineAudioContextClass: typeof OfflineAudioContext,\n tones: Float64Array,\n opts: Options,\n startFrame: number,\n endFrame: number\n): Promise<AudioBuffer> => {\n // OfflineAudioContext requires a length of at least one sample frame, so an\n // empty/silent morse string still yields a valid tiny buffer.\n const length = Math.max(1, endFrame - startFrame);\n const offlineContext = new OfflineAudioContextClass(CHANNELS, length, SAMPLE_RATE);\n const oscillator = offlineContext.createOscillator();\n const gainNode = offlineContext.createGain();\n const frequency = opts.oscillator.frequency ?? 500;\n const volume = opts.volume / 100.0;\n oscillator.type = opts.oscillator.type ?? 'sine';\n oscillator.frequency.value = frequency;\n\n const offset = startFrame / SAMPLE_RATE;\n const end = offset + length / SAMPLE_RATE;\n\n // Each tone: 0 at start, linear attack to volume, hold, linear release to 0 at\n // its end. The ramps sit inside the tone, so timing is unchanged.\n const envelope = (i: number): Array<[number, number, boolean]> => {\n const start = tones[i * 2];\n const duration = tones[i * 2 + 1];\n const ramp = Math.min(RAMP_SECONDS, duration / 4);\n return [\n [start, 0, false],\n [start + ramp, volume, true],\n [start + duration - ramp, volume, false],\n [start + duration, 0, true],\n ];\n };\n\n // First tone that ends after the chunk start.\n let first = 0;\n for (let low = 0, high = tones.length / 2; low < high; ) {\n const mid = (low + high) >> 1;\n if (tones[mid * 2] + tones[mid * 2 + 1] <= offset) low = mid + 1;\n else high = mid;\n first = low;\n }\n\n const gain = gainNode.gain;\n let initial = 0;\n if (first * 2 < tones.length && tones[first * 2] < offset) {\n // A tone runs across the chunk start: begin at its envelope value there.\n const points = envelope(first);\n for (let p = 1; p < points.length; p++) {\n const [time, value, ramped] = points[p];\n if (time > offset) {\n const [previousTime, previousValue] = points[p - 1];\n initial = ramped ? previousValue + ((value - previousValue) * (offset - previousTime)) / (time - previousTime) : previousValue;\n break;\n }\n }\n }\n gain.setValueAtTime(initial, 0);\n for (let i = first; i * 2 < tones.length && tones[i * 2] < end; i++) {\n for (const [time, value, ramped] of envelope(i)) {\n if (time > offset) {\n if (ramped) gain.linearRampToValueAtTime(value, time - offset);\n else gain.setValueAtTime(value, time - offset);\n }\n }\n }\n\n oscillator.connect(gainNode);\n gainNode.connect(offlineContext.destination);\n oscillator.start(phaseDelay(offset, frequency, SAMPLE_RATE));\n\n return offlineContext.startRendering();\n};\n\nconst writeString = (view: DataView, offset: number, text: string) => {\n for (let i = 0; i < text.length; i++) {\n view.setUint8(offset + i, text.charCodeAt(i));\n }\n};\n\n/**\n * WAV (RIFF, 16-bit PCM, mono) header for dataSize bytes of samples.\n * Based on: https://github.com/mattdiamond/Recorderjs/blob/master/src/recorder.js#L155\n */\nconst encodeWAVHeader = (sampleRate: number, dataSize: number): ArrayBuffer => {\n const bytesPerSample = BITS_PER_SAMPLE / 8;\n const blockAlign = CHANNELS * bytesPerSample;\n const view = new DataView(new ArrayBuffer(WAV_HEADER_BYTES));\n\n // RIFF chunk descriptor\n writeString(view, 0, 'RIFF');\n view.setUint32(4, WAV_HEADER_BYTES - 8 + dataSize, true); // File size - 8\n writeString(view, 8, 'WAVE');\n\n // fmt sub-chunk\n writeString(view, 12, 'fmt ');\n view.setUint32(16, 16, true); // Subchunk1Size (16 for PCM)\n view.setUint16(20, 1, true); // AudioFormat (1 = PCM)\n view.setUint16(22, CHANNELS, true);\n view.setUint32(24, sampleRate, true);\n view.setUint32(28, sampleRate * blockAlign, true); // byte rate\n view.setUint16(32, blockAlign, true);\n view.setUint16(34, BITS_PER_SAMPLE, true);\n\n // data sub-chunk\n writeString(view, 36, 'data');\n view.setUint32(40, dataSize, true);\n return view.buffer;\n};\n\nconst floatTo16BitPCM = (input: Float32Array): ArrayBuffer => {\n const view = new DataView(new ArrayBuffer(input.length * 2));\n for (let i = 0; i < input.length; i++) {\n const sample = Math.max(-1, Math.min(1, input[i]));\n view.setInt16(i * 2, sample < 0 ? sample * 0x8000 : sample * 0x7fff, true);\n }\n return view.buffer;\n};\n\n// A throwing user callback must not break the instance; report it instead.\nconst safeCall = <A extends unknown[]>(callback: ((...args: A) => void) | undefined, ...args: A): void => {\n try {\n callback?.(...args);\n } catch (err) {\n console.error(err);\n }\n};\n\nconst audio = (morse: string, options: Options): AudioResult => {\n const scope: Partial<typeof globalThis> = typeof window !== 'undefined' && window ? window : globalThis;\n const AudioContextClass = scope.AudioContext;\n const OfflineAudioContextClass = scope.OfflineAudioContext;\n\n if (!AudioContextClass || !OfflineAudioContextClass) {\n throw new Error('Web Audio API is not supported in this browser. Please use a modern browser with Web Audio API support.');\n }\n\n const { tones, totalTime } = getToneSchedule(morse, options);\n // An empty/silent morse string still renders one (silent) frame.\n const totalFrames = Math.max(1, Math.ceil(SAMPLE_RATE * totalTime));\n const plan = createChunkPlan(tones, totalFrames, SAMPLE_RATE, options.oscillator.frequency ?? 500);\n const renderChunk = (start: number): Promise<AudioBuffer> =>\n renderFrames(OfflineAudioContextClass, tones, options, start, Math.min(plan.next(start), totalFrames));\n\n // The live playback AudioContext is created lazily: callers who only render or\n // export WAV data never allocate one (browsers cap the number of live contexts).\n let context: AudioContext | null = null;\n // State management (declared before getContext so it can read `state`)\n const sources = new Set<AudioBufferSourceNode>();\n // Live gain node of the current playback run (fades in on start, out on stop),\n // the context time its fade-in started, and when the last stop fade ends.\n let fader: GainNode | null = null;\n let faderStartedAt = 0;\n let fadeEndsAt = 0;\n // First frame not yet scheduled in the current run, and whether the render of\n // that chunk is in flight (a run keeps at most one chunk scheduled ahead).\n let scheduledEnd = 0;\n let renderingAhead = false;\n let state: AudioState = 'ready';\n let pausedAt = 0;\n let startTime = 0;\n // True while a play() (or the resume of a seek) is in its async startup.\n // Lets pause()/stop()/seek() know a playback intent is in flight.\n let pendingPlay = false;\n // While seek() resumes playback the internal state is 'paused' (a resume is\n // pending); getState() keeps reporting the state the events last announced.\n let shownState: AudioState | null = null;\n // Incremented by play()/pause()/stop()/seek()/dispose(); lets in-flight work\n // (a play() awaiting a render, the next chunk's scheduling, a source's ended\n // event) detect it was superseded and bail.\n let epoch = 0;\n\n const getContext = (): AudioContext => {\n // Never create (or resurrect) a live context once disposed.\n if (!context && state !== 'disposed') {\n context = new AudioContextClass();\n }\n return context as AudioContext;\n };\n\n const events: AudioEvents = options.events || {};\n\n // Rendered chunks by start frame, oldest first.\n const chunks = new Map<number, Promise<AudioBuffer>>();\n // Renders requested for playback run at most MAX_PLAYBACK_RENDERS at a time.\n // A queued render that no requester wants any more (a later seek/stop\n // superseded them all) never starts, so scrubbing cannot pile up renders.\n type RenderJob = {\n start: number;\n wanted: Array<() => boolean>;\n promise: Promise<AudioBuffer>;\n resolve: (buffer: AudioBuffer) => void;\n reject: (error: unknown) => void;\n };\n const queued: RenderJob[] = [];\n const jobs = new Map<number, RenderJob>();\n let rendering = 0;\n // A render that throws synchronously (e.g. in the OfflineAudioContext\n // constructor) becomes a rejection, so it cannot leak a render slot.\n const safeRender = (start: number): Promise<AudioBuffer> => {\n try {\n return renderChunk(start);\n } catch (err) {\n return Promise.reject(err);\n }\n };\n // Forget a job (and its cached promise) only if they are still this job's;\n // a newer request for the same chunk may have replaced them.\n const forget = (job: RenderJob) => {\n if (jobs.get(job.start) === job) jobs.delete(job.start);\n if (chunks.get(job.start) === job.promise) chunks.delete(job.start);\n };\n const pump = () => {\n while (rendering < MAX_PLAYBACK_RENDERS && queued.length > 0) {\n const job = queued.shift() as RenderJob;\n if (!job.wanted.some((wanted) => wanted())) {\n // Removed from the cache at once, so no later request receives it.\n forget(job);\n job.reject(CANCELLED);\n continue;\n }\n rendering++;\n safeRender(job.start)\n .then(job.resolve, job.reject)\n .finally(() => {\n if (jobs.get(job.start) === job) jobs.delete(job.start);\n rendering--;\n pump();\n });\n }\n };\n\n // Queues a render in the pool (playback and WAV export share its slots).\n const enqueue = (start: number, wanted: () => boolean): RenderJob => {\n const job = { start, wanted: [wanted] } as RenderJob;\n job.promise = new Promise<AudioBuffer>((resolve, reject) => {\n job.resolve = resolve;\n job.reject = reject;\n });\n queued.push(job);\n return job;\n };\n\n // A cached playback render of the chunk at `start`, rendered if needed.\n const getChunk = (start: number, wanted: () => boolean = () => true): Promise<AudioBuffer> => {\n let buffer = chunks.get(start);\n if (buffer) {\n jobs.get(start)?.wanted.push(wanted);\n chunks.delete(start); // re-insert as most recent\n } else {\n const job = enqueue(start, wanted);\n jobs.set(start, job);\n buffer = job.promise;\n const pending = buffer;\n // A failed or cancelled render must not poison the cache.\n pending.catch(() => {\n if (chunks.get(start) === pending) chunks.delete(start);\n });\n }\n chunks.set(start, buffer);\n while (chunks.size > CACHED_CHUNKS) {\n chunks.delete(chunks.keys().next().value as number);\n }\n pump();\n return buffer;\n };\n\n // Resolves once the first chunk is rendered. A failed render is forgotten so\n // the next play()/getWaveBlob() renders again instead of failing forever.\n let ready: Promise<void> | null = null;\n const whenReady = (): Promise<void> => {\n ready ??= getChunk(0).then(\n () => {\n // Do not signal readiness if disposed meanwhile, and do NOT reset state to\n // 'ready' (the caller may have already stopped/started during rendering).\n if (state !== 'disposed') {\n safeCall(events.onready);\n }\n },\n (err) => {\n ready = null;\n throw err;\n }\n );\n return ready;\n };\n // Render eagerly; a failure surfaces from the next play()/getWaveBlob().\n whenReady().catch(() => {});\n\n // Fades the current run out and stops its sources once silent. Returns\n // whether there was a run to fade.\n const stopSources = (): boolean => {\n const ctx = context as AudioContext | null;\n const fading = ctx !== null && fader !== null;\n const stopAt = fading ? (ctx as AudioContext).currentTime + LIVE_FADE_SECONDS : 0;\n if (fading) {\n const { gain } = fader as GainNode;\n const now = (ctx as AudioContext).currentTime;\n // The fader's level now, from its fade-in (gain.value can still read the\n // default 1 before the first rendered quantum).\n const level = Math.min(1, Math.max(0, (now - faderStartedAt) / LIVE_FADE_SECONDS));\n gain.cancelScheduledValues(now);\n gain.setValueAtTime(level, now);\n gain.linearRampToValueAtTime(0, stopAt);\n fadeEndsAt = stopAt;\n }\n for (const source of sources) {\n try {\n source.stop(stopAt);\n } catch (e) {\n // Ignore if already stopped\n }\n }\n sources.clear();\n fader = null;\n renderingAhead = false;\n return fading;\n };\n\n const finish = () => {\n sources.clear();\n fader = null;\n state = 'stopped';\n pausedAt = 0;\n startTime = 0;\n safeCall(events.onended);\n };\n\n // Starts the chunk at `start` at its place on the playback timeline (startTime\n // is the context time of position 0).\n const scheduleChunk = (start: number, buffer: AudioBuffer, myEpoch: number) => {\n const ctx = context as AudioContext;\n const when = startTime + start / SAMPLE_RATE;\n const now = ctx.currentTime;\n const source = ctx.createBufferSource();\n source.buffer = buffer;\n if (now > when + 1 / SAMPLE_RATE) {\n // Late (slow render): it starts mid-chunk, so fade it in like a resume.\n const fadeIn = ctx.createGain();\n fadeIn.gain.setValueAtTime(0, now);\n fadeIn.gain.linearRampToValueAtTime(1, now + LIVE_FADE_SECONDS);\n fadeIn.connect(fader as GainNode);\n source.connect(fadeIn);\n } else {\n source.connect(fader as GainNode);\n }\n source.onended = () => {\n sources.delete(source);\n if (epoch !== myEpoch || state !== 'playing') {\n return;\n }\n if (sources.size === 0 && scheduledEnd >= totalFrames) {\n // Natural end follows the audio clock: the last chunk finished playing.\n finish();\n } else {\n scheduleAhead(myEpoch);\n }\n };\n // Starting mid-chunk (play/seek) or late (slow render): skip what has passed.\n source.start(Math.max(when, now), Math.max(0, now - when));\n sources.add(source);\n scheduledEnd = plan.next(start);\n };\n\n // Keeps one chunk scheduled after the playing one. A failed render is tried\n // again (at once if nothing is playing, else when the playing chunk ends);\n // when it fails again with nothing left to play, playback stops.\n let failedStart = -1;\n const scheduleAhead = (myEpoch: number) => {\n if (renderingAhead || sources.size >= 2 || scheduledEnd >= totalFrames) {\n return;\n }\n const start = scheduledEnd;\n const current = () => epoch === myEpoch && state === 'playing';\n renderingAhead = true;\n getChunk(start, current).then(\n (buffer) => {\n if (current()) {\n renderingAhead = false;\n scheduleChunk(start, buffer, myEpoch);\n scheduleAhead(myEpoch);\n }\n },\n (err) => {\n if (!current()) {\n return;\n }\n renderingAhead = false;\n if (err === CANCELLED) {\n scheduleAhead(myEpoch);\n return;\n }\n console.error(err);\n if (failedStart !== start) {\n failedStart = start;\n if (sources.size === 0) scheduleAhead(myEpoch);\n } else if (sources.size === 0) {\n stop();\n }\n }\n );\n };\n\n const play = async () => {\n // Already playing or disposed -> nothing to do.\n if (state === 'playing' || state === 'disposed') {\n return;\n }\n // Claim a fresh epoch. Any EARLIER in-flight play() now sees a changed epoch\n // and bails (so concurrent play() calls start exactly once).\n // Create/resume the live context now, inside the caller's user gesture\n // (iOS Safari keeps a context suspended when it is resumed later). If the\n // constructor throws (browsers cap live contexts), nothing has changed yet.\n const ctx = getContext();\n const needsResume = () => (ctx.state as string) === 'suspended' || (ctx.state as string) === 'interrupted';\n const resuming = needsResume() ? ctx.resume() : null;\n // Awaited only if this play() gets that far; never left unhandled.\n resuming?.catch(() => {});\n const myEpoch = ++epoch;\n pendingPlay = true;\n const current = (): boolean => epoch === myEpoch && state !== 'disposed';\n // One retry for a failed render; a superseded play() bails quietly.\n const load = (start: number) => getChunk(start, current).catch(() => (current() ? getChunk(start, current) : Promise.reject(CANCELLED)));\n try {\n const position = pausedAt;\n const chunk = plan.startFor(Math.floor(position * SAMPLE_RATE));\n const next = plan.next(chunk);\n const playing = load(chunk);\n // Close to the end of its chunk, wait for the next one as well, so the\n // playing chunk cannot run out before the next is rendered. If the next\n // one fails, play the current chunk and let scheduleAhead() try again.\n const following =\n next < totalFrames && next / SAMPLE_RATE - position < PREFETCH_SECONDS ? getChunk(next, current).catch(() => null) : null;\n // Combined (and given a handler) at once: the renders may reject while\n // whenReady() is still awaited, which would count as unhandled.\n const renders = Promise.all([playing, following]);\n renders.catch(() => {});\n let rendered: [AudioBuffer, AudioBuffer | null];\n try {\n rendered = await renders;\n // Bail if superseded during the render await (before whenReady(), so a\n // disposed instance never starts another render).\n if (!current()) return;\n // onready (first chunk) fires before onstarted, also when the eager\n // render failed and was retried; a failure here is the playing chunk's\n // render to report, not this one.\n await whenReady().catch(() => {});\n if (!current()) return;\n if (resuming) {\n await resuming;\n }\n if (needsResume()) {\n await ctx.resume();\n }\n } catch (err) {\n if (!current()) return;\n // A failed render or resume. After a seek's resume, playback that was\n // announced as playing stops (onstopped); otherwise the announced state stays.\n if (shownState === 'playing') {\n stop();\n } else if (shownState !== null) {\n state = shownState;\n shownState = null;\n }\n throw err;\n }\n\n // Re-check after the resume await.\n if (!current()) {\n return;\n }\n\n startTime = ctx.currentTime - position;\n state = 'playing';\n pendingPlay = false;\n shownState = null;\n failedStart = -1;\n // Fade in, in case playback resumes in the middle of a tone.\n faderStartedAt = ctx.currentTime;\n fader = ctx.createGain();\n fader.gain.setValueAtTime(0, ctx.currentTime);\n fader.gain.linearRampToValueAtTime(1, ctx.currentTime + LIVE_FADE_SECONDS);\n fader.connect(ctx.destination);\n renderingAhead = false;\n scheduleChunk(chunk, rendered[0], myEpoch);\n if (rendered[1]) {\n scheduleChunk(next, rendered[1], myEpoch);\n }\n scheduleAhead(myEpoch);\n safeCall(events.onstarted);\n } finally {\n // Only the current epoch's play() owns the pendingPlay flag; a superseding\n // call manages its own lifecycle.\n if (epoch === myEpoch) {\n pendingPlay = false;\n }\n }\n };\n\n const pause = () => {\n if (state === 'disposed') {\n return;\n }\n\n if (state === 'playing') {\n epoch++;\n pendingPlay = false;\n shownState = null;\n pausedAt = Math.min(getContext().currentTime - startTime, totalTime);\n stopSources();\n state = 'paused';\n safeCall(events.onpaused);\n return;\n }\n\n // An in-flight play() that has not started yet: supersede it (so it bails\n // on resume) and settle into 'paused' rather than dropping the intent.\n if (pendingPlay) {\n epoch++;\n pendingPlay = false;\n shownState = null;\n stopSources();\n state = 'paused';\n safeCall(events.onpaused);\n }\n };\n\n const stop = (dispose = false) => {\n if (state === 'disposed') {\n return;\n }\n\n epoch++;\n stopSources();\n\n // Active = playing, paused, or a play()/seek-resume in flight; in each case\n // the listener believes there is playback to stop.\n const wasActive = state === 'playing' || state === 'paused' || pendingPlay;\n pendingPlay = false;\n shownState = null;\n state = 'stopped';\n pausedAt = 0;\n startTime = 0;\n\n if (wasActive) {\n safeCall(events.onstopped);\n }\n\n if (dispose) {\n // Release rendered audio; it re-renders on the next play/export.\n chunks.clear();\n }\n };\n\n const seek = async (time: number) => {\n if (state === 'disposed') {\n return;\n }\n\n // Resume afterwards if playback is active or a play() is in flight (so a\n // play() immediately followed by seek() is not silently swallowed).\n const wasActive = state === 'playing' || pendingPlay;\n // Plain-JS callers may pass anything; NaN-like values seek to 0, and\n // ±Infinity clamps to the [0, totalTime] range.\n const requested = Number(time);\n const clampedTime = Number.isNaN(requested) ? 0 : Math.max(0, Math.min(requested, totalTime));\n\n const seekEpoch = ++epoch;\n stopSources();\n pausedAt = clampedTime;\n if (wasActive) {\n // Internally a resume is pending (so a pause()/stop() from the callback\n // below settles it like any pending play); getState() keeps showing the\n // announced state ('playing', or the state before a pending play()).\n shownState ??= getState();\n state = 'paused';\n pendingPlay = true;\n }\n safeCall(events.onseeked, clampedTime);\n\n // A callback that paused, stopped or seeked again wins over this resume.\n if (!wasActive || epoch !== seekEpoch) {\n return;\n }\n // A failure is settled by play() itself (stop, or the announced state).\n await play();\n };\n\n const dispose = () => {\n if (state === 'disposed') {\n return;\n }\n stop(true);\n state = 'disposed';\n const ctx = context as AudioContext | null;\n if (ctx && ctx.state !== 'closed') {\n // Let a stop fade (from this stop() or an earlier stop()/pause()) play out\n // first; a closed context outputs nothing. close() rejects if the caller\n // closed the context already.\n const close = () => ctx.close().catch(() => {});\n const fadeLeft = fadeEndsAt - ctx.currentTime;\n if (fadeLeft > 0) {\n setTimeout(close, fadeLeft * 1000 + 45);\n } else {\n close();\n }\n }\n };\n\n const getCurrentTime = (): number => {\n if (state === 'playing') {\n return Math.min(getContext().currentTime - startTime, totalTime);\n }\n return pausedAt;\n };\n\n const getTotalTime = (): number => {\n return totalTime;\n };\n\n const getState = (): AudioState => {\n return shownState ?? state;\n };\n\n // Concurrent calls (e.g. a double click on Download) share one export.\n let exporting: Promise<Blob> | null = null;\n const getWaveBlob = (): Promise<Blob> => {\n if (state === 'disposed') {\n return Promise.reject(new Error('Audio buffer not available'));\n }\n exporting ??= exportWav().finally(() => {\n exporting = null;\n });\n return exporting;\n };\n\n const exportWav = async (): Promise<Blob> => {\n await whenReady();\n if (state === 'disposed') {\n throw new Error('Audio buffer not available');\n }\n const dataSize = totalFrames * (BITS_PER_SAMPLE / 8) * CHANNELS;\n if (dataSize > MAX_WAV_DATA_BYTES) {\n throw new RangeError('morse-code-translator: audio is too long for a WAV file (about 13.5 hours at most).');\n }\n // Header plus one PCM part per chunk: the Blob never needs one contiguous\n // copy of the whole recording, and each rendered chunk can be released.\n const parts: ArrayBuffer[] = [encodeWAVHeader(SAMPLE_RATE, dataSize)];\n for (let start = 0; start < totalFrames; start = plan.next(start)) {\n // Reuse a playback render when there is one (if playback abandons it\n // meanwhile, render the chunk here); export renders are not cached.\n const render = () => {\n const job = enqueue(start, () => state !== 'disposed');\n pump();\n return job.promise;\n };\n const cached = chunks.get(start);\n const buffer = await (cached ? cached.catch((err) => (err === CANCELLED ? render() : Promise.reject(err))) : render());\n parts.push(floatTo16BitPCM(buffer.getChannelData(0)));\n }\n return new Blob(parts, { type: 'audio/wav' });\n };\n\n const getWaveUrl = async () => {\n const audioBlob = await getWaveBlob();\n return URL.createObjectURL(audioBlob);\n };\n\n const exportWave = async (filename: string = 'morse.wav') => {\n const waveUrl = await getWaveUrl();\n const anchor = document.createElement('a');\n anchor.href = waveUrl;\n anchor.target = '_blank';\n anchor.download = filename;\n anchor.click();\n // Release the internally-created object URL once the download has started.\n setTimeout(() => URL.revokeObjectURL(waveUrl), 1000);\n };\n\n const result = {\n // Playback control\n play,\n pause,\n stop,\n seek,\n dispose,\n\n // Playback information\n getCurrentTime,\n getTotalTime,\n getState,\n\n // Export functionality\n getWaveBlob,\n getWaveUrl,\n exportWave,\n } as Omit<AudioResult, 'context'>;\n\n // Context access (for advanced users); created lazily on first access. Defined\n // as a NON-enumerable getter so object spread / JSON.stringify / Object.keys do\n // not accidentally allocate a live AudioContext (browsers cap how many exist).\n Object.defineProperty(result, 'context', {\n get: getContext,\n enumerable: false,\n configurable: true,\n });\n\n return result as AudioResult;\n};\n\nexport default audio;\n","// Folds text into the forms the character tables are keyed by. Every rule here\n// maps a character to the one Morse operators actually send for it, so encode()\n// output for characters that already had a table key never changes.\n\n// Hangul syllable decomposition (Unicode 3.12) into compatibility jamo.\nconst HANGUL_BASE = 0xac00;\nconst HANGUL_END = 0xd7a3;\nconst CHOSEONG = 'ㄱㄲㄴㄷㄸㄹㅁㅂㅃㅅㅆㅇㅈㅉㅊㅋㅌㅍㅎ';\nconst JUNGSEONG = 'ㅏㅐㅑㅒㅓㅔㅕㅖㅗㅘㅙㅚㅛㅜㅝㅞㅟㅠㅡㅢㅣ';\nconst JONGSEONG = ['', ...'ㄱㄲㄳㄴㄵㄶㄷㄹㄺㄻㄼㄽㄾㄿㅀㅁㅂㅄㅅㅆㅇㅈㅊㅋㅌㅍㅎ'];\n\n// Korean Morse sends double consonants, consonant clusters and compound vowels\n// as their basic jamo.\nconst COMPOUND_JAMO: Record<string, string> = {\n 'ㄲ': 'ㄱㄱ', 'ㄸ': 'ㄷㄷ', 'ㅃ': 'ㅂㅂ', 'ㅆ': 'ㅅㅅ', 'ㅉ': 'ㅈㅈ',\n 'ㄳ': 'ㄱㅅ', 'ㄵ': 'ㄴㅈ', 'ㄶ': 'ㄴㅎ', 'ㄺ': 'ㄹㄱ', 'ㄻ': 'ㄹㅁ', 'ㄼ': 'ㄹㅂ',\n 'ㄽ': 'ㄹㅅ', 'ㄾ': 'ㄹㅌ', 'ㄿ': 'ㄹㅍ', 'ㅀ': 'ㄹㅎ', 'ㅄ': 'ㅂㅅ',\n 'ㅒ': 'ㅑㅣ', 'ㅖ': 'ㅕㅣ', 'ㅘ': 'ㅗㅏ', 'ㅙ': 'ㅗㅐ', 'ㅚ': 'ㅗㅣ', 'ㅝ': 'ㅜㅓ',\n 'ㅞ': 'ㅜㅔ', 'ㅟ': 'ㅜㅣ', 'ㅢ': 'ㅡㅣ'\n};\n\nconst splitJamo = (jamo: string): string => COMPOUND_JAMO[jamo] ?? jamo;\n\nconst decomposeHangul = (code: number): string => {\n const index = code - HANGUL_BASE;\n return (\n splitJamo(CHOSEONG[Math.floor(index / 588)]) +\n splitJamo(JUNGSEONG[Math.floor((index % 588) / 28)]) +\n splitJamo(JONGSEONG[index % 28])\n );\n};\n\n// Wabun sends small kana as their full-size forms.\nconst SMALL_KANA: Record<string, string> = {\n 'ァ': 'ア', 'ィ': 'イ', 'ゥ': 'ウ', 'ェ': 'エ', 'ォ': 'オ', 'ッ': 'ツ',\n 'ャ': 'ヤ', 'ュ': 'ユ', 'ョ': 'ヨ', 'ヮ': 'ワ', 'ヵ': 'カ', 'ヶ': 'ケ'\n};\n\nconst HIRAGANA = /[ぁ-ゖ]/; // U+3041-3096, maps to katakana at +0x60\nconst KATAKANA = /[゠-ヿ]/;\nconst KATAKANA_ITERATION = /[ヽヾ]/; // U+30FD/U+30FE: decompose to a non-letter base, leave them alone\n// Full-width ASCII (U+FF01-FF5E) and half-width kana (U+FF61-FF9F) fold to\n// their usual forms (NFKC <wide>/<narrow> decompositions). The full-width\n// parentheses U+FF08/FF09 are Japanese table keys, so they stay as they are.\nconst WIDTH_VARIANTS = /[\\uFF01-\\uFF07\\uFF0A-\\uFF5E\\uFF61-\\uFF9F]+/g;\n// A combining voiced/semi-voiced mark that did not compose (after NFKC of\n// half-width kana, or after kana that has no voiced form) is sent as the\n// standalone mark. After other letters it stays unknown.\nconst COMBINING_KANA_MARK = /[\\u3099\\u309A]/g;\nconst KANA_THEN_MARK = /(?<=[\\u3041-\\u3096\\u30A1-\\u30FA\\u30FC])[\\u3099\\u309A]/g;\nconst toStandaloneMark = (mark: string): string => (mark === '\\u3099' ? '\\u309B' : '\\u309C');\n// Hebrew points and cantillation, Arabic harakat, leftover hamza/madda marks\n// (NFC already joined them into the letters that have a precomposed form, such\n// as أ; what is left is e.g. the Persian ezafe on ه) and the tatweel are not\n// transmitted in Morse.\nconst HEBREW_MARKS = /[\\u0591-\\u05BD\\u05BF\\u05C1\\u05C2\\u05C4\\u05C5\\u05C7]/g;\nconst ARABIC_MARKS = /[\\u0640\\u064B-\\u065F\\u0670]/g;\n// Arabic-Indic, Persian and Thai digits are sent with the standard digit codes.\nconst EASTERN_DIGITS = /[\\u0660-\\u0669\\u06F0-\\u06F9\\u0E50-\\u0E59]/g;\nconst toDigit = (digit: string): string => String((digit.codePointAt(0) as number) & 0xf);\n// Thai NIKHAHIT + SARA AA is SARA AM (its compatibility decomposition).\nconst THAI_SARA_AM = /\\u0E4D\\u0E32/g;\n// Script variants of punctuation are sent as the standard punctuation:\n// Arabic question mark, comma and semicolon, Hebrew maqaf.\nconst PUNCTUATION: Record<string, string> = { '\\u061F': '?', '\\u060C': ',', '\\u061B': ';', '\\u05BE': '-' };\n// A Greek letter plus any combining marks after it (uppercasing can emit the\n// marks as separate code points, e.g. ΐ -> Ϊ́).\nconst GREEK_WITH_MARKS = /[Ͱ-Ͽἀ-῿][̀-ͯ]*/g;\nconst COMBINING_MARKS = /[̀-ͯ]/g;\n\n// Decompose precomposed (NFC) katakana such as ガ (U+30AC) into base kana + a\n// standalone voiced/semi-voiced mark (カ + ゛) so they match the Japanese map.\nconst foldKatakana = (character: string): string => {\n if (KATAKANA_ITERATION.test(character)) {\n return character;\n }\n return [...character.normalize('NFD').replace(/゙/g, '゛').replace(/゚/g, '゜')]\n .map((part) => SMALL_KANA[part] ?? part)\n .join('');\n};\n\nconst foldCharacter = (character: string): string => {\n const code = character.codePointAt(0) as number;\n if (code >= HANGUL_BASE && code <= HANGUL_END) {\n return decomposeHangul(code);\n }\n if (HIRAGANA.test(character)) {\n return foldKatakana(String.fromCodePoint(code + 0x60));\n }\n if (KATAKANA.test(character)) {\n return foldKatakana(character);\n }\n if (character === 'ẞ') {\n return 'SS';\n }\n if (PUNCTUATION[character]) {\n return PUNCTUATION[character];\n }\n return splitJamo(character);\n};\n\nexport const normalizeText = (text: string): string =>\n // toUpperCase (not toLocaleUpperCase) keeps casing deterministic regardless of\n // the host locale (e.g. avoids the Turkish i -> İ mapping). NFC so\n // canonically-equivalent decomposed input (e.g. NFD 'A'+◌́) recomposes to its\n // precomposed key ('Á') before lookup.\n [\n ...text\n .toUpperCase()\n .replace(WIDTH_VARIANTS, (run) => run.normalize('NFKC').replace(COMBINING_KANA_MARK, toStandaloneMark))\n .normalize('NFC')\n .replace(KANA_THEN_MARK, toStandaloneMark)\n .replace(HEBREW_MARKS, '')\n .replace(ARABIC_MARKS, '')\n .replace(EASTERN_DIGITS, toDigit)\n .replace(THAI_SARA_AM, '\\u0E33')\n // The tonos is not transmitted in Morse; the receiver infers it.\n .replace(GREEK_WITH_MARKS, (letter) => letter.normalize('NFD').replace(COMBINING_MARKS, ''))\n ]\n .map(foldCharacter)\n .join('');\n","import { getEncodeCharacters, getMappedCharacters, swapCharacters } from './characters.js';\nimport { tokenize } from './tokenize.js';\nimport getOptions, { assertString } from './options.js';\nimport getAudio from './audio.js';\nimport { normalizeText } from './normalize.js';\nimport type { MorseOptions, Characters, AudioResult } from './types.js';\n\n// One visible character (an emoji with modifiers, a letter with marks) that has\n// no code becomes ONE invalid marker, not one per code point. Engines without\n// Intl.Segmenter (e.g. Firefox before 125) treat every code point as a cluster.\nlet segmenter: Intl.Segmenter | null | undefined;\nfunction* clusters(text: string): Generator<string> {\n if (segmenter === undefined) {\n segmenter =\n typeof Intl !== 'undefined' && typeof Intl.Segmenter === 'function' ? new Intl.Segmenter(undefined, { granularity: 'grapheme' }) : null;\n }\n if (segmenter) {\n for (const { segment } of segmenter.segment(text)) yield segment;\n } else {\n yield* text;\n }\n}\n// Default-ignorable code points (ZWNJ/ZWJ, CGJ, direction marks, soft hyphen,\n// BOM, variation selectors, Hangul fillers) are invisible: they produce no output.\nconst INVISIBLE = /^\\p{Default_Ignorable_Code_Point}$/u;\n// JavaScript's \\s also matches U+FEFF, which Unicode does not count as whitespace.\nconst WHITESPACE = /[^\\S\\uFEFF]+/g;\n\nexport const encode = (text: string, opts?: MorseOptions | null): string => {\n assertString(text, 'text');\n const options = getOptions(opts);\n const characters = getEncodeCharacters(options);\n const lookup = (character: string): string | undefined => {\n for (const set in characters) {\n if (Object.prototype.hasOwnProperty.call(characters[set], character)) {\n return characters[set][character];\n }\n }\n return undefined;\n };\n\n const codes: string[] = [];\n const push = (code: string) => {\n // '' is a dropped unknown character (invalid: ''). A run of word gaps (also\n // around dropped characters) is one gap, and never at the start.\n if (code === '' || (code === options.space && (codes.length === 0 || codes[codes.length - 1] === options.space))) {\n return;\n }\n codes.push(code);\n };\n // Normalize BEFORE the separator goes in, so it can never combine with the\n // text (NFC) or change case; trim first so boundary whitespace cannot turn\n // into a separator.\n for (const segment of clusters(normalizeText(text.trim()).replace(WHITESPACE, options.separator))) {\n let unknown = false;\n for (const character of segment) {\n // Whitespace became the separator above; it encodes as a word gap.\n const code = character === options.separator ? options.space : lookup(character);\n if (code !== undefined) {\n push(code);\n unknown = false;\n } else if (!INVISIBLE.test(character)) {\n if (!unknown) push(options.invalid);\n unknown = true;\n }\n }\n }\n if (codes[codes.length - 1] === options.space) {\n codes.pop();\n }\n return codes.join(options.separator);\n};\n\nexport const decode = (morse: string, opts?: MorseOptions | null): string => {\n assertString(morse, 'morse');\n const options = getOptions(opts);\n const swapped = swapCharacters(options);\n return tokenize(morse, options)\n // swapped has a null prototype, so a \"constructor\" token cannot resolve.\n .map((token) => swapped[token] ?? options.invalid)\n .join('');\n};\n\nexport const characters = (options?: MorseOptions | null, usePriority: boolean = false): Characters => {\n return getMappedCharacters(getOptions(options), usePriority);\n};\n\nexport const audio = (text: string, opts?: MorseOptions | null, morseString?: string): AudioResult => {\n const options = getOptions(opts);\n // An explicit morse string (even '') wins; otherwise encode the text.\n if (morseString !== undefined) {\n assertString(morseString, 'morseString');\n }\n const morse = morseString ?? encode(text, opts);\n return getAudio(morse, options);\n};\n\n// Export types\nexport type { MorseOptions, Characters, AudioResult, Oscillator, OscillatorWaveform, AudioState, AudioEvents } from './types.js';\n\nexport default {\n encode,\n decode,\n characters,\n audio,\n};\n"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- (function(g,C){typeof exports=="object"&&typeof module<"u"?C(exports):typeof define=="function"&&define.amd?define(["exports"],C):(g=typeof globalThis<"u"?globalThis:g||self,C(g.MorseCodeTranslator={}))})(this,(function(g){"use strict";const C={1:{A:"01",B:"1000",C:"1010",D:"100",E:"0",F:"0010",G:"110",H:"0000",I:"00",J:"0111",K:"101",L:"0100",M:"11",N:"10",O:"111",P:"0110",Q:"1101",R:"010",S:"000",T:"1",U:"001",V:"0001",W:"011",X:"1001",Y:"1011",Z:"1100"},2:{0:"11111",1:"01111",2:"00111",3:"00011",4:"00001",5:"00000",6:"10000",7:"11000",8:"11100",9:"11110"},3:{".":"010101",",":"110011","?":"001100","'":"011110","!":"101011","/":"10010","(":"10110",")":"101101","&":"01000",":":"111000",";":"101010","=":"10001","+":"01010","-":"100001",_:"001101",'"':"010010",$:"0001001","@":"011010","¿":"00101","¡":"110001"},4:{Ã:"01101",Á:"01101",Å:"01101",À:"01101",Â:"01101",Ä:"0101",Ą:"0101",Æ:"0101",Ç:"10100",Ć:"10100",Ĉ:"10100",Č:"110",Ð:"00110",È:"01001",Ę:"00100",Ë:"00100",É:"00100",Ê:"10010",Ğ:"11010",Ĝ:"11010",Ĥ:"1111",İ:"01001",Ï:"10011",Ì:"01110",Ĵ:"01110",Ł:"01001",Ń:"11011",Ñ:"11011",Ó:"1110",Ò:"1110",Ö:"1110",Ô:"1110",Ø:"1110",Ś:"0001000",Ş:"01100",Ș:"1111",Š:"1111",Ŝ:"00010",ß:"000000",Þ:"01100",Ü:"0011",Ù:"0011",Ŭ:"0011",Ž:"11001",Ź:"110010",Ż:"11001"},5:{А:"01",Б:"1000",В:"011",Г:"110",Д:"100",Е:"0",Ж:"0001",З:"1100",И:"00",Й:"0111",К:"101",Л:"0100",М:"11",Н:"10",О:"111",П:"0110",Р:"010",С:"000",Т:"1",У:"001",Ф:"0010",Х:"0000",Ц:"1010",Ч:"1110",Ш:"1111",Щ:"1101",Ъ:"11011",Ы:"1011",Ь:"1001",Э:"00100",Ю:"0011",Я:"0101",Ї:"01110",Є:"00100",І:"00",Ґ:"110"},6:{Α:"01",Β:"1000",Γ:"110",Δ:"100",Ε:"0",Ζ:"1100",Η:"0000",Θ:"1010",Ι:"00",Κ:"101",Λ:"0100",Μ:"11",Ν:"10",Ξ:"1001",Ο:"111",Π:"0110",Ρ:"010",Σ:"000",Τ:"1",Υ:"1011",Φ:"0010",Χ:"1111",Ψ:"1101",Ω:"011"},7:{א:"01",ב:"1000",ג:"110",ד:"100",ה:"111",ו:"0",ז:"1100",ח:"0000",ט:"001",י:"00",כ:"101",ל:"0100",מ:"11",נ:"10",ס:"1010",ע:"0111",פ:"0110",צ:"011",ק:"1101",ר:"010",ש:"000",ת:"1"},8:{ا:"01",ب:"1000",ت:"1",ث:"1010",ج:"0111",ح:"0000",خ:"111",د:"100",ذ:"1100",ر:"010",ز:"1110",س:"000",ش:"1111",ص:"1001",ض:"0001",ط:"001",ظ:"1011",ع:"0101",غ:"110",ف:"0010",ق:"1101",ك:"101",ل:"0100",م:"11",ن:"10",ه:"00100",و:"011",ي:"00",ﺀ:"0"},9:{ا:"01",ب:"1000",پ:"0110",ت:"1",ث:"1010",ج:"0111",چ:"1110",ح:"0000",خ:"1001",د:"100",ذ:"0001",ر:"010",ز:"1100",ژ:"110",س:"000",ش:"1111",ص:"0101",ض:"00100",ط:"001",ظ:"1011",ع:"111",غ:"0011",ف:"0010",ق:"111000",ک:"101",گ:"1101",ل:"0100",م:"11",ن:"10",و:"011",ه:"0",ی:"00"},10:{ア:"11011",カ:"0100",サ:"10101",タ:"10",ナ:"010",ハ:"1000",マ:"1001",ヤ:"011",ラ:"000",ワ:"101",イ:"01",キ:"10100",シ:"11010",チ:"0010",ニ:"1010",ヒ:"11001",ミ:"00101",リ:"110",ヰ:"01001",ウ:"001",ク:"0001",ス:"11101",ツ:"0110",ヌ:"0000",フ:"1100",ム:"1",ユ:"10011",ル:"10110",ン:"01010",エ:"10111",ケ:"1011",セ:"01110",テ:"01011",ネ:"1101",ヘ:"0",メ:"10001",レ:"111",ヱ:"01100",オ:"01000",コ:"1111",ソ:"1110",ト:"00100",ノ:"0011",ホ:"100",モ:"10010",ヨ:"11",ロ:"0101",ヲ:"0111","゛":"00","゜":"00110","。":"010100",ー:"01101","、":"010101","(":"101101",")":"010010"},11:{ㄱ:"0100",ㄴ:"0010",ㄷ:"1000",ㄹ:"0001",ㅁ:"11",ㅂ:"011",ㅅ:"110",ㅇ:"101",ㅈ:"0110",ㅊ:"1010",ㅋ:"1001",ㅌ:"1100",ㅍ:"111",ㅎ:"0111",ㅏ:"0",ㅑ:"00",ㅓ:"1",ㅕ:"000",ㅗ:"01",ㅛ:"10",ㅜ:"0000",ㅠ:"010",ㅡ:"100",ㅣ:"001",ㅐ:"1101",ㅔ:"1011"},12:{ก:"110",ข:"1010",ค:"101",ง:"10110",จ:"10010",ฉ:"1111",ช:"1001",ซ:"1100",ญ:"0111",ด:"100",ต:"1",ถ:"10100",ท:"10011",น:"10",บ:"1000",ป:"0110",ผ:"1101",ฝ:"10101",พ:"01100",ฟ:"0010",ม:"11",ย:"1011",ร:"010",ล:"0100",ว:"011",ส:"000",ห:"0000",อ:"10001",ฮ:"11011",ฤ:"01011",ะ:"01000",า:"01","ิ":"00100","ี":"00","ึ":"00110","ื":"0011","ุ":"00101","ู":"1110",เ:"0",แ:"0101",ไ:"01001",โ:"111",ำ:"00010","่":"001","้":"0001","๊":"11000","๋":"01010","ั":"01101","็":"11100","์":"11001",ๆ:"10111",ฯ:"11010"}},P=e=>({...C,0:C[e.priority],1:{...C[1],[e.separator]:e.space}}),M=(e,t)=>{const n={},i=P(e);for(const o in i){n[o]={};const w=i[o];if(w)for(const c in w)n[o][c]=w[c].replace(/0/g,e.dot).replace(/1/g,e.dash)}return t||delete n[0],n},G=e=>{const t={},n=M(e,!0);for(const i in n)for(const o in n[i])typeof t[n[i][o]]>"u"&&(t[n[i][o]]=o);return t},v=(e={})=>({...e,dash:e.dash||"-",dot:e.dot||".",space:e.space||"/",separator:e.separator||" ",invalid:e.invalid||"#",priority:e.priority||1,wpm:e.wpm,unit:e.unit||.08,fwUnit:e.fwUnit||e.unit||.08,volume:e.volume||100,oscillator:{...e.oscillator,type:e.oscillator?.type||"sine",frequency:e.oscillator?.frequency||500,onended:e.oscillator?.onended||null}}),_=44100,U=1,E=16,H=1,j=3,I=1,q=3,F=7,z=50,$=(e,t,n=0)=>{const i=[];let{unit:o,fwUnit:w}=t,c=0;t.wpm&&(o=w=60/(t.wpm*z)),i.push([0,c]);const b=(r,u,a=!0)=>{i.push([r,n+c]),c+=u*(a?o:w)},s=r=>b(t.volume/100,r),m=r=>b(0,r),y=r=>b(0,r,!1);for(let r=0,u=!1;r<=e.length;r++){const a=e[r],f=e[r+1],A=e[r-1];a===t.space?(y(F),u=!1):a===t.dot?(u&&m(I),s(H),u=!0):a===t.dash?(u&&m(I),s(j),u=!0):f!==void 0&&f!==t.space&&A!==void 0&&A!==t.space&&(y(q),u=!1)}return[i,c]},J=(e,t)=>{const n=E/8,i=U*n,o=e*i,w=t.length*n,c=44+w,b=new ArrayBuffer(c),s=new DataView(b),m=(r,u)=>{for(let a=0;a<u.length;a++)s.setUint8(r+a,u.charCodeAt(a))},y=(r,u)=>{for(let a=0;a<u.length;a++,r+=n){const f=Math.max(-1,Math.min(1,u[a])),A=f<0?f*32768:f*32767;s.setInt16(r,A,!0)}};return m(0,"RIFF"),s.setUint32(4,c-8,!0),m(8,"WAVE"),m(12,"fmt "),s.setUint32(16,16,!0),s.setUint16(20,1,!0),s.setUint16(22,U,!0),s.setUint32(24,e,!0),s.setUint32(28,o,!0),s.setUint16(32,i,!0),s.setUint16(34,E,!0),m(36,"data"),s.setUint32(40,w,!0),y(44,t),s},K=(e,t)=>{const n=window.AudioContext||window.webkitAudioContext,i=window.OfflineAudioContext||window.webkitOfflineAudioContext;if(!n||!i)throw new Error("Web Audio API is not supported in this browser. Please use a modern browser with Web Audio API support.");const o=new n,[w,c]=$(e,t),b=Math.ceil(_*c),s=new i(U,b,_),m=s.createOscillator(),y=s.createGain();m.type=t.oscillator.type,m.frequency.value=t.oscillator.frequency??500,w.forEach(([l,p])=>{y.gain.setValueAtTime(l,p)}),m.connect(y),y.connect(s.destination);let r=null,u=null,a="ready",f=0,A=0,h=null;const T=t.events||{};t.oscillator.onended&&!T.onended&&(T.onended=t.oscillator.onended);const W=new Promise((l,p)=>{m.start(0),s.startRendering(),s.oncomplete=d=>{try{u=d.renderedBuffer,a="ready",T.onready?.(),l()}catch(V){p(V)}},s.addEventListener("error",d=>{p(d)})}),X=()=>{const l=o.createBufferSource();return l.buffer=u,l.connect(o.destination),l.onended=()=>{const p=D();a==="playing"&&p>=c-.01&&(a="stopped",f=0,T.onended?.())},l},B=async()=>{if(await W,o.state==="suspended"&&await o.resume(),a==="playing")return;(!r||r.buffer===null)&&(r=X()),r.start(o.currentTime,f),A=o.currentTime-f,a="playing",T.onstarted?.();const l=(c-f)*1e3;h=window.setTimeout(()=>{a==="playing"&&R()},l)},Y=()=>{a==="playing"&&(h!==null&&(clearTimeout(h),h=null),f=Math.min(o.currentTime-A,c),r&&(r.stop(0),r=null),a="paused",T.onpaused?.())},R=(l=!1)=>{if(h!==null&&(clearTimeout(h),h=null),r){try{r.stop(0)}catch{}r=null}const p=a==="playing";a="stopped",f=0,A=0,p&&T.onstopped?.(),l&&(u=null)},Z=async l=>{const p=a==="playing",d=Math.max(0,Math.min(l,c));if(r){h!==null&&(clearTimeout(h),h=null);try{r.stop(0)}catch{}r=null}f=d,T.onseeked?.(d),p&&(a="paused",await B())},e0=()=>{R(!0),o.state!=="closed"&&o.close()},D=()=>a==="playing"?Math.min(o.currentTime-A,c):f,t0=()=>c,n0=()=>a,k=async()=>{if(await W,!u)throw new Error("Audio buffer not available");const l=J(s.sampleRate,u.getChannelData(0)),p=new Uint8Array(l.byteLength);for(let d=0;d<l.byteLength;d++)p[d]=l.getUint8(d);return new Blob([p],{type:"audio/wav"})},N=async()=>{const l=await k();return URL.createObjectURL(l)};return{play:B,pause:Y,stop:R,seek:Z,dispose:e0,getCurrentTime:D,getTotalTime:t0,getState:n0,getWaveBlob:k,getWaveUrl:N,exportWave:async(l="morse.wav")=>{const p=await N(),d=document.createElement("a");d.href=p,d.target="_blank",d.download=l,d.click()},context:o,oscillator:m,gainNode:y}},S=(e,t)=>{const n=v(t),i=P(n);return[...e.replace(/\s+/g,n.separator).trim().toLocaleUpperCase()].map(o=>{for(const w in i){const c=i[w];if(c&&c[o])return c[o]}return n.invalid}).join(n.separator).replace(/0/g,n.dot).replace(/1/g,n.dash)},O=(e,t)=>{const n=v(t),i=G(n);return e.replace(/\s+/g,n.separator).trim().split(n.separator).map(o=>typeof i[o]<"u"?i[o]:n.invalid).join("")},x=(e,t=!1)=>M(v(e),t),L=(e,t,n)=>{const i=n||S(e,t),o=v(t);return K(i,o)},Q={encode:S,decode:O,characters:x,audio:L};g.audio=L,g.characters=x,g.decode=O,g.default=Q,g.encode=S,Object.defineProperties(g,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}})}));
2
- //# sourceMappingURL=morse-code-translator.umd.js.map
1
+ (function(e,t){typeof exports==`object`&&typeof module<`u`?t(exports):typeof define==`function`&&define.amd?define([`exports`],t):(e=typeof globalThis<`u`?globalThis:e||self,t(e.MorseCodeTranslator={}))})(this,function(e){Object.defineProperties(e,{__esModule:{value:!0},[Symbol.toStringTag]:{value:`Module`}});var t={1:{A:`01`,B:`1000`,C:`1010`,D:`100`,E:`0`,F:`0010`,G:`110`,H:`0000`,I:`00`,J:`0111`,K:`101`,L:`0100`,M:`11`,N:`10`,O:`111`,P:`0110`,Q:`1101`,R:`010`,S:`000`,T:`1`,U:`001`,V:`0001`,W:`011`,X:`1001`,Y:`1011`,Z:`1100`},2:{0:`11111`,1:`01111`,2:`00111`,3:`00011`,4:`00001`,5:`00000`,6:`10000`,7:`11000`,8:`11100`,9:`11110`},3:{".":`010101`,",":`110011`,"?":`001100`,"'":`011110`,"!":`101011`,"/":`10010`,"(":`10110`,")":`101101`,"&":`01000`,":":`111000`,";":`101010`,"=":`10001`,"+":`01010`,"-":`100001`,_:`001101`,'"':`010010`,$:`0001001`,"@":`011010`,"¿":`00101`,"¡":`110001`},4:{Ã:`01101`,Á:`01101`,Å:`01101`,À:`01101`,Â:`01101`,Ä:`0101`,Ą:`0101`,Æ:`0101`,Ç:`10100`,Ć:`10100`,Ĉ:`10100`,Č:`110`,Ð:`00110`,È:`01001`,É:`00100`,Ę:`00100`,Ë:`00100`,Ê:`10010`,Ğ:`11010`,Ĝ:`11010`,Ĥ:`1111`,İ:`01001`,Ï:`10011`,Ì:`01110`,Ĵ:`01110`,Ł:`01001`,Ń:`11011`,Ñ:`11011`,Ó:`1110`,Ò:`1110`,Ö:`1110`,Ô:`1110`,Ø:`1110`,Ś:`0001000`,Ş:`01100`,Ș:`1111`,Š:`1111`,Ŝ:`00010`,Þ:`01100`,Ü:`0011`,Ù:`0011`,Ŭ:`0011`,Ž:`11001`,Ź:`110010`,Ż:`11001`},5:{А:`01`,Б:`1000`,В:`011`,Г:`110`,Д:`100`,Е:`0`,Ж:`0001`,З:`1100`,И:`00`,Й:`0111`,К:`101`,Л:`0100`,М:`11`,Н:`10`,О:`111`,П:`0110`,Р:`010`,С:`000`,Т:`1`,У:`001`,Ф:`0010`,Х:`0000`,Ц:`1010`,Ч:`1110`,Ш:`1111`,Щ:`1101`,Ъ:`11011`,Ы:`1011`,Ь:`1001`,Э:`00100`,Ю:`0011`,Я:`0101`,Ї:`01110`,Є:`00100`,І:`00`,Ґ:`110`,Ё:`0`},6:{Α:`01`,Β:`1000`,Γ:`110`,Δ:`100`,Ε:`0`,Ζ:`1100`,Η:`0000`,Θ:`1010`,Ι:`00`,Κ:`101`,Λ:`0100`,Μ:`11`,Ν:`10`,Ξ:`1001`,Ο:`111`,Π:`0110`,Ρ:`010`,Σ:`000`,Τ:`1`,Υ:`1011`,Φ:`0010`,Χ:`1111`,Ψ:`1101`,Ω:`011`},7:{א:`01`,ב:`1000`,ג:`110`,ד:`100`,ה:`111`,ו:`0`,ז:`1100`,ח:`0000`,ט:`001`,י:`00`,כ:`101`,ל:`0100`,מ:`11`,נ:`10`,ס:`1010`,ע:`0111`,פ:`0110`,צ:`011`,ק:`1101`,ר:`010`,ש:`000`,ת:`1`,ך:`101`,ם:`11`,ן:`10`,ף:`0110`,ץ:`011`},8:{ا:`01`,ب:`1000`,ت:`1`,ث:`1010`,ج:`0111`,ح:`0000`,خ:`111`,د:`100`,ذ:`1100`,ر:`010`,ز:`1110`,س:`000`,ش:`1111`,ص:`1001`,ض:`0001`,ط:`001`,ظ:`1011`,ع:`0101`,غ:`110`,ف:`0010`,ق:`1101`,ك:`101`,ل:`0100`,م:`11`,ن:`10`,ه:`00100`,و:`011`,ي:`00`,ء:`0`,ﺀ:`0`},9:{ا:`01`,ب:`1000`,پ:`0110`,ت:`1`,ث:`1010`,ج:`0111`,چ:`1110`,ح:`0000`,خ:`1001`,د:`100`,ذ:`0001`,ر:`010`,ز:`1100`,ژ:`110`,س:`000`,ش:`1111`,ص:`0101`,ض:`00100`,ط:`001`,ظ:`1011`,ع:`111`,غ:`0011`,ف:`0010`,ق:`111000`,ک:`101`,گ:`1101`,ل:`0100`,م:`11`,ن:`10`,و:`011`,ه:`0`,ی:`00`},10:{ア:`11011`,カ:`0100`,サ:`10101`,タ:`10`,ナ:`010`,ハ:`1000`,マ:`1001`,ヤ:`011`,ラ:`000`,ワ:`101`,イ:`01`,キ:`10100`,シ:`11010`,チ:`0010`,ニ:`1010`,ヒ:`11001`,ミ:`00101`,リ:`110`,ヰ:`01001`,ウ:`001`,ク:`0001`,ス:`11101`,ツ:`0110`,ヌ:`0000`,フ:`1100`,ム:`1`,ユ:`10011`,ル:`10110`,ン:`01010`,エ:`10111`,ケ:`1011`,セ:`01110`,テ:`01011`,ネ:`1101`,ヘ:`0`,メ:`10001`,レ:`111`,ヱ:`01100`,オ:`01000`,コ:`1111`,ソ:`1110`,ト:`00100`,ノ:`0011`,ホ:`100`,モ:`10010`,ヨ:`11`,ロ:`0101`,ヲ:`0111`,゛:`00`,゜:`00110`,"。":`010100`,ー:`01101`,"、":`010101`,"(":`101101`,")":`010010`},11:{ㄱ:`0100`,ㄴ:`0010`,ㄷ:`1000`,ㄹ:`0001`,ㅁ:`11`,ㅂ:`011`,ㅅ:`110`,ㅇ:`101`,ㅈ:`0110`,ㅊ:`1010`,ㅋ:`1001`,ㅌ:`1100`,ㅍ:`111`,ㅎ:`0111`,ㅏ:`0`,ㅑ:`00`,ㅓ:`1`,ㅕ:`000`,ㅗ:`01`,ㅛ:`10`,ㅜ:`0000`,ㅠ:`010`,ㅡ:`100`,ㅣ:`001`,ㅐ:`1101`,ㅔ:`1011`},12:{ก:`110`,ข:`1010`,ค:`101`,ง:`10110`,จ:`10010`,ฉ:`1111`,ช:`1001`,ซ:`1100`,ญ:`0111`,ด:`100`,ต:`1`,ถ:`10100`,ท:`10011`,น:`10`,บ:`1000`,ป:`0110`,ผ:`1101`,ฝ:`10101`,พ:`01100`,ฟ:`0010`,ม:`11`,ย:`1011`,ร:`010`,ล:`0100`,ว:`011`,ส:`000`,ห:`0000`,อ:`10001`,ฮ:`11011`,ฤ:`01011`,ะ:`01000`,า:`01`,"ิ":`00100`,"ี":`00`,"ึ":`00110`,"ื":`0011`,"ุ":`00101`,"ู":`1110`,เ:`0`,แ:`0101`,ไ:`01001`,โ:`111`,ำ:`00010`,"่":`001`,"้":`0001`,"๊":`11000`,"๋":`01010`,"ั":`01101`,"็":`11100`,"์":`11001`,ๆ:`10111`,ฯ:`11010`,ฃ:`1010`,ฅ:`101`,ฆ:`101`,ศ:`000`,ษ:`000`,ฌ:`1001`,ฎ:`100`,ฏ:`1`,ฐ:`10100`,ฑ:`10011`,ฒ:`10011`,ธ:`10011`,ณ:`10`,ภ:`01100`,ฬ:`0100`,ใ:`01001`}},n=16,r=new Map,i=e=>{let i=JSON.stringify([e.dot,e.dash,e.space,e.priority]),a=r.get(i);if(a)return a;let o={},s={...t,0:t[e.priority]};for(let t in s){o[t]={};for(let n in s[t])o[t][n]=s[t][n].replace(/[01]/g,t=>t===`0`?e.dot:e.dash)}let c=Object.create(null);for(let e in o)for(let t in o[e])c[o[e][t]]??=t;c[e.space]=` `,r.size>=n&&r.delete(r.keys().next().value);let l={mapped:o,swapped:c};return r.set(i,l),l},a=e=>i(e).mapped,o=e=>i(e).swapped,s=(e,t)=>{let n={},{mapped:r}=i(e);for(let e in r)(e!==`0`||t)&&(n[e]={...r[e]});return n},c=(e,t)=>{let n=[];for(let r of e.trim().replace(/\s+/g,t.separator).split(t.separator))r.split(t.space).forEach((e,r)=>{r>0&&n.push(t.space),e!==``&&n.push(e)});return n},l=22050,u={dash:`-`,dot:`.`,space:`/`,separator:` `,invalid:`#`},d=e=>typeof e==`number`&&Number.isFinite(e)&&e>0,f=e=>Object.values(t).some(t=>Object.prototype.hasOwnProperty.call(t,e)),p=(e,t,n)=>{if(e===``)return!1;let r=0;for(;r<e.length;)if(e.startsWith(t,r))r+=t.length;else if(e.startsWith(n,r))r+=n.length;else return!1;return!0};function m(e,t){if(typeof e!=`string`)throw TypeError(`morse-code-translator: ${t} must be a string.`)}var h=(e,t)=>{let n=e[t];return n==null?u[t]:(m(n,`"${t}"`),n===``&&t!==`invalid`?u[t]:n)},g=e=>{let t=typeof e==`string`&&/^\d+$/.test(e)?Number(e):e;return Number.isInteger(t)&&t>=1&&t<=12?t:1},_=e=>{if(e.dot===e.dash)throw Error(`morse-code-translator: "dot" and "dash" symbols must be different.`);if(e.dot.startsWith(e.dash)||e.dash.startsWith(e.dot))throw Error(`morse-code-translator: "dot" and "dash" must not be a prefix of each other.`);if(e.separator===e.space)throw Error(`morse-code-translator: "separator" and "space" symbols must be different.`);for(let[t,n]of[[`separator`,e.separator],[`space`,e.space]]){if([...n].length!==1)throw Error(`morse-code-translator: "${t}" must be a single character.`);if(n===e.dot||n===e.dash)throw Error(`morse-code-translator: "${t}" must differ from the "dot" and "dash" symbols.`);if(p(n,e.dot,e.dash))throw Error(`morse-code-translator: "${t}" must not be composed solely of "dot"/"dash" symbols.`);if(t===`space`&&/\s/.test(n))throw Error(`morse-code-translator: "space" must not be a whitespace character.`)}for(let[t,n]of[[`dot`,e.dot],[`dash`,e.dash]])if(n.includes(e.space)||n.includes(e.separator)||/\s/.test(n))throw Error(`morse-code-translator: "${t}" must not contain whitespace or the "space"/"separator" symbol.`);if(f(e.separator))throw Error(`morse-code-translator: "separator" must not be an encodable character.`);if(e.invalid!==``){if(p(e.invalid,e.dot,e.dash))throw Error(`morse-code-translator: "invalid" must not be composed solely of "dot"/"dash" symbols.`);if(e.invalid.includes(e.space)||e.invalid.includes(e.separator)||/\s/.test(e.invalid))throw Error(`morse-code-translator: "invalid" must not contain whitespace or the "space"/"separator" symbol.`)}},v=e=>{let t=e??{},n=d(t.unit)?t.unit:.08,r=d(t.fwUnit)?t.fwUnit:n,i=d(t.wpm)?t.wpm:void 0,a=t.oscillator?.frequency,o=d(a)&&a<=l?a:500,s=typeof t.volume==`number`&&Number.isFinite(t.volume)?Math.min(100,Math.max(0,t.volume)):100,c=g(t.priority),u=t.oscillator?.type,f=u===`sine`||u===`square`||u===`sawtooth`||u===`triangle`?u:`sine`,p={...t,dash:h(t,`dash`),dot:h(t,`dot`),space:h(t,`space`),separator:h(t,`separator`),invalid:h(t,`invalid`),priority:c,wpm:i,unit:n,fwUnit:r,volume:s,oscillator:{type:f,frequency:o},events:t.events?{...t.events}:t.events};return _(p),p},y=44100,b=1,ee=16,x=44,te=4294967259,S=1,C=3,w=1,T=3,E=7,D=50,O=.005,ne=3,k=.005,re=2,ie=2,A=Error(`morse-code-translator: render cancelled.`),j=e=>{if(e.wpm){let t=60/(e.wpm*D);return[t,t]}return[e.unit,e.fwUnit]},ae=(e,t)=>{let[n,r]=j(t),i=t.dot.length>=t.dash.length?[[t.dot,S],[t.dash,C]]:[[t.dash,C],[t.dot,S]],a=[],o=0,s=!1;for(let l of c(e,t)){if(l===t.space){s=a.length>0;continue}if(l===t.invalid)continue;let e=[];for(let t=0;t<l.length;){let n=i.find(([e])=>l.startsWith(e,t));n?(e.push(n[1]),t+=n[0].length):t+=1}e.length!==0&&(a.length>0&&(o+=(s?E:T)*r),s=!1,e.forEach((e,t)=>{t>0&&(o+=w*n),a.push(o,e*n),o+=e*n}))}if(!Number.isFinite(o))throw RangeError(`morse-code-translator: audio duration is not finite; use a smaller unit/fwUnit.`);return{tones:Float64Array.from(a),totalTime:o}},M=(e,t,n)=>{let r=.5*t/n+1e-6;return Math.max(0,Math.ceil(e*t-r)/t-e)},oe=(e,t,n,r,i=30*n)=>{let a=e.length/2,o=t=>Math.floor(e[t*2]*n),s=t=>Math.ceil((e[t*2]+e[t*2+1])*n),c=Math.ceil(n/r)+1,l=e=>{let t=0,n=a;for(;t<n;){let r=t+n>>1;s(r)<=e?t=r+1:n=r}return t},u=e=>{let u=e*i;if(e===0||u>=t)return Math.min(u,t);let d=u+i;for(let e=l(u);e<=a;e++){let n=e===0?u:Math.max(u,s(e-1));if(n>=d||n>=t)break;if(e===a||o(e)-n>=c)return n}return t<=d?t:Math.min(Math.round(Math.ceil(u/n*r)/r*n),t)};return{startFor:e=>{let t=Math.floor(e/i),n=u(t);return n<=e?n:u(t-1)},next:e=>u(Math.floor(e/i)+1)}},se=(e,t,n,r,i)=>{let a=Math.max(1,i-r),o=new e(b,a,y),s=o.createOscillator(),c=o.createGain(),l=n.oscillator.frequency??500,u=n.volume/100;s.type=n.oscillator.type??`sine`,s.frequency.value=l;let d=r/y,f=d+a/y,p=e=>{let n=t[e*2],r=t[e*2+1],i=Math.min(O,r/4);return[[n,0,!1],[n+i,u,!0],[n+r-i,u,!1],[n+r,0,!0]]},m=0;for(let e=0,n=t.length/2;e<n;){let r=e+n>>1;t[r*2]+t[r*2+1]<=d?e=r+1:n=r,m=e}let h=c.gain,g=0;if(m*2<t.length&&t[m*2]<d){let e=p(m);for(let t=1;t<e.length;t++){let[n,r,i]=e[t];if(n>d){let[a,o]=e[t-1];g=i?o+(r-o)*(d-a)/(n-a):o;break}}}h.setValueAtTime(g,0);for(let e=m;e*2<t.length&&t[e*2]<f;e++)for(let[t,n,r]of p(e))t>d&&(r?h.linearRampToValueAtTime(n,t-d):h.setValueAtTime(n,t-d));return s.connect(c),c.connect(o.destination),s.start(M(d,l,y)),o.startRendering()},N=(e,t,n)=>{for(let r=0;r<n.length;r++)e.setUint8(t+r,n.charCodeAt(r))},ce=(e,t)=>{let n=new DataView(new ArrayBuffer(x));return N(n,0,`RIFF`),n.setUint32(4,36+t,!0),N(n,8,`WAVE`),N(n,12,`fmt `),n.setUint32(16,16,!0),n.setUint16(20,1,!0),n.setUint16(22,b,!0),n.setUint32(24,e,!0),n.setUint32(28,e*2,!0),n.setUint16(32,2,!0),n.setUint16(34,ee,!0),N(n,36,`data`),n.setUint32(40,t,!0),n.buffer},le=e=>{let t=new DataView(new ArrayBuffer(e.length*2));for(let n=0;n<e.length;n++){let r=Math.max(-1,Math.min(1,e[n]));t.setInt16(n*2,r<0?r*32768:r*32767,!0)}return t.buffer},P=(e,...t)=>{try{e?.(...t)}catch(e){console.error(e)}},ue=(e,t)=>{let n=typeof window<`u`&&window?window:globalThis,r=n.AudioContext,i=n.OfflineAudioContext;if(!r||!i)throw Error(`Web Audio API is not supported in this browser. Please use a modern browser with Web Audio API support.`);let{tones:a,totalTime:o}=ae(e,t),s=Math.max(1,Math.ceil(y*o)),c=oe(a,s,y,t.oscillator.frequency??500),l=e=>se(i,a,t,e,Math.min(c.next(e),s)),u=null,d=new Set,f=null,p=0,m=0,h=0,g=!1,_=`ready`,v=0,x=0,S=!1,C=null,w=0,T=()=>(!u&&_!==`disposed`&&(u=new r),u),E=t.events||{},D=new Map,O=[],j=new Map,M=0,N=e=>{try{return l(e)}catch(e){return Promise.reject(e)}},ue=e=>{j.get(e.start)===e&&j.delete(e.start),D.get(e.start)===e.promise&&D.delete(e.start)},F=()=>{for(;M<re&&O.length>0;){let e=O.shift();e.wanted.some(e=>e())?(M++,N(e.start).then(e.resolve,e.reject).finally(()=>{j.get(e.start)===e&&j.delete(e.start),M--,F()})):(ue(e),e.reject(A))}},I=(e,t)=>{let n={start:e,wanted:[t]};return n.promise=new Promise((e,t)=>{n.resolve=e,n.reject=t}),O.push(n),n},L=(e,t=()=>!0)=>{let n=D.get(e);if(n)j.get(e)?.wanted.push(t),D.delete(e);else{let r=I(e,t);j.set(e,r),n=r.promise;let i=n;i.catch(()=>{D.get(e)===i&&D.delete(e)})}for(D.set(e,n);D.size>ne;)D.delete(D.keys().next().value);return F(),n},R=null,z=()=>(R??=L(0).then(()=>{_!==`disposed`&&P(E.onready)},e=>{throw R=null,e}),R);z().catch(()=>{});let B=()=>{let e=u,t=e!==null&&f!==null,n=t?e.currentTime+k:0;if(t){let{gain:t}=f,r=e.currentTime,i=Math.min(1,Math.max(0,(r-p)/k));t.cancelScheduledValues(r),t.setValueAtTime(i,r),t.linearRampToValueAtTime(0,n),m=n}for(let e of d)try{e.stop(n)}catch{}return d.clear(),f=null,g=!1,t},V=()=>{d.clear(),f=null,_=`stopped`,v=0,x=0,P(E.onended)},H=(e,t,n)=>{let r=u,i=x+e/y,a=r.currentTime,o=r.createBufferSource();if(o.buffer=t,a>i+1/y){let e=r.createGain();e.gain.setValueAtTime(0,a),e.gain.linearRampToValueAtTime(1,a+k),e.connect(f),o.connect(e)}else o.connect(f);o.onended=()=>{d.delete(o),w===n&&_===`playing`&&(d.size===0&&h>=s?V():W(n))},o.start(Math.max(i,a),Math.max(0,a-i)),d.add(o),h=c.next(e)},U=-1,W=e=>{if(g||d.size>=2||h>=s)return;let t=h,n=()=>w===e&&_===`playing`;g=!0,L(t,n).then(r=>{n()&&(g=!1,H(t,r,e),W(e))},r=>{n()&&(g=!1,r===A?W(e):(console.error(r),U===t?d.size===0&&K():(U=t,d.size===0&&W(e))))})},G=async()=>{if(_===`playing`||_===`disposed`)return;let e=T(),t=()=>e.state===`suspended`||e.state===`interrupted`,n=t()?e.resume():null;n?.catch(()=>{});let r=++w;S=!0;let i=()=>w===r&&_!==`disposed`,a=e=>L(e,i).catch(()=>i()?L(e,i):Promise.reject(A));try{let o=v,l=c.startFor(Math.floor(o*y)),u=c.next(l),d=a(l),m=u<s&&u/y-o<ie?L(u,i).catch(()=>null):null,h=Promise.all([d,m]);h.catch(()=>{});let b;try{if(b=await h,!i()||(await z().catch(()=>{}),!i()))return;n&&await n,t()&&await e.resume()}catch(e){if(!i())return;throw C===`playing`?K():C!==null&&(_=C,C=null),e}if(!i())return;x=e.currentTime-o,_=`playing`,S=!1,C=null,U=-1,p=e.currentTime,f=e.createGain(),f.gain.setValueAtTime(0,e.currentTime),f.gain.linearRampToValueAtTime(1,e.currentTime+k),f.connect(e.destination),g=!1,H(l,b[0],r),b[1]&&H(u,b[1],r),W(r),P(E.onstarted)}finally{w===r&&(S=!1)}},de=()=>{_!==`disposed`&&(_===`playing`?(w++,S=!1,C=null,v=Math.min(T().currentTime-x,o),B(),_=`paused`,P(E.onpaused)):S&&(w++,S=!1,C=null,B(),_=`paused`,P(E.onpaused)))},K=(e=!1)=>{if(_===`disposed`)return;w++,B();let t=_===`playing`||_===`paused`||S;S=!1,C=null,_=`stopped`,v=0,x=0,t&&P(E.onstopped),e&&D.clear()},fe=async e=>{if(_===`disposed`)return;let t=_===`playing`||S,n=Number(e),r=Number.isNaN(n)?0:Math.max(0,Math.min(n,o)),i=++w;B(),v=r,t&&(C??=J(),_=`paused`,S=!0),P(E.onseeked,r),t&&w===i&&await G()},pe=()=>{if(_===`disposed`)return;K(!0),_=`disposed`;let e=u;if(e&&e.state!==`closed`){let t=()=>e.close().catch(()=>{}),n=m-e.currentTime;n>0?setTimeout(t,n*1e3+45):t()}},q=()=>_===`playing`?Math.min(T().currentTime-x,o):v,me=()=>o,J=()=>C??_,Y=null,he=()=>_===`disposed`?Promise.reject(Error(`Audio buffer not available`)):(Y??=ge().finally(()=>{Y=null}),Y),ge=async()=>{if(await z(),_===`disposed`)throw Error(`Audio buffer not available`);let e=ee/8*s*b;if(e>te)throw RangeError(`morse-code-translator: audio is too long for a WAV file (about 13.5 hours at most).`);let t=[ce(y,e)];for(let e=0;e<s;e=c.next(e)){let n=()=>{let t=I(e,()=>_!==`disposed`);return F(),t.promise},r=D.get(e),i=await(r?r.catch(e=>e===A?n():Promise.reject(e)):n());t.push(le(i.getChannelData(0)))}return new Blob(t,{type:`audio/wav`})},X=async()=>{let e=await he();return URL.createObjectURL(e)},Z={play:G,pause:de,stop:K,seek:fe,dispose:pe,getCurrentTime:q,getTotalTime:me,getState:J,getWaveBlob:he,getWaveUrl:X,exportWave:async(e=`morse.wav`)=>{let t=await X(),n=document.createElement(`a`);n.href=t,n.target=`_blank`,n.download=e,n.click(),setTimeout(()=>URL.revokeObjectURL(t),1e3)}};return Object.defineProperty(Z,"context",{get:T,enumerable:!1,configurable:!0}),Z},F=44032,I=55203,L=`ㄱㄲㄴㄷㄸㄹㅁㅂㅃㅅㅆㅇㅈㅉㅊㅋㅌㅍㅎ`,R=`ㅏㅐㅑㅒㅓㅔㅕㅖㅗㅘㅙㅚㅛㅜㅝㅞㅟㅠㅡㅢㅣ`,z=[``,...`ㄱㄲㄳㄴㄵㄶㄷㄹㄺㄻㄼㄽㄾㄿㅀㅁㅂㅄㅅㅆㅇㅈㅊㅋㅌㅍㅎ`],B={ㄲ:`ㄱㄱ`,ㄸ:`ㄷㄷ`,ㅃ:`ㅂㅂ`,ㅆ:`ㅅㅅ`,ㅉ:`ㅈㅈ`,ㄳ:`ㄱㅅ`,ㄵ:`ㄴㅈ`,ㄶ:`ㄴㅎ`,ㄺ:`ㄹㄱ`,ㄻ:`ㄹㅁ`,ㄼ:`ㄹㅂ`,ㄽ:`ㄹㅅ`,ㄾ:`ㄹㅌ`,ㄿ:`ㄹㅍ`,ㅀ:`ㄹㅎ`,ㅄ:`ㅂㅅ`,ㅒ:`ㅑㅣ`,ㅖ:`ㅕㅣ`,ㅘ:`ㅗㅏ`,ㅙ:`ㅗㅐ`,ㅚ:`ㅗㅣ`,ㅝ:`ㅜㅓ`,ㅞ:`ㅜㅔ`,ㅟ:`ㅜㅣ`,ㅢ:`ㅡㅣ`},V=e=>B[e]??e,H=e=>{let t=e-F;return V(L[Math.floor(t/588)])+V(R[Math.floor(t%588/28)])+V(z[t%28])},U={ァ:`ア`,ィ:`イ`,ゥ:`ウ`,ェ:`エ`,ォ:`オ`,ッ:`ツ`,ャ:`ヤ`,ュ:`ユ`,ョ:`ヨ`,ヮ:`ワ`,ヵ:`カ`,ヶ:`ケ`},W=/[ぁ-ゖ]/,G=/[゠-ヿ]/,de=/[ヽヾ]/,K=/[\uFF01-\uFF07\uFF0A-\uFF5E\uFF61-\uFF9F]+/g,fe=/[\u3099\u309A]/g,pe=/(?<=[\u3041-\u3096\u30A1-\u30FA\u30FC])[\u3099\u309A]/g,q=e=>e===`゙`?`゛`:`゜`,me=/[\u0591-\u05BD\u05BF\u05C1\u05C2\u05C4\u05C5\u05C7]/g,J=/[\u0640\u064B-\u065F\u0670]/g,Y=/[\u0660-\u0669\u06F0-\u06F9\u0E50-\u0E59]/g,he=e=>String(e.codePointAt(0)&15),ge=/\u0E4D\u0E32/g,X={"؟":`?`,"،":`,`,"؛":`;`,"־":`-`},Z=/[Ͱ-Ͽἀ-῿][̀-ͯ]*/g,_e=/[̀-ͯ]/g,ve=e=>de.test(e)?e:[...e.normalize(`NFD`).replace(/゙/g,`゛`).replace(/゚/g,`゜`)].map(e=>U[e]??e).join(``),ye=e=>{let t=e.codePointAt(0);return t>=F&&t<=I?H(t):W.test(e)?ve(String.fromCodePoint(t+96)):G.test(e)?ve(e):e===`ẞ`?`SS`:X[e]?X[e]:V(e)},be=e=>[...e.toUpperCase().replace(K,e=>e.normalize(`NFKC`).replace(fe,q)).normalize(`NFC`).replace(pe,q).replace(me,``).replace(J,``).replace(Y,he).replace(ge,`ำ`).replace(Z,e=>e.normalize(`NFD`).replace(_e,``))].map(ye).join(``),Q;function*xe(e){if(Q===void 0&&(Q=typeof Intl<`u`&&typeof Intl.Segmenter==`function`?new Intl.Segmenter(void 0,{granularity:`grapheme`}):null),Q)for(let{segment:t}of Q.segment(e))yield t;else yield*e}var Se=/^\p{Default_Ignorable_Code_Point}$/u,Ce=/[^\S\uFEFF]+/g,$=(e,t)=>{m(e,`text`);let n=v(t),r=a(n),i=e=>{for(let t in r)if(Object.prototype.hasOwnProperty.call(r[t],e))return r[t][e]},o=[],s=e=>{e!==``&&(e!==n.space||o.length!==0&&o[o.length-1]!==n.space)&&o.push(e)};for(let t of xe(be(e.trim()).replace(Ce,n.separator))){let e=!1;for(let r of t){let t=r===n.separator?n.space:i(r);t===void 0?Se.test(r)||(e||s(n.invalid),e=!0):(s(t),e=!1)}}return o[o.length-1]===n.space&&o.pop(),o.join(n.separator)},we=(e,t)=>{m(e,`morse`);let n=v(t),r=o(n);return c(e,n).map(e=>r[e]??n.invalid).join(``)},Te=(e,t=!1)=>s(v(e),t),Ee=(e,t,n)=>{let r=v(t);return n!==void 0&&m(n,`morseString`),ue(n??$(e,t),r)},De={encode:$,decode:we,characters:Te,audio:Ee};e.audio=Ee,e.characters=Te,e.decode=we,e.default=De,e.encode=$});
2
+ //# sourceMappingURL=morse-code-translator.umd.js.map