standardize definitions of durations

This commit is contained in:
Neale Pickett 2023-01-17 12:25:20 -07:00
parent 0dffcbfab0
commit 6ebb9e621d
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 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 esac

View File

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

View File

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

View File

@ -7,6 +7,7 @@
*/ */
import * as RoboKeyer from "./robokeyer.mjs" import * as RoboKeyer from "./robokeyer.mjs"
import * as time from "./time.mjs"
/** Silent period between dits and dash */ /** Silent period between dits and dash */
const PAUSE = -1 const PAUSE = -1
@ -15,24 +16,6 @@ const DIT = 1
/** Length of a dah */ /** Length of a dah */
const DAH = 3 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. * Queue Set: A Set you can shift and pop.
* *
@ -185,7 +168,7 @@ class BugKeyer extends StraightKeyer {
Reset() { Reset() {
super.Reset() super.Reset()
this.SetDitDuration(100 * Millisecond) this.SetDitDuration(100 * time.Millisecond)
if (this.pulseTimer) { if (this.pulseTimer) {
clearInterval(this.pulseTimer) clearInterval(this.pulseTimer)
this.pulseTimer = null this.pulseTimer = null

View File

@ -1,4 +1,5 @@
import {AudioSource, AudioContextTime} from "./audio.mjs" import {AudioSource, AudioContextTime} from "./audio.mjs"
import * as time from "./time.mjs"
const HIGH_FREQ = 555 const HIGH_FREQ = 555
const LOW_FREQ = 444 const LOW_FREQ = 444
@ -19,36 +20,33 @@ const LOW_FREQ = 444
* @typedef {number} Date * @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 /** The amount of time it should take an oscillator to ramp to and from zero gain
* *
* @constant {Duration} * @constant {Duration}
*/ */
const OscillatorRampDuration = 5*Millisecond const OscillatorRampDuration = 5*time.Millisecond
class Oscillator extends AudioSource { class Oscillator extends AudioSource {
/** /**
* Create a new oscillator, and encase it in a Gain for control. * 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} frequency Oscillator frequency (Hz)
* @param {number} maxGain Maximum gain (volume) of this oscillator (0.0 - 1.0) * @param {number} maxGain Maximum gain (volume) of this oscillator (0.0 - 1.0)
* @param {string} type Oscillator type * @param {string} type Oscillator type
*/ */
constructor(context, frequency, maxGain = 0.5, type = "sine") { constructor(context, frequency, maxGain = 0.5, type = "sine") {
super(context) super(context)
this.maxGain = maxGain this.maxGain = maxGain
// Start quiet // Start quiet
this.masterGain.gain.value = 0 this.masterGain.gain.value = 0
this.osc = new OscillatorNode(this.context) this.osc = new OscillatorNode(this.context)
this.osc.type = type this.osc.type = type
this.osc.connect(this.masterGain) this.osc.connect(this.masterGain)
this.setFrequency(frequency) this.setFrequency(frequency)
this.osc.start() this.osc.start()
} }
@ -88,7 +86,7 @@ class Oscillator extends AudioSource {
this.masterGain.gain.setTargetAtTime( this.masterGain.gain.setTargetAtTime(
target, target,
AudioContextTime(this.context, when), AudioContextTime(this.context, when),
timeConstant/Second, timeConstant/time.Second,
) )
} }
@ -227,7 +225,7 @@ class AudioBuzzer extends Buzzer {
Error() { Error() {
let now = Date.now() let now = Date.now()
this.errorTone.SoundAt(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" import {GetFortune} from "./fortunes.mjs"
import * as time from "./time.mjs"
const Millisecond = 1
const Second = 1000 * Millisecond
const Minute = 60 * Second
/** /**
* Compare two messages * Compare two messages
@ -61,7 +58,7 @@ export class Vail {
msg => { msg => {
this.rx(0, 0, {connected: false, notice: `Repeater disconnected: ${msg.reason}`}) this.rx(0, 0, {connected: false, notice: `Repeater disconnected: ${msg.reason}`})
console.error("Repeater connection dropped:", 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 { export class Null {
constructor(rx, interval=3*Second) { constructor(rx, interval=3*time.Second) {
this.rx = rx this.rx = rx
this.init() this.init()
} }
@ -219,11 +216,11 @@ export class Fortune extends Null {
if (this.timeout) { if (this.timeout) {
clearTimeout(this.timeout) clearTimeout(this.timeout)
} }
this.timeout = setTimeout(() => this.pulse(), 3 * Second) this.timeout = setTimeout(() => this.pulse(), 3 * time.Second)
} }
Close() { Close() {
this.keyer.Flush() this.keyer.Flush()
super.Close() super.Close()
} }
} }

View File

@ -6,15 +6,13 @@
* *
* @typedef {number} Duration * @typedef {number} Duration
*/ */
/** @type {Duration} */ /** @type {Duration} */
export const Millisecond = 1 const Millisecond = 1
/** @type {Duration} */ /** @type {Duration} */
export const Second = 1000 * Millisecond const Second = 1000 * Millisecond
/** @type {Duration} */ /** @type {Duration} */
export const Minute = 60 * Second const Minute = 60 * Second
/** @type {Duration} */ /** @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 Repeaters from "./repeaters.mjs"
import * as Chart from "./chart.mjs" import * as Chart from "./chart.mjs"
import * as I18n from "./i18n.mjs" import * as I18n from "./i18n.mjs"
import * as time from "./time.mjs"
import * as Music from "./music.mjs" import * as Music from "./music.mjs"
const DefaultRepeater = "General" 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.") 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({ const globalAudioContext = new AudioContext({
@ -21,7 +19,7 @@ const globalAudioContext = new AudioContext({
* *
* @param {string} msg Message to display * @param {string} msg Message to display
*/ */
function toast(msg, timeout=4*Second) { function toast(msg, timeout=4*time.Second) {
console.info(msg) console.info(msg)
let errors = document.querySelector("#errors") let errors = document.querySelector("#errors")
@ -41,7 +39,7 @@ class VailClient {
this.lagTimes = [0] this.lagTimes = [0]
this.rxDurations = [0] this.rxDurations = [0]
this.clockOffset = null // How badly our clock is off of the server's 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 this.beginTxTime = null // Time when we began transmitting
// Outputs // Outputs
@ -76,7 +74,7 @@ class VailClient {
this.inputInit("#keyer-mode", e => this.setKeyer(e.target.value)) this.inputInit("#keyer-mode", e => this.setKeyer(e.target.value))
this.inputInit("#keyer-rate", e => { this.inputInit("#keyer-rate", e => {
let rate = e.target.value 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']")) { for (let e of document.querySelectorAll("[data-fill='keyer-ms']")) {
e.textContent = this.ditDuration e.textContent = this.ditDuration
} }
@ -85,7 +83,7 @@ class VailClient {
this.inputs.SetDitDuration(this.ditDuration) this.inputs.SetDitDuration(this.ditDuration)
}) })
this.inputInit("#rx-delay", e => { this.inputInit("#rx-delay", e => {
this.rxDelay = e.target.value * Second this.rxDelay = e.target.value * time.Second
}) })
this.inputInit("#masterGain", e => { this.inputInit("#masterGain", e => {
this.outputs.SetGain(e.target.value / 100) this.outputs.SetGain(e.target.value / 100)
@ -463,7 +461,7 @@ class VailClient {
function init() { function init() {
if (navigator.serviceWorker) { if (navigator.serviceWorker) {
navigator.serviceWorker.register("sw.js") navigator.serviceWorker.register("scripts/sw.js")
} }
I18n.Setup() I18n.Setup()
try { try {