@ozdemirburak/morse-code-translator
Version:
Morse code translator helps you convert text to Morse code and vice versa, with the option to play Morse code audio.
610 lines (609 loc) • 14.3 kB
JavaScript
const b = {
1: {
// Latin => https://en.wikipedia.org/wiki/Morse_code
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: {
// Numbers
0: "11111",
1: "01111",
2: "00111",
3: "00011",
4: "00001",
5: "00000",
6: "10000",
7: "11000",
8: "11100",
9: "11110"
},
3: {
// Punctuation
".": "010101",
",": "110011",
"?": "001100",
"'": "011110",
"!": "101011",
"/": "10010",
"(": "10110",
")": "101101",
"&": "01000",
":": "111000",
";": "101010",
"=": "10001",
"+": "01010",
"-": "100001",
_: "001101",
'"': "010010",
$: "0001001",
"@": "011010",
"¿": "00101",
"¡": "110001"
},
4: {
// Latin Extended => https://ham.stackexchange.com/questions/1379/international-characters-in-morse-code
Ã: "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: {
// Cyrillic Alphabet => https://en.wikipedia.org/wiki/Russian_Morse_code
А: "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: {
// Greek Alphabet => https://en.wikipedia.org/wiki/Morse_code_for_non-Latin_alphabets
Α: "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: {
// Hebrew Alphabet => https://en.wikipedia.org/wiki/Morse_code_for_non-Latin_alphabets
א: "01",
ב: "1000",
ג: "110",
ד: "100",
ה: "111",
ו: "0",
ז: "1100",
ח: "0000",
ט: "001",
י: "00",
כ: "101",
ל: "0100",
מ: "11",
נ: "10",
ס: "1010",
ע: "0111",
פ: "0110",
צ: "011",
ק: "1101",
ר: "010",
ש: "000",
ת: "1"
},
8: {
// Arabic Alphabet => https://en.wikipedia.org/wiki/Morse_code_for_non-Latin_alphabets
ا: "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: {
// Persian Alphabet => https://en.wikipedia.org/wiki/Morse_code_for_non-Latin_alphabets
ا: "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: {
// 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
ア: "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: {
// Korean Alphabet => https://ko.wikipedia.org/wiki/%EB%AA%A8%EC%8A%A4_%EB%B6%80%ED%98%B8
ㄱ: "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: {
// Thai Alphabet => https://th.wikipedia.org/wiki/รหัสมอร์ส
ก: "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"
}
}, L = (e) => ({
...b,
0: b[e.priority],
1: {
...b[1],
[e.separator]: e.space
}
}), W = (e, t) => {
const n = {}, s = L(e);
for (const r in s) {
n[r] = {};
const w = s[r];
if (w)
for (const c in w)
n[r][c] = w[c].replace(/0/g, e.dot).replace(/1/g, e.dash);
}
return t || delete n[0], n;
}, q = (e) => {
const t = {}, n = W(e, !0);
for (const s in n)
for (const r in n[s])
typeof t[n[s][r]] > "u" && (t[n[s][r]] = r);
return t;
}, C = (e = {}) => ({
...e,
dash: e.dash || "-",
dot: e.dot || ".",
space: e.space || "/",
separator: e.separator || " ",
invalid: e.invalid || "#",
priority: e.priority || 1,
wpm: e.wpm,
// words per minute - PARIS method used in favour of unit/fwUnit options
unit: e.unit || 0.08,
// period of one unit, in seconds, 1.2 / c where c is speed of transmission, in words per minute
fwUnit: e.fwUnit || e.unit || 0.08,
// Farnsworth unit to control intercharacter and interword gaps
volume: e.volume || 100,
oscillator: {
...e.oscillator,
type: e.oscillator?.type || "sine",
// sine, square, sawtooth, triangle
frequency: e.oscillator?.frequency || 500,
// value in hertz
onended: e.oscillator?.onended || null
// event that fires when the tone has stopped playing
}
}), I = 44100, U = 1, M = 16, F = 1, j = 3, O = 1, z = 3, $ = 7, J = 50, K = (e, t, n = 0) => {
const s = [];
let { unit: r, fwUnit: w } = t, c = 0;
t.wpm && (r = w = 60 / (t.wpm * J)), s.push([0, c]);
const T = (o, u, a = !0) => {
s.push([o, n + c]), c += u * (a ? r : w);
}, i = (o) => T(t.volume / 100, o), m = (o) => T(0, o), y = (o) => T(0, o, !1);
for (let o = 0, u = !1; o <= e.length; o++) {
const a = e[o], f = e[o + 1], h = e[o - 1];
a === t.space ? (y($), u = !1) : a === t.dot ? (u && m(O), i(F), u = !0) : a === t.dash ? (u && m(O), i(j), u = !0) : f !== void 0 && f !== t.space && h !== void 0 && h !== t.space && (y(z), u = !1);
}
return [s, c];
}, Q = (e, t) => {
const n = M / 8, s = U * n, r = e * s, w = t.length * n, c = 44 + w, T = new ArrayBuffer(c), i = new DataView(T), m = (o, u) => {
for (let a = 0; a < u.length; a++)
i.setUint8(o + a, u.charCodeAt(a));
}, y = (o, u) => {
for (let a = 0; a < u.length; a++, o += n) {
const f = Math.max(-1, Math.min(1, u[a])), h = f < 0 ? f * 32768 : f * 32767;
i.setInt16(o, h, !0);
}
};
return m(0, "RIFF"), i.setUint32(4, c - 8, !0), m(8, "WAVE"), m(12, "fmt "), i.setUint32(16, 16, !0), i.setUint16(20, 1, !0), i.setUint16(22, U, !0), i.setUint32(24, e, !0), i.setUint32(28, r, !0), i.setUint16(32, s, !0), i.setUint16(34, M, !0), m(36, "data"), i.setUint32(40, w, !0), y(44, t), i;
}, X = (e, t) => {
const n = window.AudioContext || window.webkitAudioContext, s = window.OfflineAudioContext || window.webkitOfflineAudioContext;
if (!n || !s)
throw new Error("Web Audio API is not supported in this browser. Please use a modern browser with Web Audio API support.");
const r = new n(), [w, c] = K(e, t), T = Math.ceil(I * c), i = new s(U, T, I), m = i.createOscillator(), y = i.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(i.destination);
let o = null, u = null, a = "ready", f = 0, h = 0, g = null;
const A = t.events || {};
t.oscillator.onended && !A.onended && (A.onended = t.oscillator.onended);
const R = new Promise((l, p) => {
m.start(0), i.startRendering(), i.oncomplete = (d) => {
try {
u = d.renderedBuffer, a = "ready", A.onready?.(), l();
} catch (_) {
p(_);
}
}, i.addEventListener("error", (d) => {
p(d);
});
}), D = () => {
const l = r.createBufferSource();
return l.buffer = u, l.connect(r.destination), l.onended = () => {
const p = P();
a === "playing" && p >= c - 0.01 && (a = "stopped", f = 0, A.onended?.());
}, l;
}, S = async () => {
if (await R, r.state === "suspended" && await r.resume(), a === "playing")
return;
(!o || o.buffer === null) && (o = D()), o.start(r.currentTime, f), h = r.currentTime - f, a = "playing", A.onstarted?.();
const l = (c - f) * 1e3;
g = window.setTimeout(() => {
a === "playing" && v();
}, l);
}, k = () => {
a === "playing" && (g !== null && (clearTimeout(g), g = null), f = Math.min(r.currentTime - h, c), o && (o.stop(0), o = null), a = "paused", A.onpaused?.());
}, v = (l = !1) => {
if (g !== null && (clearTimeout(g), g = null), o) {
try {
o.stop(0);
} catch {
}
o = null;
}
const p = a === "playing";
a = "stopped", f = 0, h = 0, p && A.onstopped?.(), l && (u = null);
}, N = async (l) => {
const p = a === "playing", d = Math.max(0, Math.min(l, c));
if (o) {
g !== null && (clearTimeout(g), g = null);
try {
o.stop(0);
} catch {
}
o = null;
}
f = d, A.onseeked?.(d), p && (a = "paused", await S());
}, V = () => {
v(!0), r.state !== "closed" && r.close();
}, P = () => a === "playing" ? Math.min(r.currentTime - h, c) : f, G = () => c, H = () => a, E = async () => {
if (await R, !u)
throw new Error("Audio buffer not available");
const l = Q(i.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" });
}, x = async () => {
const l = await E();
return URL.createObjectURL(l);
};
return {
// Playback control
play: S,
pause: k,
stop: v,
seek: N,
dispose: V,
// Playback information
getCurrentTime: P,
getTotalTime: G,
getState: H,
// Export functionality
getWaveBlob: E,
getWaveUrl: x,
exportWave: async (l = "morse.wav") => {
const p = await x(), d = document.createElement("a");
d.href = p, d.target = "_blank", d.download = l, d.click();
},
// Context access (for advanced users)
context: r,
oscillator: m,
gainNode: y
};
}, B = (e, t) => {
const n = C(t), s = L(n);
return [...e.replace(/\s+/g, n.separator).trim().toLocaleUpperCase()].map((r) => {
for (const w in s) {
const c = s[w];
if (c && c[r])
return c[r];
}
return n.invalid;
}).join(n.separator).replace(/0/g, n.dot).replace(/1/g, n.dash);
}, Y = (e, t) => {
const n = C(t), s = q(n);
return e.replace(/\s+/g, n.separator).trim().split(n.separator).map((r) => typeof s[r] < "u" ? s[r] : n.invalid).join("");
}, Z = (e, t = !1) => W(C(e), t), e0 = (e, t, n) => {
const s = n || B(e, t), r = C(t);
return X(s, r);
}, n0 = {
encode: B,
decode: Y,
characters: Z,
audio: e0
};
export {
e0 as audio,
Z as characters,
Y as decode,
n0 as default,
B as encode
};
//# sourceMappingURL=morse-code-translator.es.js.map