Skip to content

Commit 6fe7778

Browse files
committed
added little tutorial to README
1 parent ab4de67 commit 6fe7778

File tree

3 files changed

+191
-7
lines changed

3 files changed

+191
-7
lines changed

README.md

Lines changed: 186 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,193 @@ Available modules:
1616
- [SEPIA STT Server](https://github.com/SEPIA-Framework/sepia-stt-server) WebSocket module for speech recognition
1717
- more to come ...
1818

19-
## Quick-Start
19+
## Tutorial
2020

21-
UNDER CONSTRUCTION
22-
In the meantime please check out the test pages.
21+
UNDER CONSTRUCTION - Please check out the test pages for more examples.
22+
23+
### Basic interface
24+
25+
#### Import library and modules
26+
27+
Copy `sepia-web-audio.js` to your project and import the library using the `<head>` section of your HTML page:
28+
29+
```html
30+
<script type="text/javascript" src="src/sepia-web-audio.js"></script>
31+
```
32+
33+
Copy the audio modules you are planning to use and set the correct folder:
34+
35+
```html
36+
<script>
37+
SepiaFW.webAudio.defaultProcessorOptions.moduleFolder = "src/modules";
38+
</script>
39+
```
40+
41+
Note: In this example we've used a folder called `src` for the library and modules folder but you can choose whatever you like.
42+
Note2: Currently (v0.9.6) there is no Javascript modules support yet. Feel free to create a request via the issues section if you need it ;-).
43+
44+
#### Create the audio processor
45+
46+
After importing the library you should see `SepiaFW.webAudio` in your scope. We have used this already in the head to set the modules folder.
47+
The `Processor` class is our main interface to handle the audio pipeline, but first we need to define the modules we want to use.
48+
Modules come in two main flavours, "switch" and "worker" with the main difference that switches are based on 'AudioWorklet' and can pass through data on a lower level (more details later).
49+
50+
For this first example we only look at raw microphone data:
51+
52+
```javascript
53+
var myModules = [];
54+
55+
function bufferCallback(data){
56+
//handle samples here using: data.samples
57+
}
58+
myModules.push({
59+
name: 'buffer-switch',
60+
settings: {
61+
onmessage: bufferCallback,
62+
options: {
63+
processorOptions: {
64+
bufferSize: 512, //size of samples generated
65+
passThroughMode: 0, //0: none, 1: original (float32 array)
66+
}
67+
}
68+
}
69+
});
70+
```
71+
72+
After the module is set up we can create the processor:
73+
74+
```javascript
75+
var processor = new SepiaFW.webAudio.Processor({
76+
onaudiostart: console.log,
77+
onaudioend: console.log,
78+
onrelease: console.log,
79+
onerror: console.error,
80+
modules: myModules
81+
82+
}, function(info){
83+
//Processor ready
84+
console.log(info); //Use 'info' to get details about source, sample-rate etc.
85+
86+
}, function(err){
87+
//Initialization error
88+
console.error(err);
89+
});
90+
```
91+
92+
#### Start, stop and release the processor
93+
94+
As soon as the ready event fired we can start processing with `processor.start()`, check `onaudiostart` (defined in processor options) and wait for data in `bufferCallback` (defined in module).
95+
96+
After we're done we stop with `processor.stop()` and look out for `onaudioend`.
97+
98+
If we don't want to restart later we can close the processor and clean up resources with `processor.release()`.
99+
100+
### Resample input and record raw 16Bit PCM mono audio (WAV)
101+
102+
A very common use-case for this library is to resample microphone input and encode it as 16Bit PCM mono data (which is basically the default WAV file format).
103+
To make this happen we will replace the buffer module from earlier with a resampler and wave encoder module.
104+
NOTE: Some browsers are actually able to natively resampling for us ^^. The resampler module will simply skip transformation in this case but it might be preferable to prevent native resampling to retain full control over the quality and speed.
105+
`SepiaFW.webAudio.isNativeStreamResamplingSupported` will be 'true' when the lib is imported because we can't test for the feature but set to 'false' after the first failed attempt of native resampling!
106+
107+
We create the resampler first and we use the "switch" version (not the "worker", this is preferred if 'AudioWorklet' is supported):
108+
109+
```javascript
110+
SepiaFW.webAudio.tryNativeStreamResampling = false; //global option (remain in control of resampling)
111+
112+
var myModules = [];
113+
var targetSampleRate = 16000; //this is the sample-rate we want
114+
var bufferSize = 512; //size of samples generated
115+
116+
function resamplerCallback(data){
117+
//data will include e.g.: data.samples and data.rms (volume)
118+
}
119+
var resampler = {
120+
name: 'speex-resample-switch',
121+
settings: {
122+
onmessage: resamplerCallback,
123+
sendToModules: [], //[moduleIndex] - filled below with index of wave-encoder module
124+
options: {
125+
processorOptions: {
126+
targetSampleRate: targetSampleRate,
127+
bufferSize: bufferSize,
128+
resampleQuality: 5, //1 (low quality) - 10 (best quality)
129+
calculateRmsVolume: true, //the resampler can calculate RMS signal volume
130+
gain: 1.0, //we can amplify the signal here
131+
passThroughMode: 0 //0: none - only switch in our pipe atm
132+
}
133+
}
134+
}
135+
};
136+
```
137+
138+
Next we create the wave-encoder module:
139+
140+
```javascript
141+
function waveEncoderCallback(data){
142+
//can be used to track capture state and get final WAV
143+
//check: data.gate, data.output.wav, data.output.buffer
144+
}
145+
var waveEncoder = {
146+
name: 'wave-encoder',
147+
type: 'worker',
148+
handle: {}, //will be updated on init. with ref. to node.
149+
settings: {
150+
onmessage: waveEncoderCallback,
151+
options: {
152+
setup: {
153+
inputSampleRate: targetSampleRate, //input of this will be ...
154+
inputSampleSize: bufferSize, //... output of resampler
155+
lookbackBufferMs: 0, //(experimental) ignore for now
156+
recordBufferLimitMs: 6000, //we can apply recording limit as milliseconds
157+
//recordBufferLimitKb: 600, //... or as kilobytes (default ~5MB)
158+
isFloat32: false //resampler gives int16 - use e.g. for buffer module
159+
}
160+
}
161+
}
162+
};
163+
```
164+
165+
Now we combine both modules to our audio pipeline. To tell the wave-encoder what input to use we combine the modules like this:
166+
167+
```javascript
168+
myModules.push(resampler); //index 1
169+
myModules.push(waveEncoder); //index 2
170+
171+
//connect resampler output to wave-encoder input:
172+
resampler.settings.sendToModules.push(2);
173+
```
174+
175+
We create the processor the same way as before (`var processor = new SepiaFW.webAudio.Processor({...});`) and call `processor.start()` when ready.
176+
The wave-encoder will receive data now but only start capturing when we explicitly tell it to using the module message interface.
177+
The same interface is used to request the captured data after we stop processing:
178+
179+
```javascript
180+
//start recording
181+
waveEncoder.handle.sendToModule({gate: "open"});
182+
183+
//wait some time then stop recording (this will trigger automatically after 'recordBufferLimitMs')
184+
waveEncoder.handle.sendToModule({gate: "close"});
185+
186+
//finally get the data (this is possible until processor is released)
187+
waveEncoder.handle.sendToModule({request: {get: "wave"}}); //encoded WAV
188+
waveEncoder.handle.sendToModule({request: {get: "buffer"}}); //raw int16 buffer
189+
```
190+
191+
Just for fun we can add the generated WAV to our page (body) like this:
192+
193+
```javascript
194+
//modified 'waveEncoderCallback':
195+
function waveEncoderCallback(data){
196+
if (data.output && data.output.wav){
197+
//just for fun, add WAV to page:
198+
var targetEle = document.body;
199+
var blobType = "audio/wav";
200+
SepiaFW.webAudio.addAudioElementToPage(targetEle, data.output.wav, blobType);
201+
}
202+
}
203+
```
204+
205+
... TO BE CONTINUED
23206

