forked from benna100/duplo-train-voice-control
-
Notifications
You must be signed in to change notification settings - Fork 0
/
index.js
114 lines (90 loc) · 3.04 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
import { PitchDetector } from "https://esm.sh/pitchy@4";
const MIN_TRAIN_SPEED = 25;
const MAX_TRAIN_SPEED = 100;
const MIN_VOICE_FREQUENCY = 80;
const MAX_VOICE_FREQUENCY = 700;
let pitches = [];
let clarities = [];
let characteristic;
function updatePitch(analyserNode, detector, input, sampleRate) {
analyserNode.getFloatTimeDomainData(input);
const [pitch, clarity] = detector.findPitch(input, sampleRate);
pitches.push(pitch);
clarities.push(clarity);
window.setTimeout(
() => updatePitch(analyserNode, detector, input, sampleRate),
10
);
}
const speedTag = document.querySelector("p.speed");
const p = document.querySelector("p.success");
async function connect() {
try {
let device = await navigator.bluetooth.requestDevice({
filters: [
{
services: ["00001623-1212-efde-1623-785feabcd123"],
},
],
});
let server = await device.gatt.connect();
let service = await server.getPrimaryService(
"00001623-1212-efde-1623-785feabcd123"
);
characteristic = await service.getCharacteristic(
"00001624-1212-efde-1623-785feabcd123"
);
} catch (e) {
alert(e);
}
p.innerText = "Successfully connected to train 🥳";
const average = (array) => array.reduce((a, b) => a + b) / array.length;
setInterval(() => {
const averagePitch = average(pitches);
const avegareClarity = average(clarities);
console.log(parseInt(averagePitch), avegareClarity);
const roundedPitch = Math.round(averagePitch * 10) / 10;
const scaledPitchForDuploTrain = d3
.scaleLinear()
.domain([MIN_VOICE_FREQUENCY, MAX_VOICE_FREQUENCY])
.range([MIN_TRAIN_SPEED, MAX_TRAIN_SPEED]);
pitches = [];
clarities = [];
const scaledPitch =
avegareClarity > 0.8 ? scaledPitchForDuploTrain(averagePitch) : -100;
if (scaledPitch > 0 && scaledPitch < 100) {
drive(scaledPitch);
speedTag.innerText = `The speed is ${scaledPitch}`;
} else {
drive(0);
speedTag.innerText = `The speed is 0`;
}
}, 300);
}
function drive(speed) {
write([0x81, 0x00, 0x00, 0x51, 0x00, speed]);
}
function write(data) {
var message = new Int8Array(2 + data.length);
message[0] = message.length;
message.set(data, 2);
characteristic.writeValue(message);
}
const buttonListen = document.querySelector("button.listen");
buttonListen.addEventListener("click", () => {
const audioContext = new window.AudioContext();
const analyserNode = audioContext.createAnalyser();
audioContext.resume();
navigator.mediaDevices.getUserMedia({ audio: true }).then((stream) => {
audioContext.createMediaStreamSource(stream).connect(analyserNode);
const detector = PitchDetector.forFloat32Array(analyserNode.fftSize);
const input = new Float32Array(detector.inputLength);
updatePitch(analyserNode, detector, input, audioContext.sampleRate);
});
buttonListen.disabled = true;
});
const buttonConnect = document.querySelector("button.connect");
buttonConnect.addEventListener("click", () => {
connect();
buttonConnect.disabled = true;
});