This commit is contained in:
Neale Pickett 2023-01-22 16:12:22 -07:00
commit 9df4c09229
8 changed files with 38 additions and 64 deletions

View File

@ -8,6 +8,6 @@ case "$1" in
docker -H ssh://melville.woozle.org service update --image ghcr.io/nealey/vail:main melville_vail
;;
"")
rsync -va static/ melville.woozle.org:/srv/vail/testing/
rsync --delete -va static/ melville.woozle.org:/srv/vail/testing/
;;
esac

View File

@ -2,6 +2,8 @@
* @file Provides some base audio tools.
*/
import * as time from "./time.mjs"
/**
* Compute the special "Audio Context" time
*
@ -13,8 +15,8 @@
*/
function AudioContextTime(context, when) {
if (!when) return 0
let acOffset = Date.now() - (context.currentTime * Second)
return Math.max(when - acOffset, 0) / Second
let acOffset = Date.now() - (context.currentTime * time.Second)
return Math.max(when - acOffset, 0) / time.Second
}
class AudioSource {

View File

@ -1,6 +1,4 @@
/** @typedef {Number} Duration */
const Millisecond = 1
const Second = 1000 * Millisecond
import * as time from "./time.mjs"
/**
* A chart of historical values.
@ -14,7 +12,7 @@ class HistoryChart {
* @param {string} style style to draw in; falls back to the `data-style` attribute
* @param {Duration} duration Time to display history for
*/
constructor(canvas, style=null, duration=20*Second) {
constructor(canvas, style=null, duration=20*time.Second) {
this.canvas = canvas
this.ctx = canvas.getContext("2d")
this.duration = duration
@ -22,7 +20,7 @@ class HistoryChart {
this.data = []
// One canvas pixel = 20ms
canvas.width = duration / (20 * Millisecond)
canvas.width = duration / (20 * time.Millisecond)
// Set origin to lower-left corner
this.ctx.scale(1, -1)
@ -113,7 +111,7 @@ class HistoryChart {
* @param duration duration of chart window
* @returns new chart, or null if it couldn't find a canvas
*/
function FromSelector(selector, style, duration=20*Second) {
function FromSelector(selector, style, duration=20*time.Second) {
let canvas = document.querySelector(selector)
if (canvas) {
return new HistoryChart(canvas, style, duration)

View File

@ -7,6 +7,7 @@
*/
import * as RoboKeyer from "./robokeyer.mjs"
import * as time from "./time.mjs"
/** Silent period between dits and dash */
const PAUSE = -1
@ -15,24 +16,6 @@ const DIT = 1
/** Length of a dah */
const DAH = 3
/**
* A time duration.
*
* JavaScript uses milliseconds in most (but not all) places.
* I've found it helpful to be able to multiply by a unit, so it's clear what's going on.
*
* @typedef {number} Duration
*/
/** @type {Duration} */
const Millisecond = 1
/** @type {Duration} */
const Second = 1000 * Millisecond
/** @type {Duration} */
const Minute = 60 * Second
/** @type {Duration} */
const Hour = 60 * Minute
/**
* Queue Set: A Set you can shift and pop.
*
@ -185,7 +168,7 @@ class BugKeyer extends StraightKeyer {
Reset() {
super.Reset()
this.SetDitDuration(100 * Millisecond)
this.SetDitDuration(100 * time.Millisecond)
if (this.pulseTimer) {
clearInterval(this.pulseTimer)
this.pulseTimer = null

View File

@ -1,4 +1,5 @@
import {AudioSource, AudioContextTime} from "./audio.mjs"
import * as time from "./time.mjs"
const HIGH_FREQ = 555
const LOW_FREQ = 444
@ -19,36 +20,33 @@ const LOW_FREQ = 444
* @typedef {number} Date
*/
const Millisecond = 1
const Second = 1000 * Millisecond
/** The amount of time it should take an oscillator to ramp to and from zero gain
*
* @constant {Duration}
*/
const OscillatorRampDuration = 5*Millisecond
const OscillatorRampDuration = 5*time.Millisecond
class Oscillator extends AudioSource {
/**
* Create a new oscillator, and encase it in a Gain for control.
*
* @param {AudioContext} context Audio context
* @param {AudioContext} context Audio context
* @param {number} frequency Oscillator frequency (Hz)
* @param {number} maxGain Maximum gain (volume) of this oscillator (0.0 - 1.0)
* @param {string} type Oscillator type
*/
constructor(context, frequency, maxGain = 0.5, type = "sine") {
super(context)
super(context)
this.maxGain = maxGain
// Start quiet
this.masterGain.gain.value = 0
// Start quiet
this.masterGain.gain.value = 0
this.osc = new OscillatorNode(this.context)
this.osc.type = type
this.osc.type = type
this.osc.connect(this.masterGain)
this.setFrequency(frequency)
this.setFrequency(frequency)
this.osc.start()
}
@ -88,7 +86,7 @@ class Oscillator extends AudioSource {
this.masterGain.gain.setTargetAtTime(
target,
AudioContextTime(this.context, when),
timeConstant/Second,
timeConstant/time.Second,
)
}
@ -227,7 +225,7 @@ class AudioBuzzer extends Buzzer {
Error() {
let now = Date.now()
this.errorTone.SoundAt(now)
this.errorTone.HushAt(now + 200*Millisecond)
this.errorTone.HushAt(now + 200*time.Millisecond)
}
}

View File

@ -1,8 +1,5 @@
import {GetFortune} from "./fortunes.mjs"
const Millisecond = 1
const Second = 1000 * Millisecond
const Minute = 60 * Second
import * as time from "./time.mjs"
/**
* Compare two messages
@ -61,7 +58,7 @@ export class Vail {
msg => {
this.rx(0, 0, {connected: false, notice: `Repeater disconnected: ${msg.reason}`})
console.error("Repeater connection dropped:", msg.reason)
setTimeout(() => this.reopen(), 2*Second)
setTimeout(() => this.reopen(), 2*time.Second)
}
)
}
@ -157,7 +154,7 @@ export class Vail {
}
export class Null {
constructor(rx, interval=3*Second) {
constructor(rx, interval=3*time.Second) {
this.rx = rx
this.init()
}
@ -219,7 +216,7 @@ export class Fortune extends Null {
if (this.timeout) {
clearTimeout(this.timeout)
}
this.timeout = setTimeout(() => this.pulse(), 3 * Second)
this.timeout = setTimeout(() => this.pulse(), 3 * time.Second)
}
Close() {

View File

@ -6,15 +6,13 @@
*
* @typedef {number} Duration
*/
/** @type {Duration} */
export const Millisecond = 1
const Millisecond = 1
/** @type {Duration} */
export const Second = 1000 * Millisecond
const Second = 1000 * Millisecond
/** @type {Duration} */
export const Minute = 60 * Second
const Minute = 60 * Second
/** @type {Duration} */
export const Hour = 60 * Minute
const Hour = 60 * Minute
export {Millisecond, Second, Minute, Hour}

View File

@ -4,12 +4,10 @@ import * as Inputs from "./inputs.mjs"
import * as Repeaters from "./repeaters.mjs"
import * as Chart from "./chart.mjs"
import * as I18n from "./i18n.mjs"
import * as time from "./time.mjs"
import * as Music from "./music.mjs"
const DefaultRepeater = "General"
const Millisecond = 1
const Second = 1000 * Millisecond
const Minute = 60 * Second
console.warn("Chrome will now complain about an AudioContext not being allowed to start. This is normal, and there is no way to make Chrome stop complaining about this.")
const globalAudioContext = new AudioContext({
@ -21,7 +19,7 @@ const globalAudioContext = new AudioContext({
*
* @param {string} msg Message to display
*/
function toast(msg, timeout=4*Second) {
function toast(msg, timeout=4*time.Second) {
console.info(msg)
let errors = document.querySelector("#errors")
@ -41,7 +39,7 @@ class VailClient {
this.lagTimes = [0]
this.rxDurations = [0]
this.clockOffset = null // How badly our clock is off of the server's
this.rxDelay = 0 * Millisecond // Time to add to incoming timestamps
this.rxDelay = 0 * time.Millisecond // Time to add to incoming timestamps
this.beginTxTime = null // Time when we began transmitting
// Outputs
@ -76,7 +74,7 @@ class VailClient {
this.inputInit("#keyer-mode", e => this.setKeyer(e.target.value))
this.inputInit("#keyer-rate", e => {
let rate = e.target.value
this.ditDuration = Math.round(Minute / rate / 50)
this.ditDuration = Math.round(time.Minute / rate / 50)
for (let e of document.querySelectorAll("[data-fill='keyer-ms']")) {
e.textContent = this.ditDuration
}
@ -85,7 +83,7 @@ class VailClient {
this.inputs.SetDitDuration(this.ditDuration)
})
this.inputInit("#rx-delay", e => {
this.rxDelay = e.target.value * Second
this.rxDelay = e.target.value * time.Second
})
this.inputInit("#masterGain", e => {
this.outputs.SetGain(e.target.value / 100)
@ -464,7 +462,7 @@ class VailClient {
function init() {
if (navigator.serviceWorker) {
navigator.serviceWorker.register("sw.js")
navigator.serviceWorker.register("scripts/sw.js")
}
I18n.Setup()
try {