-
Notifications
You must be signed in to change notification settings - Fork 4
/
index.html
329 lines (245 loc) · 11.1 KB
/
index.html
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
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=0">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="assets/css/w3.css">
<link rel="stylesheet" href="assets/css/w3-theme-black.css">
<link rel="stylesheet" href="assets/css/main.css">
<title>Formant Analyzer</title>
</head>
<body class="w3-black">
<div class="topnav">
<a href="https://github.com/tabahi/formantanalyzer.js">Github</a>
</div>
<div class="w3-container w3-center w3-opacity">
<h5 id="app_title">Formant Analyzer</h5>
</div>
<div class="w3-container w3-bottombar w3-border-dark-gray"> <!-- Main body container -->
<div class="w3-row w3-center w3-animate-zoom" id="canvas_div">
<canvas id="SpectrumCanvas" width="1200" height="300" ></canvas>
</div>
<div class="w3-row w3-center">
<p id="msg">Press Mic</p>
</div>
<div class="w3-row w3-center w3-padding-small"> <!-- Buttons -->
<div class="w3-col m6">
<div id="dropZone" class="w3-card-4">
<label for="filesx" class="w3-hover-text-amber">Load Audio: </label>
<input type="file" id="filesx" name="filesx[]" onchange="readmultifiles(this.files)" multiple="" class="w3-button w3-hover-border-khaki w3-padding" placeholder="Audio files" accept="audio/*" />
<input type="button" id="play_button" value="Play" class="w3-button w3-wide w3-border w3-border-light-blue w3-padding">
</div>
</div>
<div class="w3-col m2">
<input type="button" id="mic_button" value="Mic" class="w3-button w3-wide w3-border w3-border-amber w3-padding">
</div>
<div class="w3-col m4">
<select class="w3-select w3-dark-input" id="output_level" style="width:95%">
<option value="0" disabled>Output Level</option>
<option value="1">Bars</option>
<option value="2" selected>Spectrum</option>
<option value="3">Segments</option>
<option value="4">Segment Formants</option>
<option value="5">Segment Features [ML]</option>
<option value="10">Syllable Formants </option>
<option value="11">Distributions 264x [ML]</option>
<option value="12">Syllable Curves 23x [ML]</option>
<option value="13">Syllable 53x [ML]</option>
</select>
</div>
</div>
<div class="w3-row w3-center w3-padding-small"> <!-- File loading zone -->
</div>
</div> <!-- Main body container ends -->
<div class="footer">
<a href="https://github.com/tabahi/formantanalyzer.js/blob/main/index.html">
<span>Formant Analyzer bare minium starter file</span>
</a>
</div>
<script src="https://unpkg.com/[email protected]/index.js"></script>
<script>
var play_status = { playing:false, files_processed:0, current_file_index:0, Source:1 };
var loaded_files = null;
function Configure_FormantAnalyzer()
{
const BOX_HEIGHT = 300;
const BOX_WIDTH = window.innerWidth - 50; //reset the size of canvas element using the screen width
document.getElementById('SpectrumCanvas').width = BOX_WIDTH;
document.getElementById('SpectrumCanvas').height = BOX_HEIGHT;
let launch_config = { plot_enable: true,
spec_type: 1,
output_level: document.getElementById('output_level').value,
plot_len: 200,
f_min: 50,
f_max: 4000,
N_fft_bins: 256,
N_mel_bins: 128,
window_width: 25,
window_step: 15,
pause_length: 200,
min_seg_length: 500,
auto_noise_gate: true,
voiced_min_dB: 10,
voiced_max_dB: 100,
plot_lag: 1,
pre_norm_gain: 1000,
high_f_emph: 0.0,
plot_canvas: document.querySelector('#SpectrumCanvas').getContext('2d'),
canvas_width: BOX_WIDTH,
canvas_height: BOX_HEIGHT };
FormantAnalyzer.configure(launch_config);
}
/*This function is called asynchronously after each segment or syllable depending on the output level. si is the index of segment/syllable out of all since reset*/
async function call_backed(seg_index, seg_label, seg_time, extracted_features)
{
console.log(seg_index, seg_label, seg_time);
//console.log(extracted_features);
return;
}
document.querySelector('#mic_button').addEventListener('click', function(e) {
e.preventDefault();
play_status.Source = 3;
if(play_status.playing == false)
{
document.getElementById('msg').textContent = "Streaming from mic...";
disable_buttons(true);
document.getElementById("mic_button").value = "...";
document.getElementById("mic_button").value = "Stop";
document.getElementById("mic_button").disabled = false;
play_status.playing = true;
Configure_FormantAnalyzer();
FormantAnalyzer.LaunchAudioNodes(3, null, call_backed, ['mic'], false, false, null, null).then(function()
{
stop_playing("End sop play");
}).catch((err)=>{
console.log(err);
stop_playing("Error during play start");
document.getElementById('msg').textContent = "Error streaming";
});
}
else
{
stop_playing("Button pressed");
document.getElementById('msg').textContent = "Stopped";
}
});
document.querySelector('#play_button').addEventListener('click', function(e) {
e.preventDefault();
play_status.Source = 1;
if(play_status.playing)
{
stop_playing("Button pressed");
document.getElementById('msg').textContent = "Stopped";
}
else
{
if(!loaded_files)
{
document.getElementById('msg').textContent = "No files selected to play";
}
else
{
disable_buttons(true);
play_status.current_file_index = 0;
play_status.files_processed = 0;
if(PlayNextFile())
{
play_status.playing = true;
document.getElementById("play_button").value = "Stop";
document.getElementById("play_button").disabled = false;
document.getElementById('msg').textContent = "Playing";
}
}
}
});
function PlayNextFile() //play the files loaded in drop zone queue
{
//This function plays all the loaded files. After each file it calls 'finished_file_play()', which recursively calls this function again until it reaches the end
if(play_status.current_file_index >= loaded_files.length)
return false;
let reader = new FileReader();
//let this_file = loaded_files[play_status.current_file_index];
reader.onload = function(e)
{
let this_file_name = loaded_files[play_status.current_file_index].name;
let mimeType= loaded_files[play_status.current_file_index].type;
if(mimeType.includes("audio/") || mimeType.includes("video/"))
{
//let this_file_bin = e.target.result;
document.getElementById('msg').textContent = "Playing file " + String(play_status.current_file_index+1) + "/" + String(loaded_files.length) + ', ' + this_file_name;
Configure_FormantAnalyzer();
FormantAnalyzer.LaunchAudioNodes(1, e.target.result, call_backed, [this_file_name], false, false, null, null).then(function()
{
e = null; //clear memory
reader = null;
stop_playing("Finished processing all files");
document.getElementById('msg').textContent = "Finished playing " + String(play_status.files_processed) + " files";
return true;
}).catch((err)=>{
console.log(err);
e = null; //clear memory
reader = null;
stop_playing("Error during play start");
document.getElementById('msg').textContent = "Error playing: " + String(this_file_name);
return false;
});
}
else
{
document.getElementById('msg').textContent = "Invalid format: " + String(this_file_name) + ", " + String(mimeType);
return false;
}
}
reader.readAsArrayBuffer(loaded_files[play_status.current_file_index]); //read binary of audio file
return true;
}
function stop_playing(reason)
{
play_status.playing = false;
FormantAnalyzer.StopAudioNodes(reason);
document.getElementById("play_button").value = "Play";
document.getElementById("mic_button").value = "Mic";
document.getElementById("play_button").disabled = false;
document.getElementById("mic_button").disabled = false;
}
function disable_buttons(disable)
{
document.getElementById("play_button").disabled = disable;
document.getElementById("mic_button").disabled = disable;
}
/* Unrelated File loading functions */
function readmultifiles(files)
{
if(play_status.playing) stop_playing("New file loaded");
loaded_files = null;
play_status.current_file_index = 0;
play_status.files_processed = 0;
loaded_files = files;
document.getElementById('msg').textContent = "Total " + String(loaded_files.length) + " files loaded";
}
var handleDragOver = function(e) {
e.preventDefault();
e.stopPropagation();
e.dataTransfer.dropEffect = 'copy';
}
var handleDrop = function(e) {
e.preventDefault()
e.stopPropagation()
readmultifiles(e.dataTransfer.files);
}
function init_drag_and_drop() //initialize drag and drop zone elements
{
if (window.File && window.FileReader && window.FileList && window.Blob) {
//All the File APIs are supported.
} else {
console.warn('The Drag and Drop File APIs are not fully supported in this browser.');
}
const dropzone_div = document.getElementById('dropZone');
dropzone_div.addEventListener('drop', handleDrop, false);
dropzone_div.addEventListener('dragover', handleDragOver, false);
}
init_drag_and_drop();
</script>
</body>
</html>