I think it works? Maybe?

This commit is contained in:
Neale Pickett 2020-04-26 21:43:55 -06:00
parent b202ab6968
commit 308131f901
3 changed files with 196 additions and 78 deletions

View File

@ -24,22 +24,21 @@
<div class="mdl-layout-spacer"></div>
<!-- Navigation -->
<nav class="mdl-navigation">
<a class="mdl-navigation__link" href="">Link</a>
<a class="mdl-navigation__link" href="">Link</a>
<a class="mdl-navigation__link" href="">Link</a>
<a class="mdl-navigation__link" href="">Link</a>
<a class="mdl-navigation__link" href="https://github.com/nealey/vail">Source Code</a>
<a class="mdl-navigation__link" href="https://github.com/nealey/vail/issues/new">Bug Report</a>
</nav>
</div>
</header>
<div class="mdl-layout__drawer">
<span class="mdl-layout-title">Title</span>
<span class="mdl-layout-title">Repeaters</span>
<nav class="mdl-navigation">
<a class="mdl-navigation__link" href="">Link</a>
<a class="mdl-navigation__link" href="">Link</a>
<a class="mdl-navigation__link" href="">Link</a>
<a class="mdl-navigation__link" href="">Link</a>
<a class="mdl-navigation__link" href="?repeater=">1-15 WPM</a>
<a class="mdl-navigation__link" href="?repeater=int">16-20 WPM</a>
<a class="mdl-navigation__link" href="?repeater=adv">21-99 WPM</a>
</nav>
</div>
<main class="mdl-layout__content">
<div class="flex">
<div class="mdl-card mdl-shadow--4dp">
@ -54,12 +53,23 @@
<a href="#iambic" class="mdl-tabs__tab">Iambic</a>
</div>
<div class="mdl-tabs__panel is-active" id="straight">
<button id="key" class="key mdl-button mdl-js-button mdl-button--raised mdl-button--colored">
Key
</button>
<table class="center wide">
<tr>
<td>
<button id="key" class="key mdl-button mdl-js-button mdl-button--raised mdl-button--colored">
Key
</button>
</td>
</tr>
<tr>
<td>
<code></code>
</td>
</tr>
</table>
</div>
<div class="mdl-tabs__panel" id="iambic">
<table style="width: 100%; text-align: center;">
<table class="center wide">
<tr>
<td>
<button id="dit" class="key mdl-button mdl-js-button mdl-button--raised mdl-button--colored">
@ -74,27 +84,79 @@
</tr>
<tr>
<td>
<code>.</code> or <code></code>
<code>.</code> or <code>z</code>
</td>
<td>
<code>/</code> or <code>z</code>
<code>/</code> or <code>x</code>
</td>
</tr>
</table>
<p>
Dit length:
<output id="iambic-duration-value"></output>ms
<input
id="iambic-duration"
class="mdl-slider mdl-js-slider"
type="range"
min="40"
max="255"
value="80">
</p>
</div>
</div>
</div>
<div class="mdl-card mdl-shadow--4dp">
<div class="mdl-card__title">
<h2 class="mdl-card__title-text">
Knobs
</h2>
</div>
<div class="mdl-card__supporting-text">
<table>
<tbody>
<tr>
<td>
Average round-trip time:
</td>
<td>
<output id="lag-value">0</output>ms
</td>
</tr>
<tr>
<td>
Longest recent transmission:
</td>
<td>
<output id="longest-rx-value">0</output>ms
</td>
</tr>
<tr>
<td>
Suggested receive delay:
</td>
<td>
<output id="suggested-delay-value">0</output>ms
</td>
</tr>
<tr>
</tr>
</tbody>
</table>
<hr>
<p>
Recieve delay:
<output id="rx-delay-value"></output>ms
<input
id="rx-delay"
class="mdl-slider mdl-js-slider"
type="range"
min="0"
max="5000"
value="300">
</p>
<p>
Dit length (iambic):
<output id="iambic-duration-value"></output>ms
<input
id="iambic-duration"
class="mdl-slider mdl-js-slider"
type="range"
min="40"
max="255"
value="80">
</p>
</div>
</div>
<div class="mdl-card mdl-shadow--4dp">
<div class="mdl-card__title">
@ -125,62 +187,44 @@
Just like a radio repeater,
anybody can connect and start transmitting stuff,
and this will broadcast it to everyone connected.
If there's enough interest,
I'll add something like channels.
</p>
<h3 class="mdl-card__title-text">Why Does This Exist?</h3>
<p>
If you need this to work on a cell phone,
let me know and I'll come up with something for you.
</p>
</div>
</div>
<div class="mdl-card mdl-shadow--4dp">
<div class="mdl-card__title">
<h2 class="mdl-card__title-text">
Why Does This Exist?
</h2>
</div>
<div class="mdl-card__supporting-text">
<p>
I need a place to practice CW with actual human beings,
and I want it to be as close as possible to what I'd experience on a radio.
Also, I don't want to make people buy a bunch of radio hardware.
Nothing else like this exists on the Internet, as far as I can tell.
</p>
<h3>Who made it?</h3>
<p>
<a href="mailto:neale@woozle.org">Neale Pickett</a> kd7oqi
</p>
</div>
</div>
<div class="mdl-card mdl-shadow--4dp">
<div class="mdl-card__title">
<h3 class="mdl-card__title-text">Future plans</h3>
<h2 class="mdl-card__title-text">Future plans</h2>
</div>
<div class="mdl-card__supporting_text">
<div class="mdl-card__supporting-text">
<ul>
<li>Move to a more permanent URL</li>
<li>Make this page less ugly</li>
<li>Arduino program to let you hook up an iambic paddle over USB</li>
<li>Document the protocol</li>
<li>Support multiple channels/frequencies</li>
<li>Sensible way to make this work on a cell phone</li>
<li>Make this page less ugly (I really hate it right now)</li>
</ul>
<h3>How can I help?</h3>
<h3 class="mdl-card__title-text">How can I help?</h3>
<ul>
<li>Improve the <a href="https://github.com/nealey/vail/">source code</a></li>
<li><a href="mailto:neale@woozle.org">Email me</a> and let me know you're using it</li>
<li>Email me and let me know you're using it</li>
</ul>
<p>
<a href="mailto:neale@woozle.org">Neale Pickett</a> kd7oqi
</p>
</div>
</div>
</div>

