Spaces:
Running
Running
Upload 3 files
Browse files- hey-buddy-0.1.0.min.js +0 -0
- hey-buddy-worklet.js +86 -0
- production.html +37 -0
hey-buddy-0.1.0.min.js
CHANGED
The diff for this file is too large to render.
See raw diff
|
|
hey-buddy-worklet.js
ADDED
@@ -0,0 +1,86 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/** @module worklet */
|
2 |
+
|
3 |
+
// Called with `audioWorker.addModule('worklet.js')`
|
4 |
+
// Defines the following global variables:
|
5 |
+
// - sampleRate
|
6 |
+
// - registerProcessor
|
7 |
+
|
8 |
+
/**
|
9 |
+
* The `Processor` class is an AudioWorkletProcessor that resamples the input audio to a target sample rate.
|
10 |
+
*/
|
11 |
+
class Processor extends AudioWorkletProcessor {
|
12 |
+
/**
|
13 |
+
* @param {object} options - The options object.
|
14 |
+
* @param {object} options.processorOptions - The processor options object.
|
15 |
+
* @param {number} options.processorOptions.targetSampleRate - The target sample rate.
|
16 |
+
*/
|
17 |
+
constructor(options) {
|
18 |
+
super(options);
|
19 |
+
this.targetSampleRate = options.processorOptions.targetSampleRate;
|
20 |
+
this.inputBuffer = new Float32Array(this.inputFrameSize);
|
21 |
+
this.inputBufferSize = 0;
|
22 |
+
this.outputBuffer = new Float32Array(this.targetFrameSize);
|
23 |
+
}
|
24 |
+
|
25 |
+
/**
|
26 |
+
* The size of the input frame.
|
27 |
+
* @type {number}
|
28 |
+
*/
|
29 |
+
get inputFrameSize() {
|
30 |
+
return Math.round(sampleRate / 50);
|
31 |
+
}
|
32 |
+
|
33 |
+
/**
|
34 |
+
* The size of the target frame.
|
35 |
+
* @type {number}
|
36 |
+
*/
|
37 |
+
get targetFrameSize() {
|
38 |
+
return Math.round(this.targetSampleRate / 50);
|
39 |
+
}
|
40 |
+
|
41 |
+
/**
|
42 |
+
* Flushes the input buffer to the output buffer, resampling the audio.
|
43 |
+
* Then sends the output buffer to the main thread using the port.
|
44 |
+
*/
|
45 |
+
async flush() {
|
46 |
+
const ratio = sampleRate / this.targetSampleRate;
|
47 |
+
this.outputBuffer.fill(0);
|
48 |
+
for (let i = 0; i < this.targetFrameSize; i++) {
|
49 |
+
const index = i * ratio;
|
50 |
+
const left = Math.floor(index);
|
51 |
+
const right = Math.min(left + 1, this.targetFrameSize - 1);
|
52 |
+
const weight = index - left;
|
53 |
+
this.outputBuffer[i] = this.inputBuffer[left] * (1 - weight) + this.inputBuffer[right] * weight;
|
54 |
+
}
|
55 |
+
await this.port.postMessage(this.outputBuffer);
|
56 |
+
}
|
57 |
+
|
58 |
+
/**
|
59 |
+
* Pushes audio to the input buffer.
|
60 |
+
* @param {Float32Array} inputArray - The input audio.
|
61 |
+
*/
|
62 |
+
pushAudio(inputArray) {
|
63 |
+
const inputLength = inputArray.length;
|
64 |
+
const remainingLength = this.inputFrameSize - this.inputBufferSize;
|
65 |
+
if (inputLength < remainingLength) {
|
66 |
+
this.inputBuffer.set(inputArray, this.inputBufferSize);
|
67 |
+
this.inputBufferSize += inputLength;
|
68 |
+
return;
|
69 |
+
}
|
70 |
+
this.inputBuffer.set(inputArray.subarray(0, remainingLength), this.inputBufferSize);
|
71 |
+
this.flush();
|
72 |
+
this.inputBufferSize = 0;
|
73 |
+
this.pushAudio(inputArray.subarray(remainingLength));
|
74 |
+
}
|
75 |
+
|
76 |
+
/**
|
77 |
+
* Processes the input audio (the main worklet loop).
|
78 |
+
*/
|
79 |
+
process(inputArray, outputArray, parameters) {
|
80 |
+
this.pushAudio(inputArray[0][0]);
|
81 |
+
return true;
|
82 |
+
}
|
83 |
+
}
|
84 |
+
|
85 |
+
// Registers the processor with the name "hey-buddy".
|
86 |
+
registerProcessor("hey-buddy", Processor);
|
production.html
ADDED
@@ -0,0 +1,37 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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>Hey, Buddy!</title>
|
7 |
+
<link href="style.css" rel="stylesheet" />
|
8 |
+
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/ort.min.js"></script>
|
9 |
+
<script src="dist/hey-buddy.min.js"></script>
|
10 |
+
<script src="index.js"></script>
|
11 |
+
</head>
|
12 |
+
<body>
|
13 |
+
<div class="card">
|
14 |
+
<section id="logo">
|
15 |
+
<img src="logo.png" alt="Hey Buddy!" />
|
16 |
+
</section>
|
17 |
+
<section id="headline">
|
18 |
+
<p><strong><em>Hey Buddy!</em></strong> is a library for training wake word models (a.k.a audio keyword spotters) and deploying them to the browser for real-time use on CPU or GPU.</p>
|
19 |
+
<p>Using a wake-word as a gating mechanism for voice-enabled web applications carries numerous benefits, including reduced power consumption, improved privacy, and enhanced performance in noisy environments over speech-to-text systems.</p>
|
20 |
+
<p>This space serves as a demonstration of the JavaScript library for front-end applications. Say something like, <em>“Hey buddy, how are you?”</em> to see the wake word and voice activity detection in action. Your voice command will be isolated as an audio clip, which is then ready to be sent to your application's backend for further processing.</p>
|
21 |
+
</section>
|
22 |
+
<section id="links">
|
23 |
+
<a href="https://github.com/painebenjamin/hey-buddy" target="_blank">
|
24 |
+
<img src="https://img.shields.io/static/v1?label=painebenjamin&message=hey-buddy&logo=github&color=0b1830" alt="painebenjamin - hey-buddy" />
|
25 |
+
</a>
|
26 |
+
<a href="https://huggingface.co/benjamin-paine/hey-buddy" target="_blank">
|
27 |
+
<img src="https://img.shields.io/static/v1?label=benjamin-paine&message=hey-buddy&logo=huggingface&color=0b1830" alt="painebenjamin - hey-buddy" />
|
28 |
+
</a>
|
29 |
+
</section>
|
30 |
+
<section id="graphs"></section>
|
31 |
+
<section id="recording">
|
32 |
+
<label>Recording</label>
|
33 |
+
<div id="audio">No recording yet</div>
|
34 |
+
</section>
|
35 |
+
</div>
|
36 |
+
</body>
|
37 |
+
</html>
|