24207
# Resources (see LICENSE as well)
25208

src/modules/buffer-switch.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ class BufferProcessor extends AudioWorkletProcessor {
107107
//Control messages
108108
this.port.onmessage = function(e){
109109
if (e.data.ctrl){
110-
console.error("Controls", e.data.ctrl); //DEBUG
110+
//console.error("Controls", e.data.ctrl); //DEBUG
111111
switch (e.data.ctrl.action) {
112112
//common interface
113113
case "start":

test-modules.html

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -262,8 +262,9 @@ <h1>SEPIA Web Audio Processor - Module Tests</h1>
262262
targetSampleRate: resamplerSampleRate, //16000,
263263
resampleQuality: resamplerQuality, //7,
264264
bufferSize: resamplerBufferSize, //512,
265-
passThroughMode: 1, //0: none, 1: original (float32), 2: 16Bit PCM - NOTE: NOT resampled
266-
calculateRmsVolume: true
265+
calculateRmsVolume: true,
266+
//gain: +resamplerGain.value, //we can use this here but we have 'volumeProcessor' already ^^
267+
passThroughMode: 1 //0: none, 1: original (float32), 2: 16Bit PCM - NOTE: NOT resampled
267268
}
268269
}
269270
}
@@ -281,7 +282,7 @@ <h1>SEPIA Web Audio Processor - Module Tests</h1>
281282
resampleQuality: resamplerQuality, //7,
282283
bufferSize: resamplerBufferSize, //512, //TODO: set correct value (or replace with ratio?)
283284
calculateRmsVolume: true,
284-
gain: +resamplerGain.value //TODO: keep?
285+
gain: +resamplerGain.value //for the worker we keep it (because vol. is probably disabled)
285286
}
286287
}
287288
}

0 commit comments

Comments
 (0)