Skip to content

Commit 223542d

Browse files
committed
Mic sound visualisation
1 parent 26b426a commit 223542d

File tree

6 files changed

+133
-4
lines changed

6 files changed

+133
-4
lines changed

.dockerignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
.git
22
venv
3+
.venv
34
.idea
45
.ssl
56
__pycache__

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
venv
2+
.venv
23
.idea
34
ssl
45
__pycache__

app/static/css/training.css

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
}
2121
.tutorButtons{
2222
width: 80px;
23-
height 30px;
23+
height: 30px;
2424
}
2525
.model {
2626
display: none;
@@ -37,7 +37,7 @@
3737
background-color: #f2dede;
3838
margin: 15% auto;
3939
padding: 20px;
40-
border: 1px solid #ebccd;
40+
border: 1px solid #ebccd0;
4141
width: 50%;
4242
text-align: center;
4343
color: #a94442;
@@ -47,11 +47,13 @@
4747
display: flex;
4848
font-size: 18px;
4949
margin-top: 1%;
50+
align-items: center;
51+
gap: 30px;
5052
}
5153
.pulse{
5254
position: relative;
5355
text-align: center;
54-
left: 25px;
56+
/* left: 25px; */
5557
border-radius: 50%;
5658
background: #ff0000;
5759
width: 20px;

app/static/js/recording.js

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,9 +56,13 @@ function startRecording() {
5656
time++;
5757
}, 1000);
5858
}, 3000);
59+
5960
let audioContext = new window.AudioContext();
6061
gumStream = stream;
6162
input = audioContext.createMediaStreamSource(stream);
63+
64+
startMicVisualizer(stream, audioContext);
65+
6266
recorder = new WebAudioRecorder(input, {
6367
workerDir: "/static/js/libraries/WebAudioRecorder.js/",
6468
encoding: "mp3",
@@ -126,3 +130,91 @@ $(document).ready(function () {
126130
return "Do you really want to close?";
127131
};
128132
});
133+
134+
function startMicVisualizer (stream, audioContext) {
135+
const canvasElement = document.querySelector("#mic-visualizer-canvas");
136+
const canvasVisializerCxt = canvasElement.getContext("2d");
137+
const volumeLevelElement = document.querySelector("#volume-level-box");
138+
139+
const audioStream = audioContext.createMediaStreamSource( stream );
140+
const analyser = audioContext.createAnalyser();
141+
const fftSize = 128;
142+
143+
analyser.fftSize = fftSize;
144+
audioStream.connect(analyser);
145+
146+
const bufferLength = analyser.frequencyBinCount;
147+
148+
let frequencyArray = new Uint8Array(bufferLength);
149+
150+
const setUpCanvas = function () {
151+
canvasVisializerCxt.fillStyle = "rgb(255 255 255)";
152+
canvasVisializerCxt.fillRect(0, 0, canvasElement.width, canvasElement.height);
153+
154+
canvasVisializerCxt.lineWidth = 1.5;
155+
canvasVisializerCxt.strokeStyle = "rgb(0 0 0)";
156+
157+
canvasVisializerCxt.beginPath();
158+
}
159+
160+
const doDraw = function () {
161+
requestAnimationFrame(doDraw);
162+
163+
setUpCanvas();
164+
165+
const sliceWidth = (canvasElement.width * 1.0) / (bufferLength + 1);
166+
167+
canvasVisializerCxt.moveTo(0, canvasElement.height / 2);
168+
169+
let x = 0 + sliceWidth;
170+
171+
analyser.getByteFrequencyData(frequencyArray);
172+
173+
let direction = 1;
174+
175+
for (let i = 0; i < bufferLength; i++) {
176+
const v = frequencyArray[i] / (canvasElement.height * 2);
177+
const y = (v * canvasElement.height) / 2;
178+
179+
canvasVisializerCxt.lineTo(x, canvasElement.height / 2 + y * direction);
180+
181+
x += sliceWidth;
182+
direction *= -1;
183+
}
184+
185+
canvasVisializerCxt.lineTo(canvasElement.width, canvasElement.height / 2);
186+
canvasVisializerCxt.stroke();
187+
}
188+
189+
const showVolume = function () {
190+
setTimeout(showVolume, 500);
191+
192+
analyser.getByteFrequencyData(frequencyArray);
193+
let total = 0
194+
195+
for(let i = 0; i < bufferLength; i++) {
196+
let x = frequencyArray[i];
197+
total += x * x;
198+
}
199+
200+
const rms = Math.sqrt(total / bufferLength);
201+
let db = 20 * ( Math.log(rms) / Math.log(10) );
202+
203+
db = Math.max(db, 0);
204+
205+
let status = "";
206+
207+
// добавить эти поля в локаль
208+
if (db == 0) {
209+
status = "Ваш микрофон не работает";
210+
}
211+
else if (db <= 35) { // или другое значение/проверка (например только по средним частотам)
212+
status = "Пожалуйста, говорите громче"; // проверить, что пауза достаточно продолжительна
213+
}
214+
215+
volumeLevelElement.innerHTML = `db: ${db.toFixed(1)} ${status}`;
216+
}
217+
218+
doDraw();
219+
showVolume();
220+
}

app/templates/training.html

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@
1919
<div id="record-contain" style="display: none;">
2020
Идёт запись
2121
<div class="pulse"></div>
22-
22+
<canvas id="mic-visualizer-canvas" width="128" height="96"></canvas>
23+
<span id="volume-level-box"></span>
2324
</div>
2425

2526
<div id="controls">

app_conf/no_docker.ini

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
[constants]
2+
presentation_file_max_size_in_megabytes=16
3+
app_secret_key=secret_key_placeholder
4+
lti_consumer_key=secretconsumerkey
5+
lti_consumer_secret=supersecretconsumersecret
6+
version_file=VERSION.json
7+
backup_path=../dump/database-dump/
8+
9+
[mongodb]
10+
url=mongodb://localhost:27017/
11+
database_name=database
12+
13+
[vosk]
14+
url=ws://localhost:2700
15+
16+
[whisper]
17+
url=http://whisper:9000/asr
18+
19+
[user_agent_platform]
20+
windows=True
21+
linux=True
22+
23+
[user_agent_browser]
24+
chrome=89
25+
firefox=87
26+
27+
[locale]
28+
language=ru
29+
30+
[bugreport]
31+
form_link=https://docs.google.com/forms/d/e/1FAIpQLScUudcDPUwtTvmN_sbeljicHYhubK7pPQIM1o8Wh54HstT2BQ/viewform?usp=sf_link
32+

0 commit comments

Comments
 (0)