@ozdemirburak/morse-code-translator 5.0.2 → 5.0.3
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/index.js +30 -26
|
@@ -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"},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/index.js
CHANGED
|
@@ -224,25 +224,14 @@ const encodeWAV = (sampleRate, samples) => {
|
|
|
224
224
|
return view;
|
|
225
225
|
};
|
|
226
226
|
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) {
|
|
227
|
+
let AudioContextClass = window.AudioContext || window.webkitAudioContext;
|
|
228
|
+
let OfflineAudioContextClass = window.OfflineAudioContext || window.webkitOfflineAudioContext;
|
|
229
|
+
if (!AudioContextClass || !OfflineAudioContextClass) {
|
|
242
230
|
throw new Error('Web Audio API is not supported in this browser');
|
|
243
231
|
}
|
|
244
|
-
|
|
245
|
-
|
|
232
|
+
const context = new AudioContextClass();
|
|
233
|
+
const [gainValues, totalTime] = getGainTimings(morse, options);
|
|
234
|
+
const offlineContext = new OfflineAudioContextClass(1, 44100 * totalTime, 44100);
|
|
246
235
|
const oscillator = offlineContext.createOscillator();
|
|
247
236
|
const gainNode = offlineContext.createGain();
|
|
248
237
|
oscillator.type = options.oscillator.type;
|
|
@@ -250,31 +239,46 @@ const audio = (morse, options) => {
|
|
|
250
239
|
gainValues.forEach(([value, time]) => gainNode.gain.setValueAtTime(value, time));
|
|
251
240
|
oscillator.connect(gainNode);
|
|
252
241
|
gainNode.connect(offlineContext.destination);
|
|
253
|
-
source
|
|
254
|
-
//
|
|
255
|
-
const render = new Promise(resolve => {
|
|
242
|
+
let source;
|
|
243
|
+
// Render the audio buffer
|
|
244
|
+
const render = new Promise((resolve, reject) => {
|
|
256
245
|
oscillator.start(0);
|
|
257
246
|
offlineContext.startRendering();
|
|
258
247
|
offlineContext.oncomplete = (e) => {
|
|
259
|
-
|
|
260
|
-
|
|
248
|
+
try {
|
|
249
|
+
source = context.createBufferSource();
|
|
250
|
+
source.buffer = e.renderedBuffer;
|
|
251
|
+
source.connect(context.destination);
|
|
252
|
+
source.onended = options.oscillator.onended;
|
|
253
|
+
resolve();
|
|
254
|
+
}
|
|
255
|
+
catch (err) {
|
|
256
|
+
reject(err);
|
|
257
|
+
}
|
|
258
|
+
};
|
|
259
|
+
offlineContext.onerror = (err) => {
|
|
260
|
+
reject(err);
|
|
261
261
|
};
|
|
262
262
|
});
|
|
263
263
|
let timeout;
|
|
264
264
|
const play = async () => {
|
|
265
265
|
await render;
|
|
266
|
+
if (context.state === 'suspended') {
|
|
267
|
+
await context.resume();
|
|
268
|
+
}
|
|
266
269
|
source.start(context.currentTime);
|
|
267
|
-
timeout = setTimeout(() => { stop(); }, totalTime * 1000);
|
|
270
|
+
timeout = window.setTimeout(() => { stop(); }, totalTime * 1000);
|
|
268
271
|
};
|
|
269
272
|
const stop = () => {
|
|
270
273
|
clearTimeout(timeout);
|
|
271
|
-
|
|
272
|
-
|
|
274
|
+
if (source) {
|
|
275
|
+
source.stop(0);
|
|
276
|
+
}
|
|
273
277
|
};
|
|
274
278
|
const getWaveBlob = async () => {
|
|
275
279
|
await render;
|
|
276
280
|
const waveData = encodeWAV(offlineContext.sampleRate, source.buffer.getChannelData(0));
|
|
277
|
-
return new Blob([waveData], {
|
|
281
|
+
return new Blob([waveData], { type: 'audio/wav' });
|
|
278
282
|
};
|
|
279
283
|
const getWaveUrl = async () => {
|
|
280
284
|
const audioBlob = await getWaveBlob();
|