@ozdemirburak/morse-code-translator 5.0.3 → 6.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +1 -1
- package/README.md +39 -16
- package/dist/audio.d.ts +4 -0
- package/dist/audio.d.ts.map +1 -0
- package/dist/characters.d.ts +11 -0
- package/dist/characters.d.ts.map +1 -0
- package/dist/index.d.ts +14 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/morse-code-translator.es.js +609 -0
- package/dist/morse-code-translator.es.js.map +1 -0
- package/dist/morse-code-translator.umd.js +2 -0
- package/dist/morse-code-translator.umd.js.map +1 -0
- package/dist/options.d.ts +4 -0
- package/dist/options.d.ts.map +1 -0
- package/dist/types.d.ts +52 -0
- package/dist/types.d.ts.map +1 -0
- package/package.json +32 -28
- package/dist/morse-code-translator.min.js +0 -1
- package/src/audio.ts +0 -191
- package/src/characters.ts +0 -138
- package/src/index.d.ts +0 -26
- package/src/index.js +0 -352
- package/src/index.ts +0 -58
- package/src/options.ts +0 -24
|
@@ -0,0 +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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"}
|
|
@@ -0,0 +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
|
|
@@ -0,0 +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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"}
|
|
@@ -0,0 +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"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
export interface Window {
|
|
2
|
+
webkitAudioContext: typeof AudioContext;
|
|
3
|
+
webkitOfflineAudioContext: typeof OfflineAudioContext;
|
|
4
|
+
}
|
|
5
|
+
export type Characters = {
|
|
6
|
+
[key: string]: Record<string, string>;
|
|
7
|
+
};
|
|
8
|
+
export interface Oscillator {
|
|
9
|
+
type?: OscillatorType;
|
|
10
|
+
frequency?: number;
|
|
11
|
+
onended?: ((this: AudioScheduledSourceNode, ev: Event) => any) | null;
|
|
12
|
+
}
|
|
13
|
+
export interface Options {
|
|
14
|
+
dash: string;
|
|
15
|
+
dot: string;
|
|
16
|
+
space: string;
|
|
17
|
+
separator: string;
|
|
18
|
+
invalid: string;
|
|
19
|
+
priority: number;
|
|
20
|
+
wpm?: number;
|
|
21
|
+
unit: number;
|
|
22
|
+
fwUnit: number;
|
|
23
|
+
volume: number;
|
|
24
|
+
oscillator: Oscillator;
|
|
25
|
+
events?: AudioEvents;
|
|
26
|
+
}
|
|
27
|
+
export type AudioState = 'playing' | 'paused' | 'stopped' | 'ready';
|
|
28
|
+
export interface AudioEvents {
|
|
29
|
+
onstarted?: () => void;
|
|
30
|
+
onpaused?: () => void;
|
|
31
|
+
onstopped?: () => void;
|
|
32
|
+
onended?: () => void;
|
|
33
|
+
onready?: () => void;
|
|
34
|
+
onseeked?: (time: number) => void;
|
|
35
|
+
}
|
|
36
|
+
export interface AudioResult {
|
|
37
|
+
play: () => Promise<void>;
|
|
38
|
+
pause: () => void;
|
|
39
|
+
stop: (dispose?: boolean) => void;
|
|
40
|
+
seek: (time: number) => Promise<void>;
|
|
41
|
+
dispose: () => void;
|
|
42
|
+
getCurrentTime: () => number;
|
|
43
|
+
getTotalTime: () => number;
|
|
44
|
+
getState: () => AudioState;
|
|
45
|
+
getWaveBlob: () => Promise<Blob>;
|
|
46
|
+
getWaveUrl: () => Promise<string>;
|
|
47
|
+
exportWave: (filename?: string) => Promise<void>;
|
|
48
|
+
context: AudioContext;
|
|
49
|
+
oscillator: OscillatorNode;
|
|
50
|
+
gainNode: GainNode;
|
|
51
|
+
}
|
|
52
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,MAAM;IACrB,kBAAkB,EAAE,OAAO,YAAY,CAAC;IACxC,yBAAyB,EAAE,OAAO,mBAAmB,CAAC;CACvD;AAED,MAAM,MAAM,UAAU,GAAG;IACvB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACvC,CAAC;AAEF,MAAM,WAAW,UAAU;IACzB,IAAI,CAAC,EAAE,cAAc,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB,OAAO,CAAC,EAAE,CAAC,CAAC,IAAI,EAAE,wBAAwB,EAAE,EAAE,EAAE,KAAK,KAAK,GAAG,CAAC,GAAG,IAAI,CAAC;CACvE;AAED,MAAM,WAAW,OAAO;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,UAAU,CAAC;IACvB,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB;AAED,MAAM,MAAM,UAAU,GAAG,SAAS,GAAG,QAAQ,GAAG,SAAS,GAAG,OAAO,CAAC;AAEpE,MAAM,WAAW,WAAW;IAC1B,SAAS,CAAC,EAAE,MAAM,IAAI,CAAC;IACvB,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,IAAI,CAAC;IACvB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;CACnC;AAED,MAAM,WAAW,WAAW;IAE1B,IAAI,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1B,KAAK,EAAE,MAAM,IAAI,CAAC;IAClB,IAAI,EAAE,CAAC,OAAO,CAAC,EAAE,OAAO,KAAK,IAAI,CAAC;IAClC,IAAI,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACtC,OAAO,EAAE,MAAM,IAAI,CAAC;IAGpB,cAAc,EAAE,MAAM,MAAM,CAAC;IAC7B,YAAY,EAAE,MAAM,MAAM,CAAC;IAC3B,QAAQ,EAAE,MAAM,UAAU,CAAC;IAG3B,WAAW,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IACjC,UAAU,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,CAAC;IAClC,UAAU,EAAE,CAAC,QAAQ,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAGjD,OAAO,EAAE,YAAY,CAAC;IACtB,UAAU,EAAE,cAAc,CAAC;IAC3B,QAAQ,EAAE,QAAQ,CAAC;CACpB"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ozdemirburak/morse-code-translator",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "6.0.0",
|
|
4
4
|
"description": "Morse code translator helps you convert text to Morse code and vice versa, with the option to play Morse code audio.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"morse",
|
|
@@ -9,7 +9,9 @@
|
|
|
9
9
|
"morse decoder",
|
|
10
10
|
"morse encoder",
|
|
11
11
|
"morse translator",
|
|
12
|
-
"morse code translator"
|
|
12
|
+
"morse code translator",
|
|
13
|
+
"morse code decoder",
|
|
14
|
+
"web audio"
|
|
13
15
|
],
|
|
14
16
|
"license": "MIT",
|
|
15
17
|
"homepage": "https://morsecodetranslator.com",
|
|
@@ -19,38 +21,40 @@
|
|
|
19
21
|
"url": "https://github.com/ozdemirburak/morse-code-translator.git"
|
|
20
22
|
},
|
|
21
23
|
"devDependencies": {
|
|
22
|
-
"@
|
|
23
|
-
"
|
|
24
|
-
"
|
|
25
|
-
"
|
|
26
|
-
"
|
|
27
|
-
"
|
|
28
|
-
"
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
24
|
+
"@vitest/ui": "^4.0.9",
|
|
25
|
+
"happy-dom": "^20.0.10",
|
|
26
|
+
"tslib": "^2.8.1",
|
|
27
|
+
"typescript": "^5.9.3",
|
|
28
|
+
"vite": "^7.2.2",
|
|
29
|
+
"vite-plugin-dts": "^4.5.4",
|
|
30
|
+
"vitest": "^4.0.9"
|
|
31
|
+
},
|
|
32
|
+
"type": "module",
|
|
33
|
+
"types": "./dist/index.d.ts",
|
|
34
|
+
"main": "./dist/morse-code-translator.umd.js",
|
|
35
|
+
"module": "./dist/morse-code-translator.es.js",
|
|
36
|
+
"exports": {
|
|
37
|
+
".": {
|
|
38
|
+
"types": "./dist/index.d.ts",
|
|
39
|
+
"import": "./dist/morse-code-translator.es.js",
|
|
40
|
+
"require": "./dist/morse-code-translator.umd.js"
|
|
41
|
+
}
|
|
35
42
|
},
|
|
36
|
-
"types": "./src/index.d.ts",
|
|
37
|
-
"main": "./src/index.js",
|
|
38
43
|
"files": [
|
|
39
|
-
"LICENSE",
|
|
40
|
-
"README.md",
|
|
41
|
-
"src",
|
|
42
44
|
"dist",
|
|
43
|
-
"
|
|
45
|
+
"LICENSE",
|
|
46
|
+
"README.md"
|
|
44
47
|
],
|
|
45
48
|
"scripts": {
|
|
46
|
-
"
|
|
47
|
-
"build
|
|
48
|
-
"
|
|
49
|
-
"test": "
|
|
50
|
-
"test
|
|
51
|
-
"
|
|
49
|
+
"dev": "vite",
|
|
50
|
+
"build": "tsc --noEmit && vite build",
|
|
51
|
+
"preview": "vite preview",
|
|
52
|
+
"test": "vitest run",
|
|
53
|
+
"test:watch": "vitest",
|
|
54
|
+
"test:ui": "vitest --ui",
|
|
55
|
+
"test:coverage": "vitest run --coverage"
|
|
52
56
|
},
|
|
53
57
|
"engines": {
|
|
54
|
-
"node": ">=
|
|
58
|
+
"node": ">=18.0.0"
|
|
55
59
|
}
|
|
56
60
|
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
"use strict";const e={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"},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"}},t=t=>Object.assign(Object.assign({},e),{0:e[t.priority],1:Object.assign(Object.assign({},e[1]),{[t.separator]:t.space})}),n=(e,n)=>{const o={},r=t(e);for(const t in r){o[t]={};for(const n in r[t])o[t][n]=r[t][n].replace(/0/g,e.dot).replace(/1/g,e.dash)}return n||delete o[0],o},o=(e={})=>{var t,n,o;return Object.assign(Object.assign({},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:Object.assign(Object.assign({},e.oscillator),{type:(null===(t=e.oscillator)||void 0===t?void 0:t.type)||"sine",frequency:(null===(n=e.oscillator)||void 0===n?void 0:n.frequency)||500,onended:(null===(o=e.oscillator)||void 0===o?void 0:o.onended)||null})})},r=(e,t)=>{let n=window.AudioContext||window.webkitAudioContext,o=window.OfflineAudioContext||window.webkitOfflineAudioContext;if(!n||!o)throw new Error("Web Audio API is not supported in this browser");const r=new n,[a,i]=((e,t,n=0)=>{const o=[];let{unit:r,fwUnit:a}=t,i=0;t.wpm&&(r=a=60/(50*t.wpm)),o.push([0,i]);const s=e=>{o.push([t.volume/100*1,n+i]),i+=e*r},c=e=>{o.push([0,n+i]),i+=e*r},l=e=>{o.push([0,n+i]),i+=e*a};for(let n=0,o=!1;n<=e.length;n++)e[n]===t.space?(l(7),o=!1):e[n]===t.dot?(o?c(1):o=!0,s(1)):e[n]===t.dash?(o?c(1):o=!0,s(3)):void 0!==e[n+1]&&e[n+1]!==t.space&&void 0!==e[n-1]&&e[n-1]!==t.space&&(l(3),o=!1);return[o,i]})(e,t),s=new o(1,44100*i,44100),c=s.createOscillator(),l=s.createGain();let d;c.type=t.oscillator.type,c.frequency.value=t.oscillator.frequency,a.forEach((([e,t])=>l.gain.setValueAtTime(e,t))),c.connect(l),l.connect(s.destination);const u=new Promise(((e,n)=>{c.start(0),s.startRendering(),s.oncomplete=o=>{try{d=r.createBufferSource(),d.buffer=o.renderedBuffer,d.connect(r.destination),d.onended=t.oscillator.onended,e()}catch(e){n(e)}},s.onerror=e=>{n(e)}}));let p;const f=()=>{clearTimeout(p),d&&d.stop(0)},w=async()=>{await u;const e=((e,t)=>{const n=new ArrayBuffer(44+2*t.length),o=new DataView(n),r=(e,t,n)=>{for(let o=0;o<n.length;o++)e.setUint8(t+o,n.charCodeAt(o))};return r(o,0,"RIFF"),o.setUint32(4,36+2*t.length,!0),r(o,8,"WAVE"),r(o,12,"fmt "),o.setUint32(16,16,!0),o.setUint16(20,1,!0),o.setUint16(22,1,!0),o.setUint32(24,e,!0),o.setUint32(28,4*e,!0),o.setUint16(32,2,!0),o.setUint16(34,16,!0),r(o,36,"data"),o.setUint32(40,2*t.length,!0),((e,t,n)=>{for(let o=0;o<n.length;o++,t+=2){const r=Math.max(-1,Math.min(1,n[o]));e.setInt16(t,r<0?32768*r:32767*r,!0)}})(o,44,t),o})(s.sampleRate,d.buffer.getChannelData(0));return new Blob([e],{type:"audio/wav"})},g=async()=>{const e=await w();return URL.createObjectURL(e)};return{play:async()=>{await u,"suspended"===r.state&&await r.resume(),d.start(r.currentTime),p=window.setTimeout((()=>{f()}),1e3*i)},stop:f,getWaveBlob:w,getWaveUrl:g,exportWave:async e=>{const t=await g(),n=document.createElement("a");n.href=t,n.target="_blank",n.download=e||"morse.wav",n.click()},context:r,oscillator:c,gainNode:l}};var a,i;a=globalThis,i=()=>{const e=(e,n)=>{const r=o(n),a=t(r);return[...e.replace(/\s+/g,r.separator).trim().toLocaleUpperCase()].map((function(e){for(const t in a)if(void 0!==a[t]&&void 0!==a[t][e])return a[t][e];return r.invalid})).join(r.separator).replace(/0/g,r.dot).replace(/1/g,r.dash)};return{characters:(e,t)=>n(o(e),t),decode:(e,t)=>{const r=o(t),a=(e=>{const t={},o=n(e,!0);for(const e in o)for(const n in o[e])void 0===t[o[e][n]]&&(t[o[e][n]]=n);return t})(r);return e.replace(/\s+/g,r.separator).trim().split(r.separator).map((function(e){return void 0!==a[e]?a[e]:r.invalid})).join("")},encode:e,audio:(t,n,a)=>{const i=a||e(t,n),s=o(n);return r(i,s)}}},"object"==typeof exports?module.exports=i():"function"==typeof define&&define.amd?define(i):void 0!==a&&(a["morse-code-translator"]=i());
|
package/src/audio.ts
DELETED
|
@@ -1,191 +0,0 @@
|
|
|
1
|
-
const getGainTimings = (morse: string, opts: Options, currentTime = 0): [[[number, number]?], number] => {
|
|
2
|
-
const timings: [[number, number]?] = [];
|
|
3
|
-
let {unit, fwUnit} = opts;
|
|
4
|
-
let time = 0;
|
|
5
|
-
|
|
6
|
-
if (opts.wpm) {
|
|
7
|
-
// wpm mode uses standardised units
|
|
8
|
-
unit = fwUnit = 60 / (opts.wpm * 50)
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
timings.push([0, time]);
|
|
12
|
-
|
|
13
|
-
const tone = (i: number) => {
|
|
14
|
-
timings.push([1 * (opts.volume / 100.0), currentTime + time]);
|
|
15
|
-
time += i * unit;
|
|
16
|
-
};
|
|
17
|
-
|
|
18
|
-
const silence = (i: number) => {
|
|
19
|
-
timings.push([0, currentTime + time]);
|
|
20
|
-
time += i * unit;
|
|
21
|
-
};
|
|
22
|
-
|
|
23
|
-
const gap = (i: number) => {
|
|
24
|
-
timings.push([0, currentTime + time]);
|
|
25
|
-
time += i * fwUnit;
|
|
26
|
-
};
|
|
27
|
-
|
|
28
|
-
for (let i = 0, addSilence = false; i <= morse.length; i++) {
|
|
29
|
-
if (morse[i] === opts.space) {
|
|
30
|
-
gap(7);
|
|
31
|
-
addSilence = false;
|
|
32
|
-
} else if (morse[i] === opts.dot) {
|
|
33
|
-
if (addSilence) silence(1); else addSilence = true;
|
|
34
|
-
tone(1);
|
|
35
|
-
} else if (morse[i] === opts.dash) {
|
|
36
|
-
if (addSilence) silence(1); else addSilence = true;
|
|
37
|
-
tone(3);
|
|
38
|
-
} else if (
|
|
39
|
-
(typeof morse[i + 1] !== 'undefined' && morse[i + 1] !== opts.space) &&
|
|
40
|
-
(typeof morse[i - 1] !== 'undefined' && morse[i - 1] !== opts.space)
|
|
41
|
-
) {
|
|
42
|
-
gap(3);
|
|
43
|
-
addSilence = false;
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
return [timings, time];
|
|
48
|
-
};
|
|
49
|
-
|
|
50
|
-
// Source: https://github.com/mattdiamond/Recorderjs/blob/master/src/recorder.js#L155
|
|
51
|
-
const encodeWAV = (sampleRate: number, samples: Float32Array) => {
|
|
52
|
-
const buffer = new ArrayBuffer(44 + samples.length * 2);
|
|
53
|
-
const view = new DataView(buffer);
|
|
54
|
-
const writeString = (view: DataView, offset: number, string: string) => {
|
|
55
|
-
for (let i = 0; i < string.length; i++) {
|
|
56
|
-
view.setUint8(offset + i, string.charCodeAt(i));
|
|
57
|
-
}
|
|
58
|
-
};
|
|
59
|
-
// RIFF identifier
|
|
60
|
-
writeString(view, 0, 'RIFF');
|
|
61
|
-
// RIFF chunk length
|
|
62
|
-
view.setUint32(4, 36 + samples.length * 2, true);
|
|
63
|
-
// RIFF type
|
|
64
|
-
writeString(view, 8, 'WAVE');
|
|
65
|
-
// format chunk identifier
|
|
66
|
-
writeString(view, 12, 'fmt ');
|
|
67
|
-
// format chunk length
|
|
68
|
-
view.setUint32(16, 16, true);
|
|
69
|
-
// sample format (raw)
|
|
70
|
-
view.setUint16(20, 1, true);
|
|
71
|
-
// channel count
|
|
72
|
-
view.setUint16(22, 1, true);
|
|
73
|
-
// sample rate
|
|
74
|
-
view.setUint32(24, sampleRate, true);
|
|
75
|
-
// byte rate (sample rate * block align)
|
|
76
|
-
view.setUint32(28, sampleRate * 4, true);
|
|
77
|
-
// block align (channel count * bytes per sample)
|
|
78
|
-
view.setUint16(32, 2, true);
|
|
79
|
-
// bits per sample
|
|
80
|
-
view.setUint16(34, 16, true);
|
|
81
|
-
// data chunk identifier
|
|
82
|
-
writeString(view, 36, 'data');
|
|
83
|
-
// data chunk length
|
|
84
|
-
view.setUint32(40, samples.length * 2, true);
|
|
85
|
-
// to PCM
|
|
86
|
-
const floatTo16BitPCM = (output: DataView, offset: number, input: Float32Array) => {
|
|
87
|
-
for (let i = 0; i < input.length; i++, offset += 2) {
|
|
88
|
-
const s = Math.max(-1, Math.min(1, input[i]));
|
|
89
|
-
output.setInt16(offset, s < 0 ? s * 0x8000 : s * 0x7FFF, true);
|
|
90
|
-
}
|
|
91
|
-
};
|
|
92
|
-
floatTo16BitPCM(view, 44, samples);
|
|
93
|
-
return view;
|
|
94
|
-
};
|
|
95
|
-
|
|
96
|
-
const audio = (morse: string, options: Options) => {
|
|
97
|
-
let AudioContextClass = window.AudioContext || (window as any).webkitAudioContext;
|
|
98
|
-
let OfflineAudioContextClass = window.OfflineAudioContext || (window as any).webkitOfflineAudioContext;
|
|
99
|
-
|
|
100
|
-
if (!AudioContextClass || !OfflineAudioContextClass) {
|
|
101
|
-
throw new Error('Web Audio API is not supported in this browser');
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
const context = new AudioContextClass();
|
|
105
|
-
const [gainValues, totalTime] = getGainTimings(morse, options);
|
|
106
|
-
const offlineContext = new OfflineAudioContextClass(1, 44100 * totalTime, 44100);
|
|
107
|
-
|
|
108
|
-
const oscillator = offlineContext.createOscillator();
|
|
109
|
-
const gainNode = offlineContext.createGain();
|
|
110
|
-
|
|
111
|
-
oscillator.type = options.oscillator.type as OscillatorType;
|
|
112
|
-
oscillator.frequency.value = options.oscillator.frequency;
|
|
113
|
-
|
|
114
|
-
gainValues.forEach(([value, time]) => gainNode.gain.setValueAtTime(value, time));
|
|
115
|
-
|
|
116
|
-
oscillator.connect(gainNode);
|
|
117
|
-
gainNode.connect(offlineContext.destination);
|
|
118
|
-
|
|
119
|
-
let source: AudioBufferSourceNode;
|
|
120
|
-
|
|
121
|
-
// Render the audio buffer
|
|
122
|
-
const render = new Promise<void>((resolve, reject) => {
|
|
123
|
-
oscillator.start(0);
|
|
124
|
-
offlineContext.startRendering();
|
|
125
|
-
offlineContext.oncomplete = (e) => {
|
|
126
|
-
try {
|
|
127
|
-
source = context.createBufferSource();
|
|
128
|
-
source.buffer = e.renderedBuffer;
|
|
129
|
-
source.connect(context.destination);
|
|
130
|
-
source.onended = options.oscillator.onended;
|
|
131
|
-
resolve();
|
|
132
|
-
} catch (err) {
|
|
133
|
-
reject(err);
|
|
134
|
-
}
|
|
135
|
-
};
|
|
136
|
-
offlineContext.onerror = (err) => {
|
|
137
|
-
reject(err);
|
|
138
|
-
};
|
|
139
|
-
});
|
|
140
|
-
|
|
141
|
-
let timeout: number;
|
|
142
|
-
|
|
143
|
-
const play = async () => {
|
|
144
|
-
await render;
|
|
145
|
-
if (context.state === 'suspended') {
|
|
146
|
-
await context.resume();
|
|
147
|
-
}
|
|
148
|
-
source.start(context.currentTime);
|
|
149
|
-
timeout = window.setTimeout(() => { stop(); }, totalTime * 1000);
|
|
150
|
-
};
|
|
151
|
-
|
|
152
|
-
const stop = () => {
|
|
153
|
-
clearTimeout(timeout);
|
|
154
|
-
if (source) {
|
|
155
|
-
source.stop(0);
|
|
156
|
-
}
|
|
157
|
-
};
|
|
158
|
-
|
|
159
|
-
const getWaveBlob = async () => {
|
|
160
|
-
await render;
|
|
161
|
-
const waveData = encodeWAV(offlineContext.sampleRate, source.buffer.getChannelData(0));
|
|
162
|
-
return new Blob([waveData], { type: 'audio/wav' });
|
|
163
|
-
};
|
|
164
|
-
|
|
165
|
-
const getWaveUrl = async () => {
|
|
166
|
-
const audioBlob = await getWaveBlob();
|
|
167
|
-
return URL.createObjectURL(audioBlob);
|
|
168
|
-
};
|
|
169
|
-
|
|
170
|
-
const exportWave = async (filename: string) => {
|
|
171
|
-
const waveUrl = await getWaveUrl();
|
|
172
|
-
const anchor = document.createElement('a');
|
|
173
|
-
anchor.href = waveUrl;
|
|
174
|
-
anchor.target = '_blank';
|
|
175
|
-
anchor.download = filename || 'morse.wav';
|
|
176
|
-
anchor.click();
|
|
177
|
-
};
|
|
178
|
-
|
|
179
|
-
return {
|
|
180
|
-
play,
|
|
181
|
-
stop,
|
|
182
|
-
getWaveBlob,
|
|
183
|
-
getWaveUrl,
|
|
184
|
-
exportWave,
|
|
185
|
-
context,
|
|
186
|
-
oscillator,
|
|
187
|
-
gainNode
|
|
188
|
-
};
|
|
189
|
-
};
|
|
190
|
-
|
|
191
|
-
export default audio;
|