mirror of https://github.com/nealey/vail.git
iambic more responsive, add MIDI control
This commit is contained in:
parent
3a16ebb7af
commit
965630e1ad
104
static/vail.js
104
static/vail.js
|
@ -11,8 +11,8 @@ class Iambic {
|
||||||
constructor(beginTxFunc, endTxFunc) {
|
constructor(beginTxFunc, endTxFunc) {
|
||||||
this.beginTxFunc = beginTxFunc
|
this.beginTxFunc = beginTxFunc
|
||||||
this.endTxFunc = endTxFunc
|
this.endTxFunc = endTxFunc
|
||||||
this.interval = null
|
this.intervalDuration = null
|
||||||
this.state = this.stateSpace
|
this.state = this.stateBegin
|
||||||
this.keyState = null
|
this.keyState = null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,19 +21,30 @@ class Iambic {
|
||||||
*
|
*
|
||||||
* @param {number} duration New interval duration, in ms
|
* @param {number} duration New interval duration, in ms
|
||||||
*/
|
*/
|
||||||
SetInterval(duration) {
|
SetIntervalDuration(duration) {
|
||||||
|
this.intervalDuration = duration
|
||||||
|
if (this.interval) {
|
||||||
clearInterval(this.interval)
|
clearInterval(this.interval)
|
||||||
this.interval = setInterval(e => this.pulse(), duration)
|
this.interval = setInterval(e => this.pulse(), duration)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// An interval has passed, call whatever the current state function is
|
// An interval has passed, call whatever the current state function is
|
||||||
pulse(event) {
|
pulse(event) {
|
||||||
this.state()
|
this.state()
|
||||||
}
|
}
|
||||||
|
|
||||||
stateSpace() {
|
|
||||||
|
stateBegin() {
|
||||||
|
if (this.keyState) {
|
||||||
// Don't transmit for one interval.
|
// Don't transmit for one interval.
|
||||||
this.state = this.keyState || this.stateSpace
|
this.state = this.keyState
|
||||||
|
this.state()
|
||||||
|
} else {
|
||||||
|
// No key pressed, go back to sleep.
|
||||||
|
clearInterval(this.interval)
|
||||||
|
this.interval = null
|
||||||
|
}
|
||||||
}
|
}
|
||||||
stateDit() {
|
stateDit() {
|
||||||
// Send a dit
|
// Send a dit
|
||||||
|
@ -54,8 +65,7 @@ class Iambic {
|
||||||
stateEnd() {
|
stateEnd() {
|
||||||
// Stop sending
|
// Stop sending
|
||||||
this.endTxFunc()
|
this.endTxFunc()
|
||||||
this.state = this.stateSpace
|
this.state = this.stateBegin
|
||||||
this.state()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -80,6 +90,12 @@ class Iambic {
|
||||||
// Only stop when we've released the right key
|
// Only stop when we've released the right key
|
||||||
this.keyState = null
|
this.keyState = null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Not pulsing yet? Start right away!
|
||||||
|
if (! this.interval) {
|
||||||
|
this.interval = setInterval(e => this.pulse(), this.intervalDuration)
|
||||||
|
this.pulse()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -226,12 +242,16 @@ class Vail {
|
||||||
this.buzzer = new Buzzer()
|
this.buzzer = new Buzzer()
|
||||||
|
|
||||||
// Listen for slider values
|
// Listen for slider values
|
||||||
this.inputInit("#iambic-duration", e => this.iambic.SetInterval(e.target.value))
|
this.inputInit("#iambic-duration", e => this.iambic.SetIntervalDuration(e.target.value))
|
||||||
this.inputInit("#rx-delay", e => {this.rxDelay = Number(e.target.value)})
|
this.inputInit("#rx-delay", e => {this.rxDelay = Number(e.target.value)})
|
||||||
|
|
||||||
// Show what repeater we're on
|
// Show what repeater we're on
|
||||||
let repeater = (new URL(location)).searchParams.get("repeater") || "Default"
|
let repeater = (new URL(location)).searchParams.get("repeater") || "Default"
|
||||||
document.querySelector("#repeater").textContent = repeater
|
document.querySelector("#repeater").textContent = repeater
|
||||||
|
|
||||||
|
// Request MIDI access
|
||||||
|
navigator.requestMIDIAccess()
|
||||||
|
.then(a => this.midiInit(a))
|
||||||
}
|
}
|
||||||
|
|
||||||
inputInit(selector, func) {
|
inputInit(selector, func) {
|
||||||
|
@ -251,6 +271,51 @@ class Vail {
|
||||||
element.dispatchEvent(new Event("input"))
|
element.dispatchEvent(new Event("input"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
midiInit(access) {
|
||||||
|
this.midiAccess = access
|
||||||
|
for (let input of this.midiAccess.inputs.values()) {
|
||||||
|
input.addEventListener("midimessage", e => this.midiMessage(e))
|
||||||
|
}
|
||||||
|
this.midiAccess.addEventListener("statechange", e => this.midiStateChange(e))
|
||||||
|
}
|
||||||
|
|
||||||
|
midiStateChange(event) {
|
||||||
|
if (event.port.connection == "open") {
|
||||||
|
console.log(event)
|
||||||
|
event.port.addEventListiner("midimessage", e => this.midiMessage(e))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
midiMessage(event) {
|
||||||
|
let data = Array.from(event.data)
|
||||||
|
|
||||||
|
let begin
|
||||||
|
switch (Number(data[0])) {
|
||||||
|
case 0x90:
|
||||||
|
begin = true
|
||||||
|
break
|
||||||
|
case 0x80:
|
||||||
|
begin = false
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (data[1] % 12) {
|
||||||
|
case 0: // C
|
||||||
|
this.straightKey(begin)
|
||||||
|
break
|
||||||
|
case 1: // C#
|
||||||
|
this.iambic.Key(begin, DIT)
|
||||||
|
break
|
||||||
|
case 2: // D
|
||||||
|
this.iambic.Key(begin, DAH)
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
error(msg) {
|
error(msg) {
|
||||||
let now = new Date()
|
let now = new Date()
|
||||||
let e = document.querySelector("#errors")
|
let e = document.querySelector("#errors")
|
||||||
|
@ -318,7 +383,14 @@ class Vail {
|
||||||
wsMessage(event) {
|
wsMessage(event) {
|
||||||
let now = Date.now()
|
let now = Date.now()
|
||||||
let jmsg = event.data
|
let jmsg = event.data
|
||||||
let msg = JSON.parse(jmsg)
|
let msg
|
||||||
|
try {
|
||||||
|
msg = JSON.parse(jmsg)
|
||||||
|
}
|
||||||
|
catch(err) {
|
||||||
|
console.log(err, msg)
|
||||||
|
return
|
||||||
|
}
|
||||||
let beginTxTime = msg[0]
|
let beginTxTime = msg[0]
|
||||||
let durations = msg.slice(1)
|
let durations = msg.slice(1)
|
||||||
|
|
||||||
|
@ -352,6 +424,14 @@ class Vail {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
straightKey(begin) {
|
||||||
|
if (begin) {
|
||||||
|
this.beginTx()
|
||||||
|
} else {
|
||||||
|
this.endTx()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
key(event) {
|
key(event) {
|
||||||
if (event.repeat) {
|
if (event.repeat) {
|
||||||
// Ignore key repeats generated by the OS, we do this ourselves
|
// Ignore key repeats generated by the OS, we do this ourselves
|
||||||
|
@ -388,11 +468,7 @@ class Vail {
|
||||||
} else if (event.target.id == "dit") {
|
} else if (event.target.id == "dit") {
|
||||||
this.iambic.Key(begin, DIT)
|
this.iambic.Key(begin, DIT)
|
||||||
} else if (event.target.id == "key") {
|
} else if (event.target.id == "key") {
|
||||||
if (begin) {
|
this.straightKey(begin)
|
||||||
this.beginTx()
|
|
||||||
} else {
|
|
||||||
this.endTx()
|
|
||||||
}
|
|
||||||
} else if (event.target.id == "ck") {
|
} else if (event.target.id == "ck") {
|
||||||
this.Test()
|
this.Test()
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue