@ozdemirburak/morse-code-translator 5.0.2 → 5.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/morse-code-translator.min.js +1 -1
- package/package.json +1 -1
- package/src/audio.ts +31 -37
- package/src/characters.ts +3 -2
- package/src/index.js +32 -27
|
@@ -1 +1 @@
|
|
|
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,o=
|
|
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","ㅐ":"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"}},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/package.json
CHANGED
package/src/audio.ts
CHANGED
|
@@ -94,37 +94,16 @@ const encodeWAV = (sampleRate: number, samples: Float32Array) => {
|
|
|
94
94
|
};
|
|
95
95
|
|
|
96
96
|
const audio = (morse: string, options: Options) => {
|
|
97
|
-
let AudioContext
|
|
98
|
-
|
|
99
|
-
prototype: AudioContext;
|
|
100
|
-
} = null;
|
|
101
|
-
let OfflineAudioContext: {
|
|
102
|
-
new(contextOptions: OfflineAudioContextOptions): OfflineAudioContext;
|
|
103
|
-
new(numberOfChannels: number, length: number, sampleRate: number): OfflineAudioContext;
|
|
104
|
-
prototype: OfflineAudioContext;
|
|
105
|
-
} = null;
|
|
106
|
-
let context: AudioContext = null;
|
|
107
|
-
let offlineContext: OfflineAudioContext = null;
|
|
108
|
-
let source: AudioBufferSourceNode;
|
|
109
|
-
|
|
110
|
-
const [gainValues, totalTime] = getGainTimings(morse, options);
|
|
111
|
-
|
|
112
|
-
if (AudioContext === null && typeof window !== 'undefined') {
|
|
113
|
-
AudioContext = window.AudioContext || (window as any).webkitAudioContext;
|
|
114
|
-
context = new AudioContext();
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
if (OfflineAudioContext === null && typeof window !== 'undefined') {
|
|
118
|
-
OfflineAudioContext = window.OfflineAudioContext || (window as any).webkitOfflineAudioContext;
|
|
119
|
-
offlineContext = new OfflineAudioContext(1, 44100 * totalTime, 44100);
|
|
120
|
-
}
|
|
97
|
+
let AudioContextClass = window.AudioContext || (window as any).webkitAudioContext;
|
|
98
|
+
let OfflineAudioContextClass = window.OfflineAudioContext || (window as any).webkitOfflineAudioContext;
|
|
121
99
|
|
|
122
|
-
if (!
|
|
100
|
+
if (!AudioContextClass || !OfflineAudioContextClass) {
|
|
123
101
|
throw new Error('Web Audio API is not supported in this browser');
|
|
124
102
|
}
|
|
125
103
|
|
|
126
|
-
|
|
127
|
-
|
|
104
|
+
const context = new AudioContextClass();
|
|
105
|
+
const [gainValues, totalTime] = getGainTimings(morse, options);
|
|
106
|
+
const offlineContext = new OfflineAudioContextClass(1, 44100 * totalTime, 44100);
|
|
128
107
|
|
|
129
108
|
const oscillator = offlineContext.createOscillator();
|
|
130
109
|
const gainNode = offlineContext.createGain();
|
|
@@ -136,15 +115,26 @@ const audio = (morse: string, options: Options) => {
|
|
|
136
115
|
|
|
137
116
|
oscillator.connect(gainNode);
|
|
138
117
|
gainNode.connect(offlineContext.destination);
|
|
139
|
-
source.onended = options.oscillator.onended;
|
|
140
118
|
|
|
141
|
-
|
|
142
|
-
|
|
119
|
+
let source: AudioBufferSourceNode;
|
|
120
|
+
|
|
121
|
+
// Render the audio buffer
|
|
122
|
+
const render = new Promise<void>((resolve, reject) => {
|
|
143
123
|
oscillator.start(0);
|
|
144
124
|
offlineContext.startRendering();
|
|
145
125
|
offlineContext.oncomplete = (e) => {
|
|
146
|
-
|
|
147
|
-
|
|
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);
|
|
148
138
|
};
|
|
149
139
|
});
|
|
150
140
|
|
|
@@ -152,20 +142,24 @@ const audio = (morse: string, options: Options) => {
|
|
|
152
142
|
|
|
153
143
|
const play = async () => {
|
|
154
144
|
await render;
|
|
145
|
+
if (context.state === 'suspended') {
|
|
146
|
+
await context.resume();
|
|
147
|
+
}
|
|
155
148
|
source.start(context.currentTime);
|
|
156
|
-
timeout = setTimeout(() => { stop() }, totalTime * 1000);
|
|
149
|
+
timeout = window.setTimeout(() => { stop(); }, totalTime * 1000);
|
|
157
150
|
};
|
|
158
151
|
|
|
159
152
|
const stop = () => {
|
|
160
153
|
clearTimeout(timeout);
|
|
161
|
-
|
|
162
|
-
|
|
154
|
+
if (source) {
|
|
155
|
+
source.stop(0);
|
|
156
|
+
}
|
|
163
157
|
};
|
|
164
158
|
|
|
165
159
|
const getWaveBlob = async () => {
|
|
166
160
|
await render;
|
|
167
161
|
const waveData = encodeWAV(offlineContext.sampleRate, source.buffer.getChannelData(0));
|
|
168
|
-
return new Blob([waveData], {
|
|
162
|
+
return new Blob([waveData], { type: 'audio/wav' });
|
|
169
163
|
};
|
|
170
164
|
|
|
171
165
|
const getWaveUrl = async () => {
|
|
@@ -173,7 +167,7 @@ const audio = (morse: string, options: Options) => {
|
|
|
173
167
|
return URL.createObjectURL(audioBlob);
|
|
174
168
|
};
|
|
175
169
|
|
|
176
|
-
const exportWave = async (filename) => {
|
|
170
|
+
const exportWave = async (filename: string) => {
|
|
177
171
|
const waveUrl = await getWaveUrl();
|
|
178
172
|
const anchor = document.createElement('a');
|
|
179
173
|
anchor.href = waveUrl;
|
package/src/characters.ts
CHANGED
|
@@ -73,11 +73,12 @@ const baseCharacters: Characters = {
|
|
|
73
73
|
'゛': '00', '゜': '00110', '。': '010100', 'ー': '01101', '、': '010101',
|
|
74
74
|
'(': '101101', ')': '010010'
|
|
75
75
|
},
|
|
76
|
-
'11': { // Korean Alphabet => https://
|
|
76
|
+
'11': { // Korean Alphabet => https://ko.wikipedia.org/wiki/%EB%AA%A8%EC%8A%A4_%EB%B6%80%ED%98%B8
|
|
77
77
|
'ㄱ': '0100', 'ㄴ': '0010', 'ㄷ': '1000', 'ㄹ': '0001', 'ㅁ': '11', 'ㅂ': '011',
|
|
78
78
|
'ㅅ': '110', 'ㅇ': '101', 'ㅈ': '0110', 'ㅊ': '1010', 'ㅋ': '1001', 'ㅌ': '1100',
|
|
79
79
|
'ㅍ': '111', 'ㅎ': '0111', 'ㅏ': '0', 'ㅑ': '00', 'ㅓ': '1', 'ㅕ': '000',
|
|
80
|
-
'ㅗ': '01', 'ㅛ': '10', 'ㅜ': '0000', 'ㅠ': '010', 'ㅡ': '100', 'ㅣ': '001'
|
|
80
|
+
'ㅗ': '01', 'ㅛ': '10', 'ㅜ': '0000', 'ㅠ': '010', 'ㅡ': '100', 'ㅣ': '001',
|
|
81
|
+
'ㅐ': '1101', 'ㅔ': '1011'
|
|
81
82
|
},
|
|
82
83
|
'12': { // Thai Alphabet => https://th.wikipedia.org/wiki/รหัสมอร์ส
|
|
83
84
|
'ก': '110', 'ข': '1010', 'ค': '101', 'ง': '10110', 'จ': '10010',
|
package/src/index.js
CHANGED
|
@@ -79,7 +79,8 @@ const baseCharacters = {
|
|
|
79
79
|
'ㄱ': '0100', 'ㄴ': '0010', 'ㄷ': '1000', 'ㄹ': '0001', 'ㅁ': '11', 'ㅂ': '011',
|
|
80
80
|
'ㅅ': '110', 'ㅇ': '101', 'ㅈ': '0110', 'ㅊ': '1010', 'ㅋ': '1001', 'ㅌ': '1100',
|
|
81
81
|
'ㅍ': '111', 'ㅎ': '0111', 'ㅏ': '0', 'ㅑ': '00', 'ㅓ': '1', 'ㅕ': '000',
|
|
82
|
-
'ㅗ': '01', 'ㅛ': '10', 'ㅜ': '0000', 'ㅠ': '010', 'ㅡ': '100', 'ㅣ': '001'
|
|
82
|
+
'ㅗ': '01', 'ㅛ': '10', 'ㅜ': '0000', 'ㅠ': '010', 'ㅡ': '100', 'ㅣ': '001',
|
|
83
|
+
'ㅐ': '1101', 'ㅔ': '1011'
|
|
83
84
|
},
|
|
84
85
|
'12': {
|
|
85
86
|
'ก': '110', 'ข': '1010', 'ค': '101', 'ง': '10110', 'จ': '10010',
|
|
@@ -224,25 +225,14 @@ const encodeWAV = (sampleRate, samples) => {
|
|
|
224
225
|
return view;
|
|
225
226
|
};
|
|
226
227
|
const audio = (morse, options) => {
|
|
227
|
-
let
|
|
228
|
-
let
|
|
229
|
-
|
|
230
|
-
let offlineContext = null;
|
|
231
|
-
let source;
|
|
232
|
-
const [gainValues, totalTime] = getGainTimings(morse, options);
|
|
233
|
-
if (AudioContext === null && typeof window !== 'undefined') {
|
|
234
|
-
AudioContext = window.AudioContext || window.webkitAudioContext;
|
|
235
|
-
context = new AudioContext();
|
|
236
|
-
}
|
|
237
|
-
if (OfflineAudioContext === null && typeof window !== 'undefined') {
|
|
238
|
-
OfflineAudioContext = window.OfflineAudioContext || window.webkitOfflineAudioContext;
|
|
239
|
-
offlineContext = new OfflineAudioContext(1, 44100 * totalTime, 44100);
|
|
240
|
-
}
|
|
241
|
-
if (!context || !offlineContext) {
|
|
228
|
+
let AudioContextClass = window.AudioContext || window.webkitAudioContext;
|
|
229
|
+
let OfflineAudioContextClass = window.OfflineAudioContext || window.webkitOfflineAudioContext;
|
|
230
|
+
if (!AudioContextClass || !OfflineAudioContextClass) {
|
|
242
231
|
throw new Error('Web Audio API is not supported in this browser');
|
|
243
232
|
}
|
|
244
|
-
|
|
245
|
-
|
|
233
|
+
const context = new AudioContextClass();
|
|
234
|
+
const [gainValues, totalTime] = getGainTimings(morse, options);
|
|
235
|
+
const offlineContext = new OfflineAudioContextClass(1, 44100 * totalTime, 44100);
|
|
246
236
|
const oscillator = offlineContext.createOscillator();
|
|
247
237
|
const gainNode = offlineContext.createGain();
|
|
248
238
|
oscillator.type = options.oscillator.type;
|
|
@@ -250,31 +240,46 @@ const audio = (morse, options) => {
|
|
|
250
240
|
gainValues.forEach(([value, time]) => gainNode.gain.setValueAtTime(value, time));
|
|
251
241
|
oscillator.connect(gainNode);
|
|
252
242
|
gainNode.connect(offlineContext.destination);
|
|
253
|
-
source
|
|
254
|
-
//
|
|
255
|
-
const render = new Promise(resolve => {
|
|
243
|
+
let source;
|
|
244
|
+
// Render the audio buffer
|
|
245
|
+
const render = new Promise((resolve, reject) => {
|
|
256
246
|
oscillator.start(0);
|
|
257
247
|
offlineContext.startRendering();
|
|
258
248
|
offlineContext.oncomplete = (e) => {
|
|
259
|
-
|
|
260
|
-
|
|
249
|
+
try {
|
|
250
|
+
source = context.createBufferSource();
|
|
251
|
+
source.buffer = e.renderedBuffer;
|
|
252
|
+
source.connect(context.destination);
|
|
253
|
+
source.onended = options.oscillator.onended;
|
|
254
|
+
resolve();
|
|
255
|
+
}
|
|
256
|
+
catch (err) {
|
|
257
|
+
reject(err);
|
|
258
|
+
}
|
|
259
|
+
};
|
|
260
|
+
offlineContext.onerror = (err) => {
|
|
261
|
+
reject(err);
|
|
261
262
|
};
|
|
262
263
|
});
|
|
263
264
|
let timeout;
|
|
264
265
|
const play = async () => {
|
|
265
266
|
await render;
|
|
267
|
+
if (context.state === 'suspended') {
|
|
268
|
+
await context.resume();
|
|
269
|
+
}
|
|
266
270
|
source.start(context.currentTime);
|
|
267
|
-
timeout = setTimeout(() => { stop(); }, totalTime * 1000);
|
|
271
|
+
timeout = window.setTimeout(() => { stop(); }, totalTime * 1000);
|
|
268
272
|
};
|
|
269
273
|
const stop = () => {
|
|
270
274
|
clearTimeout(timeout);
|
|
271
|
-
|
|
272
|
-
|
|
275
|
+
if (source) {
|
|
276
|
+
source.stop(0);
|
|
277
|
+
}
|
|
273
278
|
};
|
|
274
279
|
const getWaveBlob = async () => {
|
|
275
280
|
await render;
|
|
276
281
|
const waveData = encodeWAV(offlineContext.sampleRate, source.buffer.getChannelData(0));
|
|
277
|
-
return new Blob([waveData], {
|
|
282
|
+
return new Blob([waveData], { type: 'audio/wav' });
|
|
278
283
|
};
|
|
279
284
|
const getWaveUrl = async () => {
|
|
280
285
|
const audioBlob = await getWaveBlob();
|