View File

@ -14,6 +14,14 @@
height: 6em;
}
.center {
text-align: center;
}
.wide {
width: 100%;
}
code {
background-color: #333;
color: #fff;

View File

@ -2,6 +2,7 @@
const lowFreq = 660
const highFreq = lowFreq * 6 / 5 // Perfect minor third
const errorFreq = 30
const DIT = 1
const DAH = 3
@ -91,26 +92,26 @@ class Buzzer {
// in order to avoid "pops" (square wave overtones)
// that happen with instant changes in gain.
constructor(txGain=0.5) {
constructor(txGain=0.3) {
this.txGain = txGain
this.ac = new AudioContext()
this.lowGain = this.ac.createGain()
this.lowGain.connect(this.ac.destination)
this.lowGain.gain.value = 0
this.lowOsc = this.ac.createOscillator()
this.lowOsc.connect(this.lowGain)
this.lowOsc.frequency.value = lowFreq
this.lowOsc.start()
this.highGain = this.ac.createGain()
this.highGain.connect(this.ac.destination)
this.highGain.gain.value = 0
this.highOsc = this.ac.createOscillator()
this.highOsc.connect(this.highGain)
this.highOsc.frequency.value = highFreq
this.highOsc.start()
this.lowGain = this.create(lowFreq)
this.highGain = this.create(highFreq)
this.errorGain = this.create(errorFreq, "square")
}
create(frequency, type="sine") {
let gain = this.ac.createGain()
gain.connect(this.ac.destination)
gain.gain.value = 0
let osc = this.ac.createOscillator()
osc.type = type
osc.connect(gain)
osc.frequency.value = frequency
osc.start()
return gain
}
gain(high) {
@ -145,6 +146,14 @@ class Buzzer {
this.txGain = gain
}
/**
* Play an error tone
*/
ErrorTone() {
this.errorGain.gain.setTargetAtTime(this.txGain * 0.5, this.ac.currentTime, 0.001)
this.errorGain.gain.setTargetAtTime(0, this.ac.currentTime + 0.2, 0.001)
}
/**
* Begin buzzing at time
*
@ -187,6 +196,10 @@ class Buzzer {
class Vail {
constructor() {
this.sent = []
this.lagTimes = [0]
this.rxDurations = [0]
this.rxDelay = 0 // Milliseconds to add to incoming timestamps
this.beginTxTime = null // Time when we began transmitting
// Set up WebSocket
@ -194,7 +207,7 @@ class Vail {
wsUrl.protocol = "ws:"
wsUrl.pathname += "chat"
window.socket = new WebSocket(wsUrl)
window.socket.addEventListener("message", this.wsMessage)
window.socket.addEventListener("message", e => this.wsMessage(e))
// Listen to HTML buttons
for (let e of document.querySelectorAll("button.key")) {
@ -213,6 +226,7 @@ class Vail {
// Listen for slider values
this.inputInit("#iambic-duration", e => this.iambic.SetInterval(e.target.value))
this.inputInit("#rx-delay", e => {this.rxDelay = e.target.value})
}
inputInit(selector, func) {
@ -241,17 +255,69 @@ class Vail {
let endTxTime = Date.now()
let duration = endTxTime - this.beginTxTime
this.buzzer.Silence(true)
this.wsSend(this.beginTxTime, duration)
this.beginTxTime = null
}
updateReading(selector, value) {
let e = document.querySelector(selector)
if (e) {
e.value = value
}
}
updateReadings() {
let avgLag = this.lagTimes.reduce((a,b) => (a+b)) / this.lagTimes.length
let longestRx = this.rxDurations.reduce(Math.max)
let suggestedDelay = (avgLag + longestRx) * 1.2
let msg = JSON.stringify([this.beginTxTime, duration])
window.socket.send(msg)
this.updateReading("#lag-value", avgLag.toFixed())
this.updateReading("#longest-rx-value", longestRx)
this.updateReading("#suggested-delay-value", suggestedDelay.toFixed())
}
addLagReading(duration) {
this.lagTimes.push(duration)
if (this.lagTimes.length > 20) {
this.lagTimes.shift()
}
this.updateReadings()
}
addRxDuration(duration) {
this.rxDurations.push(duration)
if (this.rxDurations.length > 20) {
this.rxDurations.shift()
}
this.updateReadings()
}
wsSend(time, duration) {
let msg = [time, duration]
let jmsg = JSON.stringify(msg)
window.socket.send(jmsg)
this.sent.push(jmsg)
}
wsMessage(event) {
let msg = JSON.parse(event.data)
let jmsg = event.data
let msg = JSON.parse(jmsg)
let beginTxTime = msg[0]
let duration = msg[1]
let sent = this.sent.filter(e => e != jmsg)
if (sent.length < this.sent.length) {
// We're getting our own message back, which tells us our lag.
// We shouldn't emit a tone, though.
this.sent = sent
this.addLagReading(Date.now() - beginTxTime - duration)
return
}
console.log(msg)
// Beep!
this.buzzer.BuzzDuration(false, beginTxTime+this.rxDelay, duration)
this.addRxDuration(duration)
}
key(event) {
@ -262,11 +328,11 @@ class Vail {
let begin = event.type.endsWith("down")
if ((event.code == "Period") || (event.key == "KeyZ")) {
if ((event.code == "KeyZ") || (event.code == "Period")) {
event.preventDefault()
this.iambic.Key(begin, DIT)
}
if ((event.code == "Slash") || (event.code == "KeyX")) {
if ((event.code == "KeyX") || (event.code == "Slash")) {
event.preventDefault()
this.iambic.Key(begin, DAH)
}