mirror of https://github.com/nealey/vail.git
Add files via upload
This commit is contained in:
parent
65dd203ab4
commit
82a505344c
|
@ -0,0 +1,116 @@
|
|||
const morseToAlphabet = new Map([
|
||||
["12", "A"],
|
||||
["2111", "B"],
|
||||
["2121", "C"],
|
||||
["211", "D"],
|
||||
["1", "E"],
|
||||
["1121", "F"],
|
||||
["221", "G"],
|
||||
["1111", "H"],
|
||||
["11", "I"],
|
||||
["1222", "J"],
|
||||
["212", "K"],
|
||||
["1211", "L"],
|
||||
["22", "M"],
|
||||
["21", "N"],
|
||||
["222", "O"],
|
||||
["1221", "P"],
|
||||
["2212", "Q"],
|
||||
["121", "R"],
|
||||
["111", "S"],
|
||||
["2", "T"],
|
||||
["112", "U"],
|
||||
["1112", "V"],
|
||||
["122", "W"],
|
||||
["2112", "X"],
|
||||
["2122", "Y"],
|
||||
["2211", "Z"],
|
||||
["12222", "1"],
|
||||
["11222", "2"],
|
||||
["11122", "3"],
|
||||
["11112", "4"],
|
||||
["11111", "5"],
|
||||
["21111", "6"],
|
||||
["22111", "7"],
|
||||
["22211", "8"],
|
||||
["22221", "9"],
|
||||
["22222", "0"],
|
||||
]);
|
||||
|
||||
class Decoder {
|
||||
constructor() {
|
||||
this.lastLetter = '';
|
||||
this.decodeArray = '';
|
||||
this.unit = 80; // adjustment: short dit reduces, long dah lengthens
|
||||
this.keyStartTime = null;
|
||||
this.keyEndTime = null;
|
||||
this.spaceTimer = null;
|
||||
this.farnsworth = 3;
|
||||
}
|
||||
|
||||
keyOn() {
|
||||
clearTimeout(this.spaceTimer);
|
||||
this.keyStartTime = Date.now();
|
||||
//var pauseDuration = (this.keyEndTime) ? this.keyStartTime - this.keyEndTime : 0;
|
||||
//if (pauseDuration > this.unit + (this.unit/10)) { // end sequence and decode letter
|
||||
//this.registerLetter();
|
||||
//}
|
||||
}
|
||||
|
||||
keyOff() {
|
||||
this.keyEndTime = Date.now();
|
||||
var keyDuration = (this.keyStartTime) ? this.keyEndTime - this.keyStartTime : 0;
|
||||
if (keyDuration < this.unit) {
|
||||
// reduce unit based on short dit
|
||||
this.unit = (keyDuration + this.unit) / 2;
|
||||
this.registerDit();
|
||||
} else if (keyDuration > this.unit * 3) {
|
||||
// lengthen unit based on long dah
|
||||
this.unit = ((keyDuration / 3) + this.unit) / 2;
|
||||
this.registerDah();
|
||||
} else {
|
||||
var ditAndDahThreshold = (this.unit * 2);
|
||||
if (keyDuration >= ditAndDahThreshold) {
|
||||
this.registerDah();
|
||||
} else {
|
||||
this.registerDit();
|
||||
}
|
||||
}
|
||||
let spaceTime = this.unit * this.farnsworth;
|
||||
this.spaceTimer = setTimeout(() => { // end sequence and decode letter
|
||||
this.updateLastLetter(this.morseToLetter(this.decodeArray));
|
||||
this.decodeArray = '';
|
||||
}, spaceTime, "keyOff");
|
||||
}
|
||||
|
||||
registerDit() {
|
||||
this.decodeArray += '1';
|
||||
}
|
||||
|
||||
registerDah() {
|
||||
this.decodeArray += '2';
|
||||
}
|
||||
|
||||
updateLastLetter(letter) {
|
||||
updateCurrentLetter(letter);
|
||||
this.lastLetter = letter;
|
||||
//console.log(this.lastLetter);
|
||||
}
|
||||
|
||||
morseToLetter(sequence) {
|
||||
var letter = morseToAlphabet.get(sequence);
|
||||
if (letter) {
|
||||
return letter;
|
||||
} else {
|
||||
return '*';
|
||||
}
|
||||
}
|
||||
|
||||
calculateWpm() {
|
||||
return 60000 / (this.unit * 50);
|
||||
}
|
||||
|
||||
setFarnsworth(farnsworth) {
|
||||
this.farnsworth = farnsworth;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,254 @@
|
|||
class Keyer {
|
||||
constructor(sndr, decoder) {
|
||||
this.sndr = sndr; // Sounder instance
|
||||
this.decoder = decoder; // Decoder instance
|
||||
// Using [ and ] for dits and dahs respectively for compatibility with the vband usb interface
|
||||
this.ditKey1 = 'ControlLeft';
|
||||
this.dahKey1 = 'ControlRight';
|
||||
this.ditKey2 = 'BracketLeft';
|
||||
this.dahKey2 = 'BracketRight';
|
||||
this.wpm = 20;
|
||||
this.unit = 60; // length of dit in milliseconds; 60 is 20wpm
|
||||
this.mode = 2; // 1: straight key, 2: iambicA, 3: iambicB, 4: ultimatic
|
||||
this.tone = 550;
|
||||
this.queue = [];
|
||||
this.ditKeyState = 0;
|
||||
this.dahKeyState = 0;
|
||||
this.lastKey = null;
|
||||
this.ditStreak = 0;
|
||||
this.dahStreak = 0;
|
||||
this.streak = 0;
|
||||
this.ditStart = null;
|
||||
this.ditStop = null;
|
||||
this.dahStart = null;
|
||||
this.dahStop = null;
|
||||
this.sending = false;
|
||||
this.lastSendTimestamp = null;
|
||||
this.oscillatorTimer = setInterval(() => {
|
||||
this.oscillate();
|
||||
}, 0);
|
||||
}
|
||||
|
||||
setWpm(wpm){
|
||||
this.wpm = wpm;
|
||||
this.unit = 60000 / (wpm * 50) // based on the PARIS method 60 seconds / 50 elements per word * WPM
|
||||
this.decoder.unit = this.unit;
|
||||
}
|
||||
|
||||
setMode(mode){
|
||||
this.mode = mode;
|
||||
}
|
||||
|
||||
setTone(tone){
|
||||
this.tone = tone;
|
||||
}
|
||||
|
||||
sendSignal() {
|
||||
this.sending = true;
|
||||
//console.log('startSignal');
|
||||
if (restartAudioNeeded()) {
|
||||
restartAudio();
|
||||
}
|
||||
this.sndr.setTone(this.tone);
|
||||
this.sndr.on();
|
||||
this.decoder.keyOn();
|
||||
}
|
||||
|
||||
stopSignal() {
|
||||
//console.log('stopSignal');
|
||||
this.sndr.off();
|
||||
this.decoder.keyOff();
|
||||
this.lastSendTimestamp = Date.now();
|
||||
setTimeout(() => {
|
||||
this.sending = false;
|
||||
}, this.unit);
|
||||
}
|
||||
|
||||
press(event, down, mode=this.mode) {
|
||||
if (mode > 1 && event.code != this.ditKey1 && event.code != this.dahKey1 && event.code != this.ditKey2 && event.code != this.dahKey2) return;
|
||||
if (mode == 1) {
|
||||
if (down) {
|
||||
if (restartAudioNeeded()) {
|
||||
restartAudio();
|
||||
}
|
||||
this.sndr.setTone(this.tone);
|
||||
this.sndr.on();
|
||||
this.decoder.keyOn();
|
||||
|
||||
} else {
|
||||
this.sndr.off();
|
||||
this.decoder.keyOff();
|
||||
}
|
||||
} else if (mode > 1) {
|
||||
//console.log(key);
|
||||
if (event.code == this.ditKey1 || event.code == this.ditKey2) {
|
||||
if (down) { // dit key down
|
||||
this.ditKeyState = 1;
|
||||
this.ditStart = Date.now()
|
||||
} else { // dit key up
|
||||
this.ditKeyState = 0;
|
||||
this.ditStop = Date.now()
|
||||
}
|
||||
}
|
||||
if (event.code == this.dahKey1 || event.code == this.dahKey2) {
|
||||
if (down) { // dah key down
|
||||
this.dahKeyState = 1;
|
||||
this.dahStart = Date.now()
|
||||
} else { // dah key up
|
||||
this.dahKeyState = 0;
|
||||
this.dahStop = Date.now()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
processQueue() {
|
||||
//console.log('processQueue');
|
||||
if (!this.sending && this.queue.length) {
|
||||
this.lastKey = this.queue.shift();
|
||||
var signalLength = (this.lastKey == 1) ? this.unit : this.unit * 3;
|
||||
this.sendSignal();
|
||||
setTimeout(() => {
|
||||
this.stopSignal();
|
||||
}, signalLength);
|
||||
}
|
||||
}
|
||||
|
||||
oscillatev1() {
|
||||
if (!this.ditKeyState && !this.dahKeyState) {
|
||||
this.queue = [];
|
||||
}
|
||||
if (this.ditKeyState) {
|
||||
if (this.queue.length == 0) {
|
||||
if (!this.dahKeyState && !this.sending || this.lastKey == 2) {
|
||||
this.queue.push(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (this.dahKeyState) {
|
||||
if (this.queue.length == 0) {
|
||||
if (!this.ditKeyState && !this.sending || this.lastKey == 1) {
|
||||
this.queue.push(2);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!this.sending && Date.now() - this.lastSendTimestamp > this.unit) {
|
||||
this.processQueue();
|
||||
}
|
||||
}
|
||||
|
||||
oscillatev2() {
|
||||
if (this.mode == 2 && !this.ditKeyState && !this.dahKeyState) { // Iambic B doesn't clear the queue
|
||||
if (this.streak > 1) {
|
||||
//console.log(this.streak + " queue: " + this.queue[0]);
|
||||
this.queue = [];
|
||||
}
|
||||
this.streak = 0;
|
||||
}
|
||||
if (this.ditKeyState) {
|
||||
if (this.queue.length < 1) {
|
||||
if (!this.sending || this.lastKey == 2) {
|
||||
this.queue.push(1);
|
||||
if (this.lastKey == 2 && this.dahKeyState) {
|
||||
this.streak++;
|
||||
} else {
|
||||
this.streak = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (this.dahKeyState) {
|
||||
if (this.queue.length < 1) {
|
||||
if (!this.sending || this.lastKey == 1) {
|
||||
this.queue.push(2);
|
||||
if (this.lastKey == 1 && this.ditKeyState) {
|
||||
this.streak++;
|
||||
} else {
|
||||
this.streak = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!this.sending && Date.now() - this.lastSendTimestamp >= this.unit) {
|
||||
this.processQueue();
|
||||
}
|
||||
}
|
||||
|
||||
oscillatev3() {
|
||||
if (this.mode == 2 && !this.ditKeyState && !this.dahKeyState && this.queue.length) { // Iambic B doesn't clear the queue
|
||||
if ((this.ditStreak && this.queue[0] == 1) || (this.dahStreak && this.queue[0] == 2)) {
|
||||
console.log("ditStreak: "+this.ditStreak+" dahStreak: "+this.dahStreak+" queue: "+this.queue[0]);
|
||||
this.queue = [];
|
||||
}
|
||||
//console.log("NO CLEAR ditStreak: "+this.ditStreak+" dahStreak: "+this.dahStreak+" queue: "+this.queue[0]);
|
||||
this.ditStreak = 0;
|
||||
this.dahStreak = 0;
|
||||
}
|
||||
if (this.ditKeyState) {
|
||||
if (!this.queue.length) {
|
||||
if (!this.sending || this.lastKey == 2) {
|
||||
this.queue.push(1);
|
||||
this.ditStreak++;
|
||||
}
|
||||
} else if (!this.dahKeyState && this.queue[0] == 2) { // dah was canceled. Replace in queue
|
||||
this.queue[0] = 1;
|
||||
this.dahStreak = 0;
|
||||
this.ditStreak++;
|
||||
}
|
||||
}
|
||||
if (this.dahKeyState) {
|
||||
if (!this.queue.length) {
|
||||
if (!this.sending || this.lastKey == 1) {
|
||||
this.queue.push(2);
|
||||
this.dahStreak++;
|
||||
}
|
||||
} else if (!this.ditKeyState && this.queue[0] == 1) { // dit was canceled. Replace in queue
|
||||
this.queue[0] = 2;
|
||||
this.ditStreak = 0;
|
||||
this.dahStreak++;
|
||||
}
|
||||
}
|
||||
if (!this.sending && Date.now() - this.lastSendTimestamp >= this.unit) {
|
||||
this.processQueue();
|
||||
}
|
||||
}
|
||||
|
||||
oscillate() {
|
||||
if (this.mode == 2 && !this.ditKeyState && !this.dahKeyState && this.queue.length) {
|
||||
if (this.queue[0] == 1) { // Dit is in the queue
|
||||
if (this.ditStart < this.dahStart || this.ditStop - this.ditStart > this.unit * 4) {
|
||||
this.queue.pop();
|
||||
}
|
||||
} else { // Dah is in the queue
|
||||
if (this.dahStart < this.ditStart || this.dahStop - this.dahStart > this.unit * 2) {
|
||||
this.queue.pop();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (this.ditKeyState) {
|
||||
if (this.queue.length == 0) {
|
||||
if ((!this.dahKeyState && !this.sending) || this.lastKey == 2) {
|
||||
this.queue.push(1);
|
||||
}
|
||||
} else { // dah key was lifted and is still in queue
|
||||
if (this.mode == 2 && !this.dahKeyState && this.dahStart < this.ditStart && this.queue[0] == 2) {
|
||||
this.queue.pop();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (this.dahKeyState) {
|
||||
if (this.queue.length == 0) {
|
||||
if ((!this.ditKeyState && !this.sending) || this.lastKey == 1) {
|
||||
this.queue.push(2);
|
||||
}
|
||||
} else { // dit key was lifted and is still in queue
|
||||
if (this.mode == 2 && !this.ditKeyState && this.ditStart < this.dahStart && this.queue[0] == 1) {
|
||||
this.queue.pop();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!this.sending && Date.now() - this.lastSendTimestamp > this.unit) {
|
||||
this.processQueue();
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue