This repository has been archived by the owner on Oct 17, 2021. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 15
/
jquery.morse.js
186 lines (157 loc) · 6.52 KB
/
jquery.morse.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
/*
* Morse.js
* A jQuery Plugin that annotates text with Morse Code
* http://github.com/mattt/Morse.js
*
* Copyright (c) 2010-2012 Mattt Thompson
* Licensed under the MIT licenses.
*/
(function($){
Morse = {
wpm: 12,
code: {
"a": "._", "b": "_...", "c": "_._.", "d": "_..",
"e": ".", "f": ".._.", "g": "__.", "h": "....",
"i": "..", "j": ".___", "k": "_._", "l": "._..",
"m": "__", "n": "_.", "o": "___", "p": ".__.",
"q": "__._", "r": "._.", "s": "...", "t": "_",
"u": ".._", "v": "..._", "w": ".__", "x": "_.._",
"y": "_.__", "z": "__..", " ": " ",
"1": ".____", "2": "..___", "3": "...__", "4": "...._", "5": ".....",
"6": "_....", "7": "__...", "8": "___..", "9": "____.", "0": "_____",
/*
* Note: Some operators prefer "!" as "___." and others as "_._.__"
* ARRL message format has most punctuation spelled out, as many symbols'
* encodings conflict with procedural signals (e.g. "=" and "BT").
*/
".": "._._._", ",": "__..__", "?": "..__..", "'": ".____.",
"/": "_.._.", "(": "_.__.", ")": "_.__._", "&": "._...",
":": "___...", ";": "_._._.", "=": "_..._", "+": "._._.",
"-": "_...._", "_": "..__._", "\"": "._.._.", "$": "..._.._",
"!": "_._.__", "@": ".__._."
},
annotate: function(el) {
var $el = $(el);
var tokens = $el.text().split(/\s+/);
$el.text('');
for (i in tokens) {
var token = tokens[i];
var letters = token.split('');
var symbols = [];
for (j in letters) {
var letter = letters[j];
var symbol = Morse.code[letter.toLowerCase()];
if (symbol) {
symbols.push(symbol);
}
}
$el.append('<ruby class="morse-code"><rb>' + token + '</rb><rt>' + symbols.join(' ') + ' ' + '</rt></ruby>');
}
$el.each(function() {
if ($("#morse-code-output")[0] === undefined) {
var audio = $('<audio id="morse-code-output"></audio>').bind("morse.mute", function(){this.pause();})
$(this).after(audio);
}
$(this).bind('morse.emit', Morse.emit).bind('click', function(){ $(this).trigger("morse.emit")});
});
},
emit: function() {
var symbols = [];
$("#morse-code-output").trigger("morse.mute").attr('src', "");
$(this).find("rt").each(function() {
symbols.push($(this).text());
});
// Javascript WAV generation based on code by sk89q (http://sk89q.therisenrealm.com/)
var generate = function(symbols, options) {
var defaults = {
channels: 1,
sampleRate: 1012,
bitDepth: 16,
unit: 0.100,
frequency: 440.0,
volume: 32767
};
var options = $.extend(defaults, options);
var channels = options.channels;
var sampleRate = options.sampleRate;
var bitsPerSample = options.bitDepth;
var unit = options.unit;
var frequency = options.frequency;
var volume = options.volume;
var data = [];
var samples = 0;
var tone = function(length) {
for (var i = 0; i < sampleRate * unit * length; i++) {
for (var c = 0; c < channels; c++) {
var v = volume * Math.sin((2 * Math.PI) * (i / sampleRate) * frequency);
data.push(pack("v", v)); samples++;
}
}
}
var silence = function(length) {
for (var i = 0; i < sampleRate * unit * length; i++) {
for (var c = 0; c < channels; c++) {
data.push(pack("v", 0)); samples++;
}
}
}
for (var i in symbols) {
var length;
var symbol = symbols[i];
if (symbol == '|') {
silence(7);
} else {
if (symbol == '.') {
tone(1);
silence(1);
} else if (symbol == '_') {
tone(3);
silence(1);
} else {
silence(3);
}
}
}
data = data.join('');
// Format sub-chunk
var chunk1 = [
"fmt ", // Sub-chunk identifier
pack("V", 16), // Chunk length
pack("v", 1), // Audio format (1 is linear quantization)
pack("v", channels),
pack("V", sampleRate),
pack("V", sampleRate * channels * bitsPerSample / 8), // Byte rate
pack("v", channels * bitsPerSample / 8),
pack("v", bitsPerSample)
].join('');
// Data sub-chunk (contains the sound)
var chunk2 = [
"data", // Sub-chunk identifier
pack("V", samples * channels * bitsPerSample / 8), // Chunk length
data
].join('');
// Header
var header = [
"RIFF",
pack("V", 4 + (8 + chunk1.length) + (8 + chunk2.length)), // Length
"WAVE"
].join('');
return "data:audio/wav;base64," + escape(btoa([header, chunk1, chunk2].join('')));
};
// Base 64 encoding function, for browsers that do not support btoa()
// by Tyler Akins (http://rumkin.com), available in the public domain
var btoa=function(b){var c="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",h="",a,d,e,j,i,f,g=0;do{a=b.charCodeAt(g++);d=b.charCodeAt(g++);e=b.charCodeAt(g++);j=a>>2;a=(a&3)<<4|d>>4;i=(d&15)<<2|e>>6;f=e&63;if(isNaN(d))i=f=64;else if(isNaN(e))f=64;h=h+c.charAt(j)+c.charAt(a)+c.charAt(i)+c.charAt(f)}while(g<b.length);return h};
// pack() emulation (from the PHP version), for binary crunching
var pack = function(e){for(var b="",c=1,d=0;d<e.length;d++){var f=e.charAt(d),a=arguments[c];c++;switch(f){case "a":b+=a[0]+"\u0000";break;case "A":b+=a[0]+" ";break;case "C":case "c":b+=String.fromCharCode(a);break;case "n":b+=String.fromCharCode(a>>8&255,a&255);break;case "v":b+=String.fromCharCode(a&255,a>>8&255);break;case "N":b+=String.fromCharCode(a>>24&255,a>>16&255,a>>8&255,a&255);break;case "V":b+=String.fromCharCode(a&255,a>>8&255,a>>16&255,a>>24&255);break;case "x":c--;b+="\u0000";break;default:throw new Error("Unknown pack format character '"+
f+"'");}}return b};
$("#morse-code-output").attr('src', generate(symbols.join('|'), {unit: 1.200 / Morse.wpm}))[0].play();
},
};
$.fn.extend({
morseCode: function() {
return this.each(function(){
(new Morse.annotate(this));
});
}
});
})(jQuery);