aavi21458 commited on
Commit
a3548c7
·
verified ·
1 Parent(s): 0a47cfa

Upload folder using huggingface_hub

Browse files
Files changed (1) hide show
  1. index.html +1218 -19
index.html CHANGED
@@ -1,19 +1,1218 @@
1
- <!doctype html>
2
- <html>
3
- <head>
4
- <meta charset="utf-8" />
5
- <meta name="viewport" content="width=device-width" />
6
- <title>My static Space</title>
7
- <link rel="stylesheet" href="style.css" />
8
- </head>
9
- <body>
10
- <div class="card">
11
- <h1>Welcome to your static Space!</h1>
12
- <p>You can modify this app directly by editing <i>index.html</i> in the Files and versions tab.</p>
13
- <p>
14
- Also don't forget to check the
15
- <a href="https://huggingface.co/docs/hub/spaces" target="_blank">Spaces documentation</a>.
16
- </p>
17
- </div>
18
- </body>
19
- </html>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Noise Reducer - Remove Crowd Noise</title>
7
+ <link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap" rel="stylesheet">
8
+ <style>
9
+ :root {
10
+ --primary: #6366f1;
11
+ --primary-hover: #4f46e5;
12
+ --secondary: #10b981;
13
+ --bg-dark: #0f172a;
14
+ --bg-card: #1e293b;
15
+ --bg-card-hover: #334155;
16
+ --text-primary: #f8fafc;
17
+ --text-secondary: #94a3b8;
18
+ --border: #334155;
19
+ --gradient-1: #6366f1;
20
+ --gradient-2: #8b5cf6;
21
+ --gradient-3: #06b6d4;
22
+ }
23
+
24
+ * {
25
+ margin: 0;
26
+ padding: 0;
27
+ box-sizing: border-box;
28
+ }
29
+
30
+ body {
31
+ font-family: 'Inter', sans-serif;
32
+ background: var(--bg-dark);
33
+ color: var(--text-primary);
34
+ min-height: 100vh;
35
+ overflow-x: hidden;
36
+ }
37
+
38
+ /* Animated Background */
39
+ .bg-pattern {
40
+ position: fixed;
41
+ top: 0;
42
+ left: 0;
43
+ width: 100%;
44
+ height: 100%;
45
+ z-index: -1;
46
+ background:
47
+ radial-gradient(ellipse at 20% 20%, rgba(99, 102, 241, 0.15) 0%, transparent 50%),
48
+ radial-gradient(ellipse at 80% 80%, rgba(139, 92, 246, 0.1) 0%, transparent 50%),
49
+ radial-gradient(ellipse at 50% 50%, rgba(6, 182, 212, 0.05) 0%, transparent 70%);
50
+ }
51
+
52
+ .container {
53
+ max-width: 900px;
54
+ margin: 0 auto;
55
+ padding: 2rem 1.5rem;
56
+ }
57
+
58
+ /* Header */
59
+ header {
60
+ text-align: center;
61
+ margin-bottom: 3rem;
62
+ }
63
+
64
+ .logo {
65
+ display: inline-flex;
66
+ align-items: center;
67
+ gap: 0.75rem;
68
+ margin-bottom: 1rem;
69
+ }
70
+
71
+ .logo-icon {
72
+ width: 48px;
73
+ height: 48px;
74
+ background: linear-gradient(135deg, var(--gradient-1), var(--gradient-2));
75
+ border-radius: 12px;
76
+ display: flex;
77
+ align-items: center;
78
+ justify-content: center;
79
+ box-shadow: 0 8px 32px rgba(99, 102, 241, 0.3);
80
+ }
81
+
82
+ .logo-icon svg {
83
+ width: 28px;
84
+ height: 28px;
85
+ color: white;
86
+ }
87
+
88
+ h1 {
89
+ font-size: 2.5rem;
90
+ font-weight: 700;
91
+ background: linear-gradient(135deg, var(--text-primary), var(--text-secondary));
92
+ -webkit-background-clip: text;
93
+ -webkit-text-fill-color: transparent;
94
+ background-clip: text;
95
+ margin-bottom: 0.5rem;
96
+ }
97
+
98
+ .subtitle {
99
+ color: var(--text-secondary);
100
+ font-size: 1.1rem;
101
+ }
102
+
103
+ .built-with {
104
+ display: inline-flex;
105
+ align-items: center;
106
+ gap: 0.5rem;
107
+ margin-top: 1rem;
108
+ padding: 0.5rem 1rem;
109
+ background: rgba(99, 102, 241, 0.1);
110
+ border: 1px solid rgba(99, 102, 241, 0.2);
111
+ border-radius: 20px;
112
+ font-size: 0.85rem;
113
+ color: var(--primary);
114
+ text-decoration: none;
115
+ transition: all 0.3s ease;
116
+ }
117
+
118
+ .built-with:hover {
119
+ background: rgba(99, 102, 241, 0.2);
120
+ transform: translateY(-2px);
121
+ }
122
+
123
+ /* Main Card */
124
+ .main-card {
125
+ background: var(--bg-card);
126
+ border-radius: 24px;
127
+ padding: 2rem;
128
+ border: 1px solid var(--border);
129
+ box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.5);
130
+ }
131
+
132
+ /* Upload Section */
133
+ .upload-section {
134
+ border: 2px dashed var(--border);
135
+ border-radius: 16px;
136
+ padding: 3rem 2rem;
137
+ text-align: center;
138
+ cursor: pointer;
139
+ transition: all 0.3s ease;
140
+ position: relative;
141
+ overflow: hidden;
142
+ }
143
+
144
+ .upload-section::before {
145
+ content: '';
146
+ position: absolute;
147
+ inset: 0;
148
+ background: linear-gradient(135deg, rgba(99, 102, 241, 0.1), rgba(139, 92, 246, 0.05));
149
+ opacity: 0;
150
+ transition: opacity 0.3s ease;
151
+ }
152
+
153
+ .upload-section:hover::before,
154
+ .upload-section.drag-over::before {
155
+ opacity: 1;
156
+ }
157
+
158
+ .upload-section:hover,
159
+ .upload-section.drag-over {
160
+ border-color: var(--primary);
161
+ transform: scale(1.01);
162
+ }
163
+
164
+ .upload-icon {
165
+ width: 64px;
166
+ height: 64px;
167
+ margin: 0 auto 1rem;
168
+ background: linear-gradient(135deg, var(--gradient-1), var(--gradient-3));
169
+ border-radius: 50%;
170
+ display: flex;
171
+ align-items: center;
172
+ justify-content: center;
173
+ box-shadow: 0 8px 32px rgba(99, 102, 241, 0.3);
174
+ }
175
+
176
+ .upload-icon svg {
177
+ width: 32px;
178
+ height: 32px;
179
+ color: white;
180
+ }
181
+
182
+ .upload-text {
183
+ font-size: 1.1rem;
184
+ margin-bottom: 0.5rem;
185
+ }
186
+
187
+ .upload-hint {
188
+ color: var(--text-secondary);
189
+ font-size: 0.9rem;
190
+ }
191
+
192
+ .file-types {
193
+ display: flex;
194
+ justify-content: center;
195
+ gap: 0.5rem;
196
+ margin-top: 1rem;
197
+ }
198
+
199
+ .file-type-badge {
200
+ padding: 0.25rem 0.75rem;
201
+ background: rgba(99, 102, 241, 0.15);
202
+ border-radius: 12px;
203
+ font-size: 0.75rem;
204
+ font-weight: 600;
205
+ color: var(--primary);
206
+ text-transform: uppercase;
207
+ }
208
+
209
+ #fileInput {
210
+ display: none;
211
+ }
212
+
213
+ /* File Info */
214
+ .file-info {
215
+ display: none;
216
+ margin-top: 1.5rem;
217
+ padding: 1rem;
218
+ background: rgba(99, 102, 241, 0.1);
219
+ border-radius: 12px;
220
+ border: 1px solid rgba(99, 102, 241, 0.2);
221
+ }
222
+
223
+ .file-info.active {
224
+ display: flex;
225
+ align-items: center;
226
+ gap: 1rem;
227
+ }
228
+
229
+ .file-icon {
230
+ width: 40px;
231
+ height: 40px;
232
+ background: var(--primary);
233
+ border-radius: 8px;
234
+ display: flex;
235
+ align-items: center;
236
+ justify-content: center;
237
+ }
238
+
239
+ .file-details {
240
+ flex: 1;
241
+ }
242
+
243
+ .file-name {
244
+ font-weight: 600;
245
+ margin-bottom: 0.25rem;
246
+ }
247
+
248
+ .file-size {
249
+ font-size: 0.85rem;
250
+ color: var(--text-secondary);
251
+ }
252
+
253
+ .remove-file {
254
+ width: 32px;
255
+ height: 32px;
256
+ background: rgba(239, 68, 68, 0.2);
257
+ border: none;
258
+ border-radius: 8px;
259
+ color: #ef4444;
260
+ cursor: pointer;
261
+ display: flex;
262
+ align-items: center;
263
+ justify-content: center;
264
+ transition: all 0.2s ease;
265
+ }
266
+
267
+ .remove-file:hover {
268
+ background: rgba(239, 68, 68, 0.3);
269
+ }
270
+
271
+ /* Controls Section */
272
+ .controls-section {
273
+ margin-top: 2rem;
274
+ padding-top: 2rem;
275
+ border-top: 1px solid var(--border);
276
+ display: none;
277
+ }
278
+
279
+ .controls-section.active {
280
+ display: block;
281
+ animation: fadeIn 0.5s ease;
282
+ }
283
+
284
+ @keyframes fadeIn {
285
+ from { opacity: 0; transform: translateY(10px); }
286
+ to { opacity: 1; transform: translateY(0); }
287
+ }
288
+
289
+ .control-group {
290
+ margin-bottom: 1.5rem;
291
+ }
292
+
293
+ .control-label {
294
+ display: flex;
295
+ justify-content: space-between;
296
+ align-items: center;
297
+ margin-bottom: 0.75rem;
298
+ }
299
+
300
+ .control-label span {
301
+ font-weight: 500;
302
+ }
303
+
304
+ .control-value {
305
+ font-size: 0.85rem;
306
+ color: var(--primary);
307
+ font-weight: 600;
308
+ }
309
+
310
+ /* Custom Range Slider */
311
+ input[type="range"] {
312
+ width: 100%;
313
+ height: 8px;
314
+ -webkit-appearance: none;
315
+ background: var(--bg-dark);
316
+ border-radius: 4px;
317
+ outline: none;
318
+ }
319
+
320
+ input[type="range"]::-webkit-slider-thumb {
321
+ -webkit-appearance: none;
322
+ width: 20px;
323
+ height: 20px;
324
+ background: linear-gradient(135deg, var(--gradient-1), var(--gradient-2));
325
+ border-radius: 50%;
326
+ cursor: pointer;
327
+ box-shadow: 0 4px 12px rgba(99, 102, 241, 0.4);
328
+ transition: transform 0.2s ease;
329
+ }
330
+
331
+ input[type="range"]::-webkit-slider-thumb:hover {
332
+ transform: scale(1.1);
333
+ }
334
+
335
+ input[type="range"]::-moz-range-thumb {
336
+ width: 20px;
337
+ height: 20px;
338
+ background: linear-gradient(135deg, var(--gradient-1), var(--gradient-2));
339
+ border-radius: 50%;
340
+ cursor: pointer;
341
+ border: none;
342
+ }
343
+
344
+ /* Buttons */
345
+ .btn {
346
+ display: inline-flex;
347
+ align-items: center;
348
+ justify-content: center;
349
+ gap: 0.5rem;
350
+ padding: 1rem 2rem;
351
+ border-radius: 12px;
352
+ font-size: 1rem;
353
+ font-weight: 600;
354
+ cursor: pointer;
355
+ transition: all 0.3s ease;
356
+ border: none;
357
+ text-decoration: none;
358
+ }
359
+
360
+ .btn-primary {
361
+ width: 100%;
362
+ background: linear-gradient(135deg, var(--gradient-1), var(--gradient-2));
363
+ color: white;
364
+ box-shadow: 0 8px 24px rgba(99, 102, 241, 0.3);
365
+ }
366
+
367
+ .btn-primary:hover {
368
+ transform: translateY(-2px);
369
+ box-shadow: 0 12px 32px rgba(99, 102, 241, 0.4);
370
+ }
371
+
372
+ .btn-primary:disabled {
373
+ opacity: 0.5;
374
+ cursor: not-allowed;
375
+ transform: none;
376
+ }
377
+
378
+ .btn-secondary {
379
+ background: var(--bg-card-hover);
380
+ color: var(--text-primary);
381
+ border: 1px solid var(--border);
382
+ }
383
+
384
+ .btn-secondary:hover {
385
+ background: var(--border);
386
+ }
387
+
388
+ /* Progress Section */
389
+ .progress-section {
390
+ display: none;
391
+ margin-top: 2rem;
392
+ }
393
+
394
+ .progress-section.active {
395
+ display: block;
396
+ }
397
+
398
+ .progress-container {
399
+ background: var(--bg-dark);
400
+ border-radius: 12px;
401
+ padding: 1.5rem;
402
+ text-align: center;
403
+ }
404
+
405
+ .progress-text {
406
+ margin-bottom: 1rem;
407
+ font-weight: 500;
408
+ }
409
+
410
+ .progress-bar {
411
+ width: 100%;
412
+ height: 8px;
413
+ background: var(--bg-card-hover);
414
+ border-radius: 4px;
415
+ overflow: hidden;
416
+ }
417
+
418
+ .progress-fill {
419
+ height: 100%;
420
+ background: linear-gradient(90deg, var(--gradient-1), var(--gradient-2), var(--gradient-3));
421
+ border-radius: 4px;
422
+ transition: width 0.3s ease;
423
+ position: relative;
424
+ }
425
+
426
+ .progress-fill::after {
427
+ content: '';
428
+ position: absolute;
429
+ top: 0;
430
+ left: 0;
431
+ right: 0;
432
+ bottom: 0;
433
+ background: linear-gradient(90deg, transparent, rgba(255,255,255,0.3), transparent);
434
+ animation: shimmer 1.5s infinite;
435
+ }
436
+
437
+ @keyframes shimmer {
438
+ 0% { transform: translateX(-100%); }
439
+ 100% { transform: translateX(100%); }
440
+ }
441
+
442
+ .progress-steps {
443
+ display: flex;
444
+ justify-content: space-between;
445
+ margin-top: 1rem;
446
+ font-size: 0.8rem;
447
+ color: var(--text-secondary);
448
+ }
449
+
450
+ .progress-step {
451
+ display: flex;
452
+ align-items: center;
453
+ gap: 0.5rem;
454
+ opacity: 0.5;
455
+ transition: opacity 0.3s ease;
456
+ }
457
+
458
+ .progress-step.active {
459
+ opacity: 1;
460
+ color: var(--primary);
461
+ }
462
+
463
+ .progress-step.completed {
464
+ opacity: 1;
465
+ color: var(--secondary);
466
+ }
467
+
468
+ /* Results Section */
469
+ .results-section {
470
+ display: none;
471
+ margin-top: 2rem;
472
+ }
473
+
474
+ .results-section.active {
475
+ display: block;
476
+ animation: fadeIn 0.5s ease;
477
+ }
478
+
479
+ .result-card {
480
+ background: var(--bg-dark);
481
+ border-radius: 16px;
482
+ padding: 1.5rem;
483
+ margin-bottom: 1rem;
484
+ }
485
+
486
+ .result-header {
487
+ display: flex;
488
+ align-items: center;
489
+ gap: 1rem;
490
+ margin-bottom: 1rem;
491
+ }
492
+
493
+ .result-icon {
494
+ width: 48px;
495
+ height: 48px;
496
+ background: linear-gradient(135deg, var(--secondary), #059669);
497
+ border-radius: 12px;
498
+ display: flex;
499
+ align-items: center;
500
+ justify-content: center;
501
+ }
502
+
503
+ .result-icon svg {
504
+ width: 24px;
505
+ height: 24px;
506
+ color: white;
507
+ }
508
+
509
+ .result-title {
510
+ font-size: 1.25rem;
511
+ font-weight: 600;
512
+ }
513
+
514
+ .result-subtitle {
515
+ font-size: 0.85rem;
516
+ color: var(--text-secondary);
517
+ }
518
+
519
+ /* Audio Player */
520
+ .audio-player {
521
+ background: var(--bg-card);
522
+ border-radius: 12px;
523
+ padding: 1rem;
524
+ margin-bottom: 1rem;
525
+ }
526
+
527
+ .audio-info {
528
+ display: flex;
529
+ justify-content: space-between;
530
+ align-items: center;
531
+ margin-bottom: 1rem;
532
+ }
533
+
534
+ .audio-label {
535
+ font-size: 0.85rem;
536
+ color: var(--text-secondary);
537
+ font-weight: 500;
538
+ }
539
+
540
+ .audio-time {
541
+ font-size: 0.85rem;
542
+ color: var(--text-secondary);
543
+ }
544
+
545
+ .waveform-container {
546
+ height: 60px;
547
+ background: var(--bg-dark);
548
+ border-radius: 8px;
549
+ margin-bottom: 1rem;
550
+ position: relative;
551
+ overflow: hidden;
552
+ }
553
+
554
+ .waveform-canvas {
555
+ width: 100%;
556
+ height: 100%;
557
+ }
558
+
559
+ .audio-controls {
560
+ display: flex;
561
+ align-items: center;
562
+ gap: 1rem;
563
+ }
564
+
565
+ .play-btn {
566
+ width: 48px;
567
+ height: 48px;
568
+ background: var(--primary);
569
+ border: none;
570
+ border-radius: 50%;
571
+ color: white;
572
+ cursor: pointer;
573
+ display: flex;
574
+ align-items: center;
575
+ justify-content: center;
576
+ transition: all 0.2s ease;
577
+ }
578
+
579
+ .play-btn:hover {
580
+ transform: scale(1.05);
581
+ background: var(--primary-hover);
582
+ }
583
+
584
+ .audio-slider {
585
+ flex: 1;
586
+ }
587
+
588
+ .audio-slider input[type="range"] {
589
+ height: 4px;
590
+ }
591
+
592
+ /* Action Buttons */
593
+ .action-buttons {
594
+ display: flex;
595
+ gap: 1rem;
596
+ }
597
+
598
+ .action-buttons .btn {
599
+ flex: 1;
600
+ }
601
+
602
+ /* Comparison */
603
+ .comparison-toggle {
604
+ display: flex;
605
+ align-items: center;
606
+ gap: 0.75rem;
607
+ margin-bottom: 1rem;
608
+ cursor: pointer;
609
+ }
610
+
611
+ .toggle-switch {
612
+ width: 48px;
613
+ height: 24px;
614
+ background: var(--bg-dark);
615
+ border-radius: 12px;
616
+ position: relative;
617
+ transition: background 0.3s ease;
618
+ }
619
+
620
+ .toggle-switch::after {
621
+ content: '';
622
+ position: absolute;
623
+ width: 20px;
624
+ height: 20px;
625
+ background: white;
626
+ border-radius: 50%;
627
+ top: 2px;
628
+ left: 2px;
629
+ transition: transform 0.3s ease;
630
+ }
631
+
632
+ .comparison-toggle.active .toggle-switch {
633
+ background: var(--primary);
634
+ }
635
+
636
+ .comparison-toggle.active .toggle-switch::after {
637
+ transform: translateX(24px);
638
+ }
639
+
640
+ /* Toast Notification */
641
+ .toast {
642
+ position: fixed;
643
+ bottom: 2rem;
644
+ right: 2rem;
645
+ background: var(--bg-card);
646
+ border: 1px solid var(--border);
647
+ border-radius: 12px;
648
+ padding: 1rem 1.5rem;
649
+ display: flex;
650
+ align-items: center;
651
+ gap: 0.75rem;
652
+ box-shadow: 0 10px 40px rgba(0, 0, 0, 0.4);
653
+ transform: translateY(100px);
654
+ opacity: 0;
655
+ transition: all 0.3s ease;
656
+ z-index: 1000;
657
+ }
658
+
659
+ .toast.show {
660
+ transform: translateY(0);
661
+ opacity: 1;
662
+ }
663
+
664
+ .toast.error {
665
+ border-color: #ef4444;
666
+ }
667
+
668
+ .toast.success {
669
+ border-color: var(--secondary);
670
+ }
671
+
672
+ /* Responsive */
673
+ @media (max-width: 640px) {
674
+ h1 {
675
+ font-size: 1.75rem;
676
+ }
677
+
678
+ .main-card {
679
+ padding: 1.5rem;
680
+ }
681
+
682
+ .upload-section {
683
+ padding: 2rem 1rem;
684
+ }
685
+
686
+ .action-buttons {
687
+ flex-direction: column;
688
+ }
689
+ }
690
+ </style>
691
+ </head>
692
+ <body>
693
+ <div class="bg-pattern"></div>
694
+
695
+ <div class="container">
696
+ <header>
697
+ <div class="logo">
698
+ <div class="logo-icon">
699
+ <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
700
+ <path stroke-linecap="round" stroke-linejoin="round" d="M19.114 5.636a9 9 0 010 12.728M16.463 8.288a5.25 5.25 0 010 7.424M6.75 8.25l4.72-4.72a.75.75 0 011.28.53v15.88a.75.75 0 01-1.28.53l-4.72-4.72H4.51c-.88 0-1.704-.507-1.938-1.354A9.009 9.009 0 012.25 12c0-.83.112-1.633.322-2.396C2.806 8.756 3.63 8.25 4.51 8.25H6.75z" />
701
+ </svg>
702
+ </div>
703
+ <h1>Noise Reducer</h1>
704
+ </div>
705
+ <p class="subtitle">Remove crowd noise from your audio & video files</p>
706
+ <a href="https://huggingface.co/spaces/akhaliq/anycoder" target="_blank" class="built-with">
707
+ Built with anycoder
708
+ </a>
709
+ </header>
710
+
711
+ <main class="main-card">
712
+ <!-- Upload Section -->
713
+ <div class="upload-section" id="uploadSection">
714
+ <div class="upload-icon">
715
+ <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
716
+ <path stroke-linecap="round" stroke-linejoin="round" d="M3 16.5v2.25A2.25 2.25 0 005.25 21h13.5A2.25 2.25 0 0021 18.75V16.5m-13.5-9L12 3m0 0l4.5 4.5M12 3v13.5" />
717
+ </svg>
718
+ </div>
719
+ <p class="upload-text">Drop your file here or click to browse</p>
720
+ <p class="upload-hint">Maximum file size: 100MB</p>
721
+ <div class="file-types">
722
+ <span class="file-type-badge">MP3</span>
723
+ <span class="file-type-badge">MP4</span>
724
+ <span class="file-type-badge">WAV</span>
725
+ <span class="file-type-badge">M4A</span>
726
+ </div>
727
+ <input type="file" id="fileInput" accept=".mp3,.mp4,.wav,.m4a,audio/*,video/*">
728
+ </div>
729
+
730
+ <!-- File Info -->
731
+ <div class="file-info" id="fileInfo">
732
+ <div class="file-icon">
733
+ <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
734
+ <path stroke-linecap="round" stroke-linejoin="round" d="M9 19V6l12-3v13M9 19c0 1.105-1.343 2-3 2s-3-.895-3-2 1.343-2 3-2 3 .895 3 2zm12-3c0 1.105-1.343 2-3 2s-3-.895-3-2 1.343-2 3-2 3 .895 3 2zM9 10l12-3" />
735
+ </svg>
736
+ </div>
737
+ <div class="file-details">
738
+ <div class="file-name" id="fileName">filename.mp3</div>
739
+ <div class="file-size" id="fileSize">0 MB</div>
740
+ </div>
741
+ <button class="remove-file" id="removeFile">
742
+ <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
743
+ <path stroke-linecap="round" stroke-linejoin="round" d="M6 18L18 6M6 6l12 12" />
744
+ </svg>
745
+ </button>
746
+ </div>
747
+
748
+ <!-- Controls Section -->
749
+ <div class="controls-section" id="controlsSection">
750
+ <div class="control-group">
751
+ <div class="control-label">
752
+ <span>Noise Reduction Level</span>
753
+ <span class="control-value" id="noiseLevelValue">50%</span>
754
+ </div>
755
+ <input type="range" id="noiseLevel" min="0" max="100" value="50">
756
+ </div>
757
+
758
+ <div class="control-group">
759
+ <div class="control-label">
760
+ <span>Sensitivity</span>
761
+ <span class="control-value" id="sensitivityValue">Medium</span>
762
+ </div>
763
+ <input type="range" id="sensitivity" min="0" max="100" value="50">
764
+ </div>
765
+
766
+ <div class="comparison-toggle" id="comparisonToggle">
767
+ <div class="toggle-switch"></div>
768
+ <span>Preview original audio</span>
769
+ </div>
770
+
771
+ <button class="btn btn-primary" id="processBtn">
772
+ <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
773
+ <path stroke-linecap="round" stroke-linejoin="round" d="M13 10V3L4 14h7v7l9-11h-7z" />
774
+ </svg>
775
+ Remove Noise
776
+ </button>
777
+ </div>
778
+
779
+ <!-- Progress Section -->
780
+ <div class="progress-section" id="progressSection">
781
+ <div class="progress-container">
782
+ <p class="progress-text" id="progressText">Processing your audio...</p>
783
+ <div class="progress-bar">
784
+ <div class="progress-fill" id="progressFill" style="width: 0%"></div>
785
+ </div>
786
+ <div class="progress-steps">
787
+ <div class="progress-step" id="step1">
788
+ <svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
789
+ <path stroke-linecap="round" stroke-linejoin="round" d="M5 13l4 4L19 7" />
790
+ </svg>
791
+ Analyzing
792
+ </div>
793
+ <div class="progress-step" id="step2">
794
+ <svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
795
+ <path stroke-linecap="round" stroke-linejoin="round" d="M5 13l4 4L19 7" />
796
+ </svg>
797
+ Reducing
798
+ </div>
799
+ <div class="progress-step" id="step3">
800
+ <svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
801
+ <path stroke-linecap="round" stroke-linejoin="round" d="M5 13l4 4L19 7" />
802
+ </svg>
803
+ Finalizing
804
+ </div>
805
+ </div>
806
+ </div>
807
+ </div>
808
+
809
+ <!-- Results Section -->
810
+ <div class="results-section" id="resultsSection">
811
+ <div class="result-card">
812
+ <div class="result-header">
813
+ <div class="result-icon">
814
+ <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
815
+ <path stroke-linecap="round" stroke-linejoin="round" d="M5 3v4M3 5h4M6 17v4m-2-2h4m5-16l2.286 6.857L21 12l-5.714 2.143L13 21l-2.286-6.857L5 12l5.714-2.143L13 3z" />
816
+ </svg>
817
+ </div>
818
+ <div>
819
+ <div class="result-title">Processing Complete!</div>
820
+ <div class="result-subtitle">Your audio has been cleaned</div>
821
+ </div>
822
+ </div>
823
+
824
+ <div class="audio-player">
825
+ <div class="audio-info">
826
+ <span class="audio-label">Original Audio</span>
827
+ <span class="audio-time" id="originalTime">0:00 / 0:00</span>
828
+ </div>
829
+ <div class="waveform-container">
830
+ <canvas class="waveform-canvas" id="originalWaveform"></canvas>
831
+ </div>
832
+ <div class="audio-controls">
833
+ <button class="play-btn" id="playOriginal">
834
+ <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="currentColor" viewBox="0 0 24 24">
835
+ <path d="M8 5v14l11-7z"/>
836
+ </svg>
837
+ </button>
838
+ <div class="audio-slider">
839
+ <input type="range" id="originalSeek" min="0" max="100" value="0">
840
+ </div>
841
+ </div>
842
+ </div>
843
+
844
+ <div class="audio-player">
845
+ <div class="audio-info">
846
+ <span class="audio-label" style="color: var(--secondary);">Processed Audio</span>
847
+ <span class="audio-time" id="processedTime">0:00 / 0:00</span>
848
+ </div>
849
+ <div class="waveform-container">
850
+ <canvas class="waveform-canvas" id="processedWaveform"></canvas>
851
+ </div>
852
+ <div class="audio-controls">
853
+ <button class="play-btn" id="playProcessed" style="background: var(--secondary);">
854
+ <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="currentColor" viewBox="0 0 24 24">
855
+ <path d="M8 5v14l11-7z"/>
856
+ </svg>
857
+ </button>
858
+ <div class="audio-slider">
859
+ <input type="range" id="processedSeek" min="0" max="100" value="0">
860
+ </div>
861
+ </div>
862
+ </div>
863
+
864
+ <div class="action-buttons">
865
+ <button class="btn btn-secondary" id="resetBtn">
866
+ <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
867
+ <path stroke-linecap="round" stroke-linejoin="round" d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15" />
868
+ </svg>
869
+ Start Over
870
+ </button>
871
+ <button class="btn btn-primary" id="downloadBtn">
872
+ <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
873
+ <path stroke-linecap="round" stroke-linejoin="round" d="M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-4l-4 4m0 0l-4-4m4 4V4" />
874
+ </svg>
875
+ Download Processed
876
+ </button>
877
+ </div>
878
+ </div>
879
+ </div>
880
+ </main>
881
+ </div>
882
+
883
+ <!-- Toast Notification -->
884
+ <div class="toast" id="toast">
885
+ <span id="toastMessage">Message</span>
886
+ </div>
887
+
888
+ <script>
889
+ // Application State
890
+ const state = {
891
+ file: null,
892
+ originalAudioBuffer: null,
893
+ processedAudioBuffer: null,
894
+ originalAudio: null,
895
+ processedAudio: null,
896
+ isPlayingOriginal: false,
897
+ isPlayingProcessed: false,
898
+ previewOriginal: false,
899
+ audioContext: null,
900
+ sourceNodes: {
901
+ original: null,
902
+ processed: null
903
+ },
904
+ gainNodes: {
905
+ original: null,
906
+ processed: null
907
+ },
908
+ analyserNodes: {
909
+ original: null,
910
+ processed: null
911
+ }
912
+ };
913
+
914
+ // DOM Elements
915
+ const elements = {
916
+ uploadSection: document.getElementById('uploadSection'),
917
+ fileInput: document.getElementById('fileInput'),
918
+ fileInfo: document.getElementById('fileInfo'),
919
+ fileName: document.getElementById('fileName'),
920
+ fileSize: document.getElementById('fileSize'),
921
+ removeFile: document.getElementById('removeFile'),
922
+ controlsSection: document.getElementById('controlsSection'),
923
+ noiseLevel: document.getElementById('noiseLevel'),
924
+ noiseLevelValue: document.getElementById('noiseLevelValue'),
925
+ sensitivity: document.getElementById('sensitivity'),
926
+ sensitivityValue: document.getElementById('sensitivityValue'),
927
+ comparisonToggle: document.getElementById('comparisonToggle'),
928
+ processBtn: document.getElementById('processBtn'),
929
+ progressSection: document.getElementById('progressSection'),
930
+ progressText: document.getElementById('progressText'),
931
+ progressFill: document.getElementById('progressFill'),
932
+ step1: document.getElementById('step1'),
933
+ step2: document.getElementById('step2'),
934
+ step3: document.getElementById('step3'),
935
+ resultsSection: document.getElementById('resultsSection'),
936
+ playOriginal: document.getElementById('playOriginal'),
937
+ playProcessed: document.getElementById('playProcessed'),
938
+ originalSeek: document.getElementById('originalSeek'),
939
+ processedSeek: document.getElementById('processedSeek'),
940
+ originalTime: document.getElementById('originalTime'),
941
+ processedTime: document.getElementById('processedTime'),
942
+ originalWaveform: document.getElementById('originalWaveform'),
943
+ processedWaveform: document.getElementById('processedWaveform'),
944
+ resetBtn: document.getElementById('resetBtn'),
945
+ downloadBtn: document.getElementById('downloadBtn'),
946
+ toast: document.getElementById('toast'),
947
+ toastMessage: document.getElementById('toastMessage')
948
+ };
949
+
950
+ // Initialize Audio Context
951
+ function initAudioContext() {
952
+ if (!state.audioContext) {
953
+ state.audioContext = new (window.AudioContext || window.webkitAudioContext)();
954
+ }
955
+ }
956
+
957
+ // File Upload Handling
958
+ elements.uploadSection.addEventListener('click', () => elements.fileInput.click());
959
+
960
+ elements.uploadSection.addEventListener('dragover', (e) => {
961
+ e.preventDefault();
962
+ elements.uploadSection.classList.add('drag-over');
963
+ });
964
+
965
+ elements.uploadSection.addEventListener('dragleave', () => {
966
+ elements.uploadSection.classList.remove('drag-over');
967
+ });
968
+
969
+ elements.uploadSection.addEventListener('drop', (e) => {
970
+ e.preventDefault();
971
+ elements.uploadSection.classList.remove('drag-over');
972
+ const file = e.dataTransfer.files[0];
973
+ if (file) handleFileSelect(file);
974
+ });
975
+
976
+ elements.fileInput.addEventListener('change', (e) => {
977
+ const file = e.target.files[0];
978
+ if (file) handleFileSelect(file);
979
+ });
980
+
981
+ function handleFileSelect(file) {
982
+ const validTypes = ['audio/mpeg', 'audio/mp3', 'audio/wav', 'audio/m4a', 'audio/x-m4a', 'video/mp4', 'video/quicktime'];
983
+ const extension = file.name.split('.').pop().toLowerCase();
984
+ const validExtensions = ['mp3', 'mp4', 'wav', 'm4a'];
985
+
986
+ if (!validExtensions.includes(extension)) {
987
+ showToast('Please upload a valid audio or video file (MP3, MP4, WAV, M4A)', 'error');
988
+ return;
989
+ }
990
+
991
+ if (file.size > 100 * 1024 * 1024) {
992
+ showToast('File size exceeds 100MB limit', 'error');
993
+ return;
994
+ }
995
+
996
+ state.file = file;
997
+ elements.fileName.textContent = file.name;
998
+ elements.fileSize.textContent = formatFileSize(file.size);
999
+ elements.fileInfo.classList.add('active');
1000
+ elements.uploadSection.style.display = 'none';
1001
+ elements.controlsSection.classList.add('active');
1002
+
1003
+ // Load audio
1004
+ loadAudioFile(file);
1005
+ }
1006
+
1007
+ function formatFileSize(bytes) {
1008
+ if (bytes < 1024) return bytes + ' B';
1009
+ if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB';
1010
+ return (bytes / (1024 * 1024)).toFixed(1) + ' MB';
1011
+ }
1012
+
1013
+ async function loadAudioFile(file) {
1014
+ try {
1015
+ initAudioContext();
1016
+
1017
+ const arrayBuffer = await file.arrayBuffer();
1018
+ let audioBuffer;
1019
+
1020
+ if (file.type.startsWith('video') || file.name.endsWith('.mp4')) {
1021
+ // Extract audio from video
1022
+ const video = document.createElement('video');
1023
+ video.src = URL.createObjectURL(file);
1024
+ await new Promise(resolve => {
1025
+ video.onloadedmetadata = resolve;
1026
+ });
1027
+
1028
+ // Create offline context to extract audio
1029
+ const offlineContext = new OfflineAudioContext(
1030
+ 2,
1031
+ video.duration * 44100,
1032
+ 44100
1033
+ );
1034
+
1035
+ // For video files, we'll use the web audio API differently
1036
+ audioBuffer = await state.audioContext.decodeAudioData(arrayBuffer);
1037
+ } else {
1038
+ audioBuffer = await state.audioContext.decodeAudioData(arrayBuffer);
1039
+ }
1040
+
1041
+ state.originalAudioBuffer = audioBuffer;
1042
+ drawWaveform(state.originalAudioBuffer, elements.originalWaveform);
1043
+ showToast('Audio loaded successfully', 'success');
1044
+ } catch (error) {
1045
+ console.error('Error loading audio:', error);
1046
+ showToast('Error loading audio file', 'error');
1047
+ }
1048
+ }
1049
+
1050
+ // Draw Waveform
1051
+ function drawWaveform(audioBuffer, canvas) {
1052
+ const ctx = canvas.getContext('2d');
1053
+ const width = canvas.width = canvas.offsetWidth * 2;
1054
+ const height = canvas.height = canvas.offsetHeight * 2;
1055
+
1056
+ const data = audioBuffer.getChannelData(0);
1057
+ const step = Math.ceil(data.length / width);
1058
+ const amp = height / 2;
1059
+
1060
+ ctx.fillStyle = '#1e293b';
1061
+ ctx.fillRect(0, 0, width, height);
1062
+
1063
+ ctx.beginPath();
1064
+ ctx.strokeStyle = '#6366f1';
1065
+ ctx.lineWidth = 2;
1066
+
1067
+ for (let i = 0; i < width; i++) {
1068
+ let min = 1.0;
1069
+ let max = -1.0;
1070
+
1071
+ for (let j = 0; j < step; j++) {
1072
+ const datum = data[(i * step) + j];
1073
+ if (datum < min) min = datum;
1074
+ if (datum > max) max = datum;
1075
+ }
1076
+
1077
+ ctx.moveTo(i, (1 + min) * amp);
1078
+ ctx.lineTo(i, (1 + max) * amp);
1079
+ }
1080
+
1081
+ ctx.stroke();
1082
+ }
1083
+
1084
+ // Control Handlers
1085
+ elements.noiseLevel.addEventListener('input', (e) => {
1086
+ elements.noiseLevelValue.textContent = e.target.value + '%';
1087
+ });
1088
+
1089
+ elements.sensitivity.addEventListener('input', (e) => {
1090
+ const value = e.target.value;
1091
+ let label = 'Low';
1092
+ if (value > 33) label = 'Medium';
1093
+ if (value > 66) label = 'High';
1094
+ elements.sensitivityValue.textContent = label;
1095
+ });
1096
+
1097
+ elements.comparisonToggle.addEventListener('click', () => {
1098
+ state.previewOriginal = !state.previewOriginal;
1099
+ elements.comparisonToggle.classList.toggle('active', state.previewOriginal);
1100
+ });
1101
+
1102
+ // Remove File
1103
+ elements.removeFile.addEventListener('click', () => {
1104
+ state.file = null;
1105
+ state.originalAudioBuffer = null;
1106
+ state.processedAudioBuffer = null;
1107
+ elements.fileInput.value = '';
1108
+ elements.fileInfo.classList.remove('active');
1109
+ elements.uploadSection.style.display = 'block';
1110
+ elements.controlsSection.classList.remove('active');
1111
+ elements.resultsSection.classList.remove('active');
1112
+ });
1113
+
1114
+ // Noise Reduction Processing
1115
+ elements.processBtn.addEventListener('click', async () => {
1116
+ if (!state.originalAudioBuffer) {
1117
+ showToast('Please upload an audio file first', 'error');
1118
+ return;
1119
+ }
1120
+
1121
+ elements.controlsSection.classList.remove('active');
1122
+ elements.progressSection.classList.add('active');
1123
+
1124
+ const noiseLevel = parseInt(elements.noiseLevel.value) / 100;
1125
+ const sensitivity = parseInt(elements.sensitivity.value) / 100;
1126
+
1127
+ try {
1128
+ // Step 1: Analyzing
1129
+ await updateProgress(10, 'Analyzing audio...', 'step1');
1130
+ await sleep(800);
1131
+
1132
+ // Step 2: Reducing noise
1133
+ await updateProgress(40, 'Reducing crowd noise...', 'step2');
1134
+
1135
+ // Process the audio
1136
+ const processedBuffer = await reduceNoise(state.originalAudioBuffer, noiseLevel, sensitivity);
1137
+ state.processedAudioBuffer = processedBuffer;
1138
+
1139
+ await sleep(500);
1140
+
1141
+ // Step 3: Finalizing
1142
+ await updateProgress(80, 'Finalizing...', 'step3');
1143
+ await sleep(500);
1144
+
1145
+ await updateProgress(100, 'Complete!', 'step3');
1146
+ await sleep(300);
1147
+
1148
+ elements.progressSection.classList.remove('active');
1149
+ elements.resultsSection.classList.add('active');
1150
+
1151
+ // Setup audio players
1152
+ setupAudioPlayers();
1153
+ drawWaveform(state.processedAudioBuffer, elements.processedWaveform);
1154
+
1155
+ showToast('Noise reduction complete!', 'success');
1156
+ } catch (error) {
1157
+ console.error('Processing error:', error);
1158
+ showToast('Error processing audio', 'error');
1159
+ elements.progressSection.classList.remove('active');
1160
+ elements.controlsSection.classList.add('active');
1161
+ }
1162
+ });
1163
+
1164
+ async function updateProgress(percent, text, activeStep) {
1165
+ elements.progressFill.style.width = percent + '%';
1166
+ elements.progressText.textContent = text;
1167
+
1168
+ if (activeStep) {
1169
+ elements.step1.classList.remove('active');
1170
+ elements.step2.classList.remove('active');
1171
+ elements.step3.classList.remove('active');
1172
+ document.getElementById(activeStep).classList.add('active');
1173
+ }
1174
+ }
1175
+
1176
+ function sleep(ms) {
1177
+ return new Promise(resolve => setTimeout(resolve, ms));
1178
+ }
1179
+
1180
+ // Noise Reduction Algorithm (Spectral Gating)
1181
+ async function reduceNoise(audioBuffer, noiseLevel, sensitivity) {
1182
+ const numberOfChannels = audioBuffer.numberOfChannels;
1183
+ const length = audioBuffer.length;
1184
+ const sampleRate = audioBuffer.sampleRate;
1185
+
1186
+ const processedBuffer = state.audioContext.createBuffer(
1187
+ numberOfChannels,
1188
+ length,
1189
+ sampleRate
1190
+ );
1191
+
1192
+ // Noise reduction parameters
1193
+ const noiseThreshold = 0.01 + (1 - noiseLevel) * 0.05;
1194
+ const gateThreshold = sensitivity * 0.1;
1195
+ const attackTime = 0.01;
1196
+ const releaseTime = 0.1;
1197
+
1198
+ for (let channel = 0; channel < numberOfChannels; channel++) {
1199
+ const inputData = audioBuffer.getChannelData(channel);
1200
+ const outputData = processedBuffer.getChannelData(channel);
1201
+
1202
+ // Simple spectral gating implementation
1203
+ let envelope = 0;
1204
+ const attackCoeff = Math.exp(-1 / (attackTime * sampleRate));
1205
+ const releaseCoeff = Math.exp(-1 / (releaseTime * sampleRate));
1206
+
1207
+ // Estimate noise floor from first 0.1 seconds
1208
+ let noiseFloor = 0;
1209
+ const noiseSamples = Math.min(length, Math.floor(0.1 * sampleRate));
1210
+ for (let i = 0; i < noiseSamples; i++) {
1211
+ noiseFloor += Math.abs(inputData[i]);
1212
+ }
1213
+ noiseFloor /= noiseSamples;
1214
+ noiseFloor = Math.max(noiseFloor, noiseThreshold);
1215
+
1216
+ for (let i = 0; i < length; i++) {
1217
+ const sample = inputData[i];
1218
+ const absSample = Math