@ozdemirburak/morse-code-translator 6.0.0 → 7.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":[],"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', 'Þ': '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(/[01]/g, (c) => (c === '0' ? options.dot : options.dash));\n }\n }\n }\n if (!usePriority) {\n delete mapped['0'];\n }\n return mapped;\n};\n\nconst swapCharacters = (options: Options) => {\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 const mappedCharacters = getMappedCharacters(options, true);\n for (const set in mappedCharacters) {\n for (const key in mappedCharacters[set]) {\n const code = mappedCharacters[set][key];\n if (typeof swapped[code] === 'undefined') {\n swapped[code] = key;\n }\n }\n }\n // The word-gap symbol must always decode to a literal space, independent of a\n // custom separator (otherwise the gap decodes back to the separator string).\n // Only override the (incorrect) separator-derived mapping, never a real\n // character that legitimately owns this code.\n if (typeof swapped[options.space] === 'undefined' || swapped[options.space] === options.separator) {\n swapped[options.space] = ' ';\n }\n return swapped;\n};\n\nexport {\n baseCharacters,\n getCharacters,\n getMappedCharacters,\n swapCharacters\n};\n","import type { Options } from './types.js';\nimport { baseCharacters } from './characters.js';\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\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 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 audio renderer splits on the space/separator before tokenizing dot/dash,\n // so a dot/dash that contains either 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)) {\n throw new Error(`morse-code-translator: \"${name}\" must not contain the \"space\" or \"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 // 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 (o.invalid !== '' && 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 // '0'/'1' are the internal code sentinels; symbols that pass through the\n // code-substitution step must not contain them.\n for (const [name, value] of [['space', o.space], ['invalid', o.invalid]] as const) {\n if (/[01]/.test(value)) {\n throw new Error(`morse-code-translator: \"${name}\" must not contain the reserved characters \"0\" or \"1\".`);\n }\n }\n};\n\nconst getOptions = (opts: Partial<Options> = {}): Options => {\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 frequency = isPositiveNumber(opts.oscillator?.frequency) ? (opts.oscillator as { frequency: number }).frequency : 500;\n // volume is 0-100; 0 is a legitimate value (mute), only non-finite/missing fall back.\n const volume = typeof opts.volume === 'number' && Number.isFinite(opts.volume) ? opts.volume : 100;\n // priority must be an integer in [1, 12]; out-of-range silently selects the\n // wrong/empty alphabet otherwise.\n const priority = Number.isInteger(opts.priority) && (opts.priority as number) >= 1 && (opts.priority as number) <= 12 ? (opts.priority as number) : 1;\n // oscillator.type must be a valid OscillatorType, or it throws in real browsers.\n const requestedType = opts.oscillator?.type;\n const oscillatorType: OscillatorType =\n requestedType === 'sine' || requestedType === 'square' || requestedType === 'sawtooth' || requestedType === 'triangle'\n ? requestedType\n : 'sine';\n\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 ?? '#', // '' 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 ...opts.oscillator,\n type: oscillatorType, // sine, square, sawtooth, triangle\n frequency, // value in hertz\n onended: opts.oscillator?.onended || null // event that fires when the tone has stopped playing\n },\n // Clone events so internal mutation (backwards-compat onended) never leaks\n // back into the caller-supplied object.\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';\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\n// Upper bound on rendered audio length, so a degenerate (huge / non-finite)\n// unit/wpm cannot produce an Infinite totalTime, buffer, or playback timer.\nconst MAX_TOTAL_SECONDS = 3600;\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 // Try the longer symbol first so a shorter dot/dash that is a prefix of the\n // other (e.g. dot '..' vs dash '...') cannot greedily mis-tokenize it.\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 // Split into words by the word-gap symbol, then characters by the separator,\n // then consume whole dot/dash symbols. Matching whole symbols (rather than\n // single code points) supports multi-character dot/dash/space symbols. Empty\n // words are dropped so leading/trailing/doubled word separators do not emit\n // phantom word gaps.\n const words = morse\n .split(opts.space)\n .map((word) => word.split(opts.separator).filter((character) => character !== ''))\n .filter((characters) => characters.length > 0);\n words.forEach((characters, wordIndex) => {\n if (wordIndex > 0) {\n gap(WORD_GAP);\n }\n characters.forEach((character, characterIndex) => {\n if (characterIndex > 0) {\n gap(INTER_CHARACTER_GAP);\n }\n let position = 0;\n let needsSilence = false;\n while (position < character.length) {\n const matched = symbolOrder.find(([symbol]) => symbol && character.startsWith(symbol, position));\n if (matched) {\n if (needsSilence) silence(INTRA_CHARACTER_GAP);\n tone(matched[1]);\n needsSilence = true;\n position += matched[0].length;\n } else {\n // Skip any unexpected symbol (e.g. the invalid-character marker).\n position += 1;\n }\n }\n });\n });\n\n // Clamp so a degenerate unit/wpm cannot yield a non-finite or absurd duration.\n return [timings, Math.min(time, MAX_TOTAL_SECONDS)];\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 [gainValues, totalTime] = getGainTimings(morse, options);\n // OfflineAudioContext requires a length of at least one sample frame, so an\n // empty/silent morse string still yields a valid tiny buffer. The upper bound\n // is already enforced by getGainTimings clamping totalTime to MAX_TOTAL_SECONDS.\n const bufferLength = Math.max(1, 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 // 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 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 // True while a play() is in its async startup (between the synchronous entry\n // and the moment it actually starts or bails). Lets stop()/seek() know a\n // playback intent is in flight.\n let pendingPlay = false;\n // Incremented by play()/stop()/seek()/dispose(); lets an in-flight play()\n // detect it was superseded during an await and bail instead of resurrecting.\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 // 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 // If the instance was disposed before rendering finished, do not populate\n // the buffer or signal readiness — keeps post-dispose export deterministic\n // (getWaveBlob throws) instead of timing-dependent. Still resolve so any\n // awaiters do not hang. Otherwise: do NOT reset state to 'ready' (the\n // caller may have already stopped/started during rendering).\n if (state !== 'disposed') {\n renderedBuffer = e.renderedBuffer;\n events.onready?.();\n }\n resolve();\n } catch (err) {\n reject(err);\n }\n };\n offlineContext.addEventListener('error', (err) => {\n reject(err);\n });\n });\n\n const clearAutoStop = () => {\n if (timeout !== null) {\n clearTimeout(timeout);\n timeout = null;\n }\n };\n\n const stopSource = () => {\n if (source) {\n try {\n source.stop(0);\n } catch (e) {\n // Ignore if already stopped\n }\n source = null;\n }\n };\n\n // Helper: Create a new audio source\n const createSource = (): AudioBufferSourceNode => {\n const ctx = getContext();\n const newSource = ctx.createBufferSource();\n newSource.buffer = renderedBuffer;\n newSource.connect(ctx.destination);\n return newSource;\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); stop()/seek()/\n // dispose() also bump the epoch to supersede an in-flight play.\n const myEpoch = ++epoch;\n pendingPlay = true;\n const superseded = (): boolean => epoch !== myEpoch || getState() === 'disposed';\n try {\n await render;\n\n // Bail if superseded during the render await. Checked BEFORE touching the\n // context so a disposed/stopped instance never lazily creates one.\n if (superseded()) {\n return;\n }\n\n const ctx = getContext();\n // Resume audio context if suspended\n if (ctx.state === 'suspended') {\n await ctx.resume();\n }\n\n // Re-check after the resume await for the same reason.\n if (superseded()) {\n return;\n }\n\n // Create new source if needed (source is null whenever not actively playing)\n if (!source) {\n source = createSource();\n }\n\n // Start playback from pausedAt position\n source.start(ctx.currentTime, pausedAt);\n startTime = ctx.currentTime - pausedAt;\n state = 'playing';\n events.onstarted?.();\n\n // Set up auto-stop when playback completes naturally. pause()/stop()/seek()\n // all clear this timer, so when it fires playback genuinely reached the end.\n clearAutoStop();\n const remainingTime = (totalTime - pausedAt) * 1000;\n timeout = window.setTimeout(() => {\n if (state === 'playing') {\n clearAutoStop();\n stopSource();\n state = 'stopped';\n pausedAt = 0;\n startTime = 0;\n events.onended?.();\n }\n }, remainingTime);\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 clearAutoStop();\n pausedAt = Math.min(getContext().currentTime - startTime, totalTime);\n stopSource();\n state = 'paused';\n 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 clearAutoStop();\n stopSource();\n state = 'paused';\n events.onpaused?.();\n }\n };\n\n const stop = (dispose = false) => {\n if (state === 'disposed') {\n return;\n }\n\n epoch++;\n clearAutoStop();\n stopSource();\n\n // Active = currently playing OR a play()/seek-resume is in flight; in both\n // cases the playback the listener believes is happening is being stopped.\n const wasActive = state === 'playing' || pendingPlay;\n pendingPlay = false;\n state = 'stopped';\n pausedAt = 0;\n startTime = 0;\n\n if (wasActive) {\n events.onstopped?.();\n }\n\n if (dispose) {\n renderedBuffer = null;\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 // Neutralize only NaN (Math.min/Math.max do not); ±Infinity still clamps to\n // the [0, totalTime] range as expected.\n const safeTime = Number.isNaN(time) ? 0 : time;\n const clampedTime = Math.max(0, Math.min(safeTime, totalTime));\n\n epoch++;\n // Stop current playback\n clearAutoStop();\n stopSource();\n\n pausedAt = clampedTime;\n events.onseeked?.(clampedTime);\n\n if (wasActive) {\n state = 'paused'; // transient; play() sets it back to 'playing'\n await play();\n }\n };\n\n const dispose = () => {\n stop(true);\n state = 'disposed';\n if (context && context.state !== 'closed') {\n context.close();\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 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 // 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\n // Audio nodes (for advanced users)\n oscillator,\n gainNode,\n } as AudioResult;\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;\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\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.\n// Scoped to the katakana block so precomposed Latin/other scripts that rely on\n// NFC keys (e.g. Ã, Á) are left untouched.\nconst KATAKANA = /[゠-ヿ]/;\nconst KATAKANA_ITERATION = /[ヽヾ]/; // U+30FD/U+30FE: decompose to a non-letter base, leave them alone\nconst normalizeKatakana = (text: string): string =>\n // NFC first so canonically-equivalent decomposed input (e.g. NFD Latin 'A'+◌́)\n // recomposes to its precomposed key ('Á') before lookup.\n [...text.normalize('NFC')]\n .map((character) =>\n KATAKANA.test(character) && !KATAKANA_ITERATION.test(character)\n ? // Decompose the katakana char and map its combining voiced/semi-voiced\n // mark to the standalone mark used as a map key. Scoped to katakana so a\n // stray combining mark on a non-Japanese base stays invalid. (NFC above\n // recomposes already-decomposed NFD katakana input first.)\n character.normalize('NFD').replace(/゙/g, '゛').replace(/゚/g, '゜')\n : character\n )\n .join('');\n\nexport const encode = (text: string, opts?: Partial<Options>): string => {\n const options = getOptions(opts);\n const characters = getCharacters(options);\n // toUpperCase (not toLocaleUpperCase) keeps casing deterministic regardless of\n // the host locale (e.g. avoids the Turkish i -> İ mapping).\n // trim BEFORE substituting whitespace so boundary whitespace cannot turn into\n // a (non-whitespace) separator that then emits phantom leading/trailing gaps.\n let codes = [...normalizeKatakana(text.trim().replace(/\\s+/g, options.separator).toUpperCase())]\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 // Substitute the internal 0/1 sentinels per code in a single pass (before\n // joining) so dot/dash symbols that themselves contain '0'/'1' are not\n // re-scanned, and so the separator is never subjected to substitution.\n .map((code) => code.replace(/[01]/g, (c) => (c === '0' ? options.dot : options.dash)))\n // Drop empty tokens so unknown characters in drop-unknown mode (invalid: '')\n // do not leave phantom/leading/trailing separators in the output.\n .filter((code) => code !== '');\n\n // In drop-unknown mode a dropped character can leave an orphaned word-gap\n // symbol at an edge or doubled-up; remove word gaps not flanked by real codes.\n if (options.invalid === '') {\n codes = codes.filter(\n (code, i) =>\n code !== options.space ||\n (codes[i - 1] !== undefined &&\n codes[i - 1] !== options.space &&\n codes[i + 1] !== undefined &&\n codes[i + 1] !== options.space)\n );\n }\n\n return codes.join(options.separator);\n};\n\nexport const decode = (morse: string, opts?: Partial<Options>): string => {\n const options = getOptions(opts);\n const swapped = swapCharacters(options);\n const normalized = morse.trim().replace(/\\s+/g, options.separator);\n if (normalized === '') {\n return '';\n }\n return normalized\n .split(options.separator)\n .map((characters) =>\n // hasOwnProperty guards against inherited Object.prototype members\n // (e.g. a \"constructor\" token) leaking into the decoded output.\n Object.prototype.hasOwnProperty.call(swapped, characters) ? swapped[characters] : 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 options = getOptions(opts);\n const morse = morseString || encode(text, 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"],"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`},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`}},n=e=>({...t,0:t[e.priority],1:{...t[1],[e.separator]:e.space}}),r=(e,t)=>{let r={},i=n(e);for(let t in i){r[t]={};let n=i[t];if(n)for(let i in n)r[t][i]=n[i].replace(/[01]/g,t=>t===`0`?e.dot:e.dash)}return t||delete r[0],r},i=e=>{let t=Object.create(null),n=r(e,!0);for(let e in n)for(let r in n[e]){let i=n[e][r];t[i]===void 0&&(t[i]=r)}return(t[e.space]===void 0||t[e.space]===e.separator)&&(t[e.space]=` `),t},a=e=>typeof e==`number`&&Number.isFinite(e)&&e>0,o=e=>Object.values(t).some(t=>Object.prototype.hasOwnProperty.call(t,e)),s=(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},c=e=>{if(e.dot===e.dash)throw Error(`morse-code-translator: "dot" and "dash" symbols must be different.`);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(s(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))throw Error(`morse-code-translator: "${t}" must not contain the "space" or "separator" symbol.`);if(o(e.separator))throw Error(`morse-code-translator: "separator" must not be an encodable character.`);if(e.invalid!==``&&s(e.invalid,e.dot,e.dash))throw Error(`morse-code-translator: "invalid" must not be composed solely of "dot"/"dash" symbols.`);for(let[t,n]of[[`space`,e.space],[`invalid`,e.invalid]])if(/[01]/.test(n))throw Error(`morse-code-translator: "${t}" must not contain the reserved characters "0" or "1".`)},l=(e={})=>{let t=a(e.unit)?e.unit:.08,n=a(e.fwUnit)?e.fwUnit:t,r=a(e.wpm)?e.wpm:void 0,i=a(e.oscillator?.frequency)?e.oscillator.frequency:500,o=typeof e.volume==`number`&&Number.isFinite(e.volume)?e.volume:100,s=Number.isInteger(e.priority)&&e.priority>=1&&e.priority<=12?e.priority:1,l=e.oscillator?.type,u=l===`sine`||l===`square`||l===`sawtooth`||l===`triangle`?l:`sine`,d={...e,dash:e.dash||`-`,dot:e.dot||`.`,space:e.space||`/`,separator:e.separator||` `,invalid:e.invalid??`#`,priority:s,wpm:r,unit:t,fwUnit:n,volume:o,oscillator:{...e.oscillator,type:u,frequency:i,onended:e.oscillator?.onended||null},events:e.events?{...e.events}:e.events};return c(d),d},u=44100,d=1,f=16,p=1,m=3,h=1,g=3,_=7,v=50,y=3600,b=(e,t,n=0)=>{let r=[],{unit:i,fwUnit:a}=t,o=0;t.wpm&&(i=a=60/(t.wpm*v)),r.push([0,o]);let s=(e,t,s=!0)=>{r.push([e,n+o]),o+=t*(s?i:a)},c=e=>s(t.volume/100,e),l=e=>s(0,e),u=e=>s(0,e,!1),d=t.dot.length>=t.dash.length?[[t.dot,p],[t.dash,m]]:[[t.dash,m],[t.dot,p]];return e.split(t.space).map(e=>e.split(t.separator).filter(e=>e!==``)).filter(e=>e.length>0).forEach((e,t)=>{t>0&&u(_),e.forEach((e,t)=>{t>0&&u(g);let n=0,r=!1;for(;n<e.length;){let t=d.find(([t])=>t&&e.startsWith(t,n));t?(r&&l(h),c(t[1]),r=!0,n+=t[0].length):n+=1}})}),[r,Math.min(o,y)]},x=(e,t)=>{let n=f/8,r=d*n,i=e*r,a=t.length*n,o=44+a,s=new ArrayBuffer(o),c=new DataView(s),l=(e,t)=>{for(let n=0;n<t.length;n++)c.setUint8(e+n,t.charCodeAt(n))};return l(0,`RIFF`),c.setUint32(4,o-8,!0),l(8,`WAVE`),l(12,`fmt `),c.setUint32(16,16,!0),c.setUint16(20,1,!0),c.setUint16(22,d,!0),c.setUint32(24,e,!0),c.setUint32(28,i,!0),c.setUint16(32,r,!0),c.setUint16(34,f,!0),l(36,`data`),c.setUint32(40,a,!0),((e,t)=>{for(let r=0;r<t.length;r++,e+=n){let n=Math.max(-1,Math.min(1,t[r])),i=n<0?n*32768:n*32767;c.setInt16(e,i,!0)}})(44,t),c},S=(e,t)=>{let n=window.AudioContext||window.webkitAudioContext,r=window.OfflineAudioContext||window.webkitOfflineAudioContext;if(!n||!r)throw Error(`Web Audio API is not supported in this browser. Please use a modern browser with Web Audio API support.`);let[i,a]=b(e,t),o=new r(d,Math.max(1,Math.ceil(u*a)),u),s=o.createOscillator(),c=o.createGain();s.type=t.oscillator.type,s.frequency.value=t.oscillator.frequency??500,i.forEach(([e,t])=>{c.gain.setValueAtTime(e,t)}),s.connect(c),c.connect(o.destination);let l=null,f=null,p=null,m=`ready`,h=0,g=0,_=null,v=!1,y=0,S=()=>(!l&&m!==`disposed`&&(l=new n),l),C=t.events||{};t.oscillator.onended&&!C.onended&&(C.onended=t.oscillator.onended);let w=new Promise((e,t)=>{s.start(0),o.startRendering(),o.oncomplete=n=>{try{m!==`disposed`&&(p=n.renderedBuffer,C.onready?.()),e()}catch(e){t(e)}},o.addEventListener(`error`,e=>{t(e)})}),T=()=>{_!==null&&(clearTimeout(_),_=null)},E=()=>{if(f){try{f.stop(0)}catch{}f=null}},D=()=>{let e=S(),t=e.createBufferSource();return t.buffer=p,t.connect(e.destination),t},O=async()=>{if(m===`playing`||m===`disposed`)return;let e=++y;v=!0;let t=()=>y!==e||F()===`disposed`;try{if(await w,t())return;let e=S();if(e.state===`suspended`&&await e.resume(),t())return;f||=D(),f.start(e.currentTime,h),g=e.currentTime-h,m=`playing`,C.onstarted?.(),T();let n=(a-h)*1e3;_=window.setTimeout(()=>{m===`playing`&&(T(),E(),m=`stopped`,h=0,g=0,C.onended?.())},n)}finally{y===e&&(v=!1)}},k=()=>{if(m!==`disposed`){if(m===`playing`){T(),h=Math.min(S().currentTime-g,a),E(),m=`paused`,C.onpaused?.();return}v&&(y++,v=!1,T(),E(),m=`paused`,C.onpaused?.())}},A=(e=!1)=>{if(m===`disposed`)return;y++,T(),E();let t=m===`playing`||v;v=!1,m=`stopped`,h=0,g=0,t&&C.onstopped?.(),e&&(p=null)},j=async e=>{if(m===`disposed`)return;let t=m===`playing`||v,n=Math.max(0,Math.min(Number.isNaN(e)?0:e,a));y++,T(),E(),h=n,C.onseeked?.(n),t&&(m=`paused`,await O())},M=()=>{A(!0),m=`disposed`,l&&l.state!==`closed`&&l.close()},N=()=>m===`playing`?Math.min(S().currentTime-g,a):h,P=()=>a,F=()=>m,I=async()=>{if(await w,!p)throw Error(`Audio buffer not available`);let e=x(o.sampleRate,p.getChannelData(0)),t=new Uint8Array(e.byteLength);for(let n=0;n<e.byteLength;n++)t[n]=e.getUint8(n);return new Blob([t],{type:`audio/wav`})},L=async()=>{let e=await I();return URL.createObjectURL(e)},R={play:O,pause:k,stop:A,seek:j,dispose:M,getCurrentTime:N,getTotalTime:P,getState:F,getWaveBlob:I,getWaveUrl:L,exportWave:async(e=`morse.wav`)=>{let t=await L(),n=document.createElement(`a`);n.href=t,n.target=`_blank`,n.download=e,n.click(),setTimeout(()=>URL.revokeObjectURL(t),1e3)},oscillator:s,gainNode:c};return Object.defineProperty(R,"context",{get:S,enumerable:!1,configurable:!0}),R},C=/[゠-ヿ]/,w=/[ヽヾ]/,T=e=>[...e.normalize(`NFC`)].map(e=>C.test(e)&&!w.test(e)?e.normalize(`NFD`).replace(/゙/g,`゛`).replace(/゚/g,`゜`):e).join(``),E=(e,t)=>{let r=l(t),i=n(r),a=[...T(e.trim().replace(/\s+/g,r.separator).toUpperCase())].map(e=>{for(let t in i){let n=i[t];if(n&&n[e])return n[e]}return r.invalid}).map(e=>e.replace(/[01]/g,e=>e===`0`?r.dot:r.dash)).filter(e=>e!==``);return r.invalid===``&&(a=a.filter((e,t)=>e!==r.space||a[t-1]!==void 0&&a[t-1]!==r.space&&a[t+1]!==void 0&&a[t+1]!==r.space)),a.join(r.separator)},D=(e,t)=>{let n=l(t),r=i(n),a=e.trim().replace(/\s+/g,n.separator);return a===``?``:a.split(n.separator).map(e=>Object.prototype.hasOwnProperty.call(r,e)?r[e]:n.invalid).join(``)},O=(e,t=!1)=>r(l(e),t),k=(e,t,n)=>{let r=l(t);return S(n||E(e,t),r)},A={encode:E,decode:D,characters:O,audio:k};e.audio=k,e.characters=O,e.decode=D,e.default=A,e.encode=E});
2
+ //# sourceMappingURL=morse-code-translator.umd.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"morse-code-translator.umd.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.umd.js","names":[],"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', 'Þ': '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(/[01]/g, (c) => (c === '0' ? options.dot : options.dash));\n }\n }\n }\n if (!usePriority) {\n delete mapped['0'];\n }\n return mapped;\n};\n\nconst swapCharacters = (options: Options) => {\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 const mappedCharacters = getMappedCharacters(options, true);\n for (const set in mappedCharacters) {\n for (const key in mappedCharacters[set]) {\n const code = mappedCharacters[set][key];\n if (typeof swapped[code] === 'undefined') {\n swapped[code] = key;\n }\n }\n }\n // The word-gap symbol must always decode to a literal space, independent of a\n // custom separator (otherwise the gap decodes back to the separator string).\n // Only override the (incorrect) separator-derived mapping, never a real\n // character that legitimately owns this code.\n if (typeof swapped[options.space] === 'undefined' || swapped[options.space] === options.separator) {\n swapped[options.space] = ' ';\n }\n return swapped;\n};\n\nexport {\n baseCharacters,\n getCharacters,\n getMappedCharacters,\n swapCharacters\n};\n","import type { Options } from './types.js';\nimport { baseCharacters } from './characters.js';\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\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 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 audio renderer splits on the space/separator before tokenizing dot/dash,\n // so a dot/dash that contains either 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)) {\n throw new Error(`morse-code-translator: \"${name}\" must not contain the \"space\" or \"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 // 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 (o.invalid !== '' && 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 // '0'/'1' are the internal code sentinels; symbols that pass through the\n // code-substitution step must not contain them.\n for (const [name, value] of [['space', o.space], ['invalid', o.invalid]] as const) {\n if (/[01]/.test(value)) {\n throw new Error(`morse-code-translator: \"${name}\" must not contain the reserved characters \"0\" or \"1\".`);\n }\n }\n};\n\nconst getOptions = (opts: Partial<Options> = {}): Options => {\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 frequency = isPositiveNumber(opts.oscillator?.frequency) ? (opts.oscillator as { frequency: number }).frequency : 500;\n // volume is 0-100; 0 is a legitimate value (mute), only non-finite/missing fall back.\n const volume = typeof opts.volume === 'number' && Number.isFinite(opts.volume) ? opts.volume : 100;\n // priority must be an integer in [1, 12]; out-of-range silently selects the\n // wrong/empty alphabet otherwise.\n const priority = Number.isInteger(opts.priority) && (opts.priority as number) >= 1 && (opts.priority as number) <= 12 ? (opts.priority as number) : 1;\n // oscillator.type must be a valid OscillatorType, or it throws in real browsers.\n const requestedType = opts.oscillator?.type;\n const oscillatorType: OscillatorType =\n requestedType === 'sine' || requestedType === 'square' || requestedType === 'sawtooth' || requestedType === 'triangle'\n ? requestedType\n : 'sine';\n\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 ?? '#', // '' 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 ...opts.oscillator,\n type: oscillatorType, // sine, square, sawtooth, triangle\n frequency, // value in hertz\n onended: opts.oscillator?.onended || null // event that fires when the tone has stopped playing\n },\n // Clone events so internal mutation (backwards-compat onended) never leaks\n // back into the caller-supplied object.\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';\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\n// Upper bound on rendered audio length, so a degenerate (huge / non-finite)\n// unit/wpm cannot produce an Infinite totalTime, buffer, or playback timer.\nconst MAX_TOTAL_SECONDS = 3600;\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 // Try the longer symbol first so a shorter dot/dash that is a prefix of the\n // other (e.g. dot '..' vs dash '...') cannot greedily mis-tokenize it.\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 // Split into words by the word-gap symbol, then characters by the separator,\n // then consume whole dot/dash symbols. Matching whole symbols (rather than\n // single code points) supports multi-character dot/dash/space symbols. Empty\n // words are dropped so leading/trailing/doubled word separators do not emit\n // phantom word gaps.\n const words = morse\n .split(opts.space)\n .map((word) => word.split(opts.separator).filter((character) => character !== ''))\n .filter((characters) => characters.length > 0);\n words.forEach((characters, wordIndex) => {\n if (wordIndex > 0) {\n gap(WORD_GAP);\n }\n characters.forEach((character, characterIndex) => {\n if (characterIndex > 0) {\n gap(INTER_CHARACTER_GAP);\n }\n let position = 0;\n let needsSilence = false;\n while (position < character.length) {\n const matched = symbolOrder.find(([symbol]) => symbol && character.startsWith(symbol, position));\n if (matched) {\n if (needsSilence) silence(INTRA_CHARACTER_GAP);\n tone(matched[1]);\n needsSilence = true;\n position += matched[0].length;\n } else {\n // Skip any unexpected symbol (e.g. the invalid-character marker).\n position += 1;\n }\n }\n });\n });\n\n // Clamp so a degenerate unit/wpm cannot yield a non-finite or absurd duration.\n return [timings, Math.min(time, MAX_TOTAL_SECONDS)];\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 [gainValues, totalTime] = getGainTimings(morse, options);\n // OfflineAudioContext requires a length of at least one sample frame, so an\n // empty/silent morse string still yields a valid tiny buffer. The upper bound\n // is already enforced by getGainTimings clamping totalTime to MAX_TOTAL_SECONDS.\n const bufferLength = Math.max(1, 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 // 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 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 // True while a play() is in its async startup (between the synchronous entry\n // and the moment it actually starts or bails). Lets stop()/seek() know a\n // playback intent is in flight.\n let pendingPlay = false;\n // Incremented by play()/stop()/seek()/dispose(); lets an in-flight play()\n // detect it was superseded during an await and bail instead of resurrecting.\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 // 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 // If the instance was disposed before rendering finished, do not populate\n // the buffer or signal readiness — keeps post-dispose export deterministic\n // (getWaveBlob throws) instead of timing-dependent. Still resolve so any\n // awaiters do not hang. Otherwise: do NOT reset state to 'ready' (the\n // caller may have already stopped/started during rendering).\n if (state !== 'disposed') {\n renderedBuffer = e.renderedBuffer;\n events.onready?.();\n }\n resolve();\n } catch (err) {\n reject(err);\n }\n };\n offlineContext.addEventListener('error', (err) => {\n reject(err);\n });\n });\n\n const clearAutoStop = () => {\n if (timeout !== null) {\n clearTimeout(timeout);\n timeout = null;\n }\n };\n\n const stopSource = () => {\n if (source) {\n try {\n source.stop(0);\n } catch (e) {\n // Ignore if already stopped\n }\n source = null;\n }\n };\n\n // Helper: Create a new audio source\n const createSource = (): AudioBufferSourceNode => {\n const ctx = getContext();\n const newSource = ctx.createBufferSource();\n newSource.buffer = renderedBuffer;\n newSource.connect(ctx.destination);\n return newSource;\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); stop()/seek()/\n // dispose() also bump the epoch to supersede an in-flight play.\n const myEpoch = ++epoch;\n pendingPlay = true;\n const superseded = (): boolean => epoch !== myEpoch || getState() === 'disposed';\n try {\n await render;\n\n // Bail if superseded during the render await. Checked BEFORE touching the\n // context so a disposed/stopped instance never lazily creates one.\n if (superseded()) {\n return;\n }\n\n const ctx = getContext();\n // Resume audio context if suspended\n if (ctx.state === 'suspended') {\n await ctx.resume();\n }\n\n // Re-check after the resume await for the same reason.\n if (superseded()) {\n return;\n }\n\n // Create new source if needed (source is null whenever not actively playing)\n if (!source) {\n source = createSource();\n }\n\n // Start playback from pausedAt position\n source.start(ctx.currentTime, pausedAt);\n startTime = ctx.currentTime - pausedAt;\n state = 'playing';\n events.onstarted?.();\n\n // Set up auto-stop when playback completes naturally. pause()/stop()/seek()\n // all clear this timer, so when it fires playback genuinely reached the end.\n clearAutoStop();\n const remainingTime = (totalTime - pausedAt) * 1000;\n timeout = window.setTimeout(() => {\n if (state === 'playing') {\n clearAutoStop();\n stopSource();\n state = 'stopped';\n pausedAt = 0;\n startTime = 0;\n events.onended?.();\n }\n }, remainingTime);\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 clearAutoStop();\n pausedAt = Math.min(getContext().currentTime - startTime, totalTime);\n stopSource();\n state = 'paused';\n 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 clearAutoStop();\n stopSource();\n state = 'paused';\n events.onpaused?.();\n }\n };\n\n const stop = (dispose = false) => {\n if (state === 'disposed') {\n return;\n }\n\n epoch++;\n clearAutoStop();\n stopSource();\n\n // Active = currently playing OR a play()/seek-resume is in flight; in both\n // cases the playback the listener believes is happening is being stopped.\n const wasActive = state === 'playing' || pendingPlay;\n pendingPlay = false;\n state = 'stopped';\n pausedAt = 0;\n startTime = 0;\n\n if (wasActive) {\n events.onstopped?.();\n }\n\n if (dispose) {\n renderedBuffer = null;\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 // Neutralize only NaN (Math.min/Math.max do not); ±Infinity still clamps to\n // the [0, totalTime] range as expected.\n const safeTime = Number.isNaN(time) ? 0 : time;\n const clampedTime = Math.max(0, Math.min(safeTime, totalTime));\n\n epoch++;\n // Stop current playback\n clearAutoStop();\n stopSource();\n\n pausedAt = clampedTime;\n events.onseeked?.(clampedTime);\n\n if (wasActive) {\n state = 'paused'; // transient; play() sets it back to 'playing'\n await play();\n }\n };\n\n const dispose = () => {\n stop(true);\n state = 'disposed';\n if (context && context.state !== 'closed') {\n context.close();\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 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 // 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\n // Audio nodes (for advanced users)\n oscillator,\n gainNode,\n } as AudioResult;\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;\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\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.\n// Scoped to the katakana block so precomposed Latin/other scripts that rely on\n// NFC keys (e.g. Ã, Á) are left untouched.\nconst KATAKANA = /[゠-ヿ]/;\nconst KATAKANA_ITERATION = /[ヽヾ]/; // U+30FD/U+30FE: decompose to a non-letter base, leave them alone\nconst normalizeKatakana = (text: string): string =>\n // NFC first so canonically-equivalent decomposed input (e.g. NFD Latin 'A'+◌́)\n // recomposes to its precomposed key ('Á') before lookup.\n [...text.normalize('NFC')]\n .map((character) =>\n KATAKANA.test(character) && !KATAKANA_ITERATION.test(character)\n ? // Decompose the katakana char and map its combining voiced/semi-voiced\n // mark to the standalone mark used as a map key. Scoped to katakana so a\n // stray combining mark on a non-Japanese base stays invalid. (NFC above\n // recomposes already-decomposed NFD katakana input first.)\n character.normalize('NFD').replace(/゙/g, '゛').replace(/゚/g, '゜')\n : character\n )\n .join('');\n\nexport const encode = (text: string, opts?: Partial<Options>): string => {\n const options = getOptions(opts);\n const characters = getCharacters(options);\n // toUpperCase (not toLocaleUpperCase) keeps casing deterministic regardless of\n // the host locale (e.g. avoids the Turkish i -> İ mapping).\n // trim BEFORE substituting whitespace so boundary whitespace cannot turn into\n // a (non-whitespace) separator that then emits phantom leading/trailing gaps.\n let codes = [...normalizeKatakana(text.trim().replace(/\\s+/g, options.separator).toUpperCase())]\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 // Substitute the internal 0/1 sentinels per code in a single pass (before\n // joining) so dot/dash symbols that themselves contain '0'/'1' are not\n // re-scanned, and so the separator is never subjected to substitution.\n .map((code) => code.replace(/[01]/g, (c) => (c === '0' ? options.dot : options.dash)))\n // Drop empty tokens so unknown characters in drop-unknown mode (invalid: '')\n // do not leave phantom/leading/trailing separators in the output.\n .filter((code) => code !== '');\n\n // In drop-unknown mode a dropped character can leave an orphaned word-gap\n // symbol at an edge or doubled-up; remove word gaps not flanked by real codes.\n if (options.invalid === '') {\n codes = codes.filter(\n (code, i) =>\n code !== options.space ||\n (codes[i - 1] !== undefined &&\n codes[i - 1] !== options.space &&\n codes[i + 1] !== undefined &&\n codes[i + 1] !== options.space)\n );\n }\n\n return codes.join(options.separator);\n};\n\nexport const decode = (morse: string, opts?: Partial<Options>): string => {\n const options = getOptions(opts);\n const swapped = swapCharacters(options);\n const normalized = morse.trim().replace(/\\s+/g, options.separator);\n if (normalized === '') {\n return '';\n }\n return normalized\n .split(options.separator)\n .map((characters) =>\n // hasOwnProperty guards against inherited Object.prototype members\n // (e.g. a \"constructor\" token) leaking into the decoded output.\n Object.prototype.hasOwnProperty.call(swapped, characters) ? swapped[characters] : 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 options = getOptions(opts);\n const morse = morseString || encode(text, 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"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"options.d.ts","sourceRoot":"","sources":["../src/options.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAE1C,QAAA,MAAM,UAAU,GAAI,OAAM,OAAO,CAAC,OAAO,CAAM,KAAG,OAqBjD,CAAC;AAEF,eAAe,UAAU,CAAC"}
1
+ {"version":3,"file":"options.d.ts","sourceRoot":"","sources":["../src/options.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AA6E1C,QAAA,MAAM,UAAU,GAAI,OAAM,OAAO,CAAC,OAAO,CAAM,KAAG,OA6CjD,CAAC;AAEF,eAAe,UAAU,CAAC"}
package/dist/types.d.ts CHANGED
@@ -8,6 +8,7 @@ export type Characters = {
8
8
  export interface Oscillator {
9
9
  type?: OscillatorType;
10
10
  frequency?: number;
11
+ /** @deprecated Use audio.events.onended instead */
11
12
  onended?: ((this: AudioScheduledSourceNode, ev: Event) => any) | null;
12
13
  }
13
14
  export interface Options {
@@ -24,7 +25,7 @@ export interface Options {
24
25
  oscillator: Oscillator;
25
26
  events?: AudioEvents;
26
27
  }
27
- export type AudioState = 'playing' | 'paused' | 'stopped' | 'ready';
28
+ export type AudioState = 'playing' | 'paused' | 'stopped' | 'ready' | 'disposed';
28
29
  export interface AudioEvents {
29
30
  onstarted?: () => void;
30
31
  onpaused?: () => void;
@@ -45,7 +46,7 @@ export interface AudioResult {
45
46
  getWaveBlob: () => Promise<Blob>;
46
47
  getWaveUrl: () => Promise<string>;
47
48
  exportWave: (filename?: string) => Promise<void>;
48
- context: AudioContext;
49
+ context: AudioContext | null;
49
50
  oscillator: OscillatorNode;
50
51
  gainNode: GainNode;
51
52
  }