Fortunes are now a repeater

This commit is contained in:
Neale Pickett 2021-04-27 18:37:25 -06:00
parent 42c88c3896
commit fbc489dfdc
5 changed files with 88 additions and 14 deletions

View File

@ -462,6 +462,6 @@ export const fortunes = [
/** /**
* Return a randomly-chosen fortune. * Return a randomly-chosen fortune.
*/ */
export function getFortune() { export function GetFortune() {
return fortunes[Math.floor(Math.random() * fortunes.length)] return fortunes[Math.floor(Math.random() * fortunes.length)]
} }

View File

@ -44,6 +44,15 @@
<a class="mdl-navigation__link" href="?repeater=21-99+WPM">21-99 WPM</a> <a class="mdl-navigation__link" href="?repeater=21-99+WPM">21-99 WPM</a>
</nav> </nav>
<hr> <hr>
<span class="mdl-layout-title">Local Practice</span>
<nav class="mdl-navigation">
<a class="mdl-navigation__link" href="?repeater=Fortunes">Fortunes</a>
<a class="mdl-navigation__link" href="?repeater=Fortunes: Pauses ×2">Fortunes (slow)</a>
<a class="mdl-navigation__link" href="?repeater=Fortunes: Pauses ×4">Fortunes (very slow)</a>
<a class="mdl-navigation__link" href="?repeater=Fortunes: Pauses ×6">Fortunes (very very slow)</a>
<a class="mdl-navigation__link" href="?repeater=Fortunes: Pauses ×10">Fortunes (crazy slow)</a>
</nav>
<nav class="mdl-navigation"> <nav class="mdl-navigation">
<a class="mdl-navigation__link" href="https://morse.withgoogle.com/learn/">Learn Morse Code</a> <a class="mdl-navigation__link" href="https://morse.withgoogle.com/learn/">Learn Morse Code</a>
<a class="mdl-navigation__link" href="https://github.com/nealey/vail-adapter">Use a physical key</a> <a class="mdl-navigation__link" href="https://github.com/nealey/vail-adapter">Use a physical key</a>
@ -71,6 +80,10 @@
<option>1-15 WPM</option> <option>1-15 WPM</option>
<option>16-20 WPM</option> <option>16-20 WPM</option>
<option>21+ WPM</option> <option>21+ WPM</option>
<option>Fortunes: Pauses ×8</option>
<option>Fortunes: Pauses ×4</option>
<option>Fortunes: Pauses ×2</option>
<option>Fortunes</option>
</datalist> </datalist>
<label class="mdl-textfield__label" for="repeater">Repeater</label> <label class="mdl-textfield__label" for="repeater">Repeater</label>
</div> </div>

View File

@ -90,11 +90,12 @@ if (!window.AudioContext) {
*/ */
class Keyer { class Keyer {
/** /**
* Create an Iambic control * Create an Keyer
* *
* @param {TxControl} beginTxFunc Function to begin transmitting * @param {TxControl} beginTxFunc Callback to begin transmitting
* @param {TxControl} endTxFunc Function to end transmitting * @param {TxControl} endTxFunc Callback to end transmitting
* @param {number} intervalDuration Dit duration (milliseconds) * @param {number} intervalDuration Dit duration (milliseconds)
* @param {number} pauseMultiplier How long to stretch out inter-letter and inter-word pauses
*/ */
constructor(beginTxFunc, endTxFunc, {intervalDuration=100, pauseMultiplier=1}={}) { constructor(beginTxFunc, endTxFunc, {intervalDuration=100, pauseMultiplier=1}={}) {
this.beginTxFunc = beginTxFunc this.beginTxFunc = beginTxFunc
@ -201,6 +202,11 @@ class Keyer {
this.maybePulse() this.maybePulse()
} }
/**
* Enqueue a morse code string (eg "... --- ...")
*
* @param {string} ms String to enqueue
*/
EnqueueMorseString(ms) { EnqueueMorseString(ms) {
for (let mc of ms) { for (let mc of ms) {
switch (mc) { switch (mc) {
@ -217,6 +223,11 @@ class Keyer {
} }
} }
/**
* Enqueue an ASCII string (eg "SOS help")
*
* @param {string} s String to enqueue
*/
EnqueueAsciiString(s, {pauseLetter = PAUSE_LETTER, pauseWord = PAUSE_WORD} = {}) { EnqueueAsciiString(s, {pauseLetter = PAUSE_LETTER, pauseWord = PAUSE_WORD} = {}) {
for (let c of s.toLowerCase()) { for (let c of s.toLowerCase()) {
let m = MorseMap[c] let m = MorseMap[c]

View File

@ -1,3 +1,9 @@
import {GetFortune} from "./fortunes.mjs"
const Millisecond = 1
const Second = 1000 * Millisecond
const Minute = 60 * Second
export class Vail { export class Vail {
constructor(name, rx) { constructor(name, rx) {
this.name = name this.name = name
@ -104,7 +110,7 @@ export class Vail {
} }
export class Null { export class Null {
constructor(name, rx) { constructor() {
} }
Transmit(time, duration, squelch=True) { Transmit(time, duration, squelch=True) {
@ -113,3 +119,35 @@ export class Null {
Close() { Close() {
} }
} }
export class Fortune {
/**
*
* @param rx Receive callback
* @param {Keyer} keyer Keyer object
*/
constructor(rx, keyer) {
this.rx = rx
this.keyer = keyer
this.interval = setInterval(() => this.pulse(), 1 * Minute)
this.pulse()
}
pulse() {
if (this.keyer.Busy()) {
return
}
let fortune = GetFortune()
this.keyer.EnqueueAsciiString(`${fortune}\x04 `)
}
Transmit(time, duration, squelch=true) {
// Do nothing.
}
Close() {
clearInterval(this.interval)
}
}

View File

@ -1,7 +1,6 @@
import * as Morse from "./morse.mjs" import * as Morse from "./morse.mjs"
import * as Inputs from "./inputs.mjs" import * as Inputs from "./inputs.mjs"
import * as Repeaters from "./repeaters.mjs" import * as Repeaters from "./repeaters.mjs"
import {getFortune} from "./fortunes.mjs"
const DefaultRepeater = "General Chaos" const DefaultRepeater = "General Chaos"
@ -27,7 +26,7 @@ class VailClient {
this.sent = [] this.sent = []
this.lagTimes = [0] this.lagTimes = [0]
this.rxDurations = [0] this.rxDurations = [0]
this.clockOffset = 0 // How badly our clock is off of the server's this.clockOffset = "unknown" // How badly our clock is off of the server's
this.rxDelay = 0 // Milliseconds to add to incoming timestamps this.rxDelay = 0 // Milliseconds to add to incoming timestamps
this.beginTxTime = null // Time when we began transmitting this.beginTxTime = null // Time when we began transmitting
this.debug = localStorage.debug this.debug = localStorage.debug
@ -37,14 +36,14 @@ class VailClient {
let me = new URL(location) let me = new URL(location)
let repeater = me.searchParams.get("repeater") let repeater = me.searchParams.get("repeater")
me.search = "" me.search = ""
me.hash = repeater me.hash = decodeURIComponent(repeater)
window.location = me window.location = me
} }
// Make helpers // Make helpers
this.buzzer = new Morse.Buzzer() this.buzzer = new Morse.Buzzer()
this.keyer = new Morse.Keyer(() => this.beginTx(), () => this.endTx()) this.keyer = new Morse.Keyer(() => this.beginTx(), () => this.endTx())
this.iambicKeyer = new Morse.Keyer(() => this.buzzer.Buzz(), () => this.buzzer.Silence()) this.roboKeyer = new Morse.Keyer(() => this.buzzer.Buzz(), () => this.buzzer.Silence())
// Set up various input methods // Set up various input methods
this.inputs = Inputs.SetupAll(this.keyer) this.inputs = Inputs.SetupAll(this.keyer)
@ -60,7 +59,7 @@ class VailClient {
// Set up sliders // Set up sliders
this.sliderInit("#iambic-duration", e => { this.sliderInit("#iambic-duration", e => {
this.keyer.SetIntervalDuration(e.target.value) this.keyer.SetIntervalDuration(e.target.value)
this.iambicKeyer.SetIntervalDuration(e.target.value) this.roboKeyer.SetIntervalDuration(e.target.value)
}) })
this.sliderInit("#rx-delay", e => { this.sliderInit("#rx-delay", e => {
this.rxDelay = Number(e.target.value) this.rxDelay = Number(e.target.value)
@ -68,7 +67,7 @@ class VailClient {
// Fill in the name of our repeater // Fill in the name of our repeater
let repeaterElement = document.querySelector("#repeater").addEventListener("change", e => this.setRepeater(e.target.value.trim())) let repeaterElement = document.querySelector("#repeater").addEventListener("change", e => this.setRepeater(e.target.value.trim()))
this.setRepeater(decodeURI(unescape(window.location.hash.split("#")[1] || ""))) this.setRepeater(decodeURI(decodeURIComponent(window.location.hash.split("#")[1] || "")))
} }
/** /**
@ -81,7 +80,7 @@ class VailClient {
*/ */
setRepeater(name) { setRepeater(name) {
if (!name || (name == "")) { if (!name || (name == "")) {
name = "General Chaos" name = DefaultRepeater
} }
this.repeaterName = name this.repeaterName = name
@ -106,7 +105,20 @@ class VailClient {
if (this.repeater) { if (this.repeater) {
this.repeater.Close() this.repeater.Close()
} }
this.repeater = new Repeaters.Vail(name, (w,d,s) => this.receive(w,d,s)) let rx = (w,d,s) => this.receive(w,d,s)
// You can set the repeater name to "Fortunes: Pauses×10" for a nice and easy intro
if (name.startsWith("Fortunes")) {
let m = name.match(/[x×]([0-9]+)/)
let mult = 1
if (m) {
mult = Number(m[1])
}
this.roboKeyer.SetPauseMultiplier(mult)
this.repeater = new Repeaters.Fortune(rx, this.roboKeyer)
} else {
this.repeater = new Repeaters.Vail(name, rx)
}
toast(`Now using repeater: ${name}`) toast(`Now using repeater: ${name}`)
} }
@ -180,7 +192,7 @@ class VailClient {
* @param {dict} stats Stuff the repeater class would like us to know about * @param {dict} stats Stuff the repeater class would like us to know about
*/ */
receive(when, duration, stats) { receive(when, duration, stats) {
this.clockOffset = stats.clockOffset this.clockOffset = stats.clockOffset || "unknown"
let now = Date.now() let now = Date.now()
when += this.rxDelay when += this.rxDelay