speaker-calibration 1.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +72 -0
- package/dist/example/index.html +47 -0
- package/dist/example/listener.html +59 -0
- package/dist/example/server.js +50 -0
- package/dist/example/speaker.html +81 -0
- package/dist/example/styles.css +23 -0
- package/dist/main.js +1 -0
- package/dist/mlsGen.js +6814 -0
- package/dist/mlsGen.wasm +0 -0
- package/netlify.toml +27 -0
- package/package.json +61 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2022 EasyEyes
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
# Speaker-Calibration
|
|
2
|
+
|
|
3
|
+
[](https://app.netlify.com/sites/focused-hodgkin-0a6531/deploys)
|
|
4
|
+
|
|
5
|
+
# Contribution Guidelines
|
|
6
|
+
|
|
7
|
+
_As of 03/01/2022_
|
|
8
|
+
|
|
9
|
+
## Initial Setup
|
|
10
|
+
|
|
11
|
+
1. `git clone https://github.com/EasyEyes/speaker-calibration.git`
|
|
12
|
+
2. `cd speaker-calibration`
|
|
13
|
+
3. `npm i`
|
|
14
|
+
|
|
15
|
+
## Local Development
|
|
16
|
+
|
|
17
|
+
All outputs from the scripts/recipies below should be automatically placed in the `/dist` directory.
|
|
18
|
+
This is what will be served once the library is published.
|
|
19
|
+
|
|
20
|
+
### Example
|
|
21
|
+
|
|
22
|
+
In `/dist/example` you will find a small example app that uses the `speaker-calibration` library.
|
|
23
|
+
|
|
24
|
+
### Javascript
|
|
25
|
+
|
|
26
|
+
In `package.json` you will see some key scripts:
|
|
27
|
+
|
|
28
|
+
1. `build:wasm` cleans and rebuilds the wasm files
|
|
29
|
+
2. `build:dev` tells webpack to build the `speaker-calibration` library in development watch mode,
|
|
30
|
+
outputing to `/dist`
|
|
31
|
+
3. `serve:dev` spins up an `express.js` server on port `3000` using `nodemon`. It serves the
|
|
32
|
+
`/dist` & `/dist/example` folders.
|
|
33
|
+
4. `lint` runs `eslint` on all js files in the project
|
|
34
|
+
5. `lint:fix` lints and automatically fixes all js files in the project.
|
|
35
|
+
6. `build:doc` builds the documentation using `jsdoc`. Outputs to `/doc`
|
|
36
|
+
|
|
37
|
+
Run `(1)` & `(2)` in seperate shell windows, with this setup you will be able to modify both the
|
|
38
|
+
library and front end examples with hot reload built in. `(3)` provides a simple abstraction on the
|
|
39
|
+
`makefile` recipies below. Run `(5)` precommit to keep you code standardized.
|
|
40
|
+
|
|
41
|
+
TODO Make `(5)` a precommit hook
|
|
42
|
+
|
|
43
|
+
### CPP/WASM
|
|
44
|
+
|
|
45
|
+
We are using [Emscripten](https://emscripten.org/) to compile the C++ code into a wasm file. Usage
|
|
46
|
+
requires the installation of the Emscriten compiler. Instructions can be found on their website. In
|
|
47
|
+
`makefile` you will see a few recipies:
|
|
48
|
+
|
|
49
|
+
- `mlsGen_bind` compiles the cpp files to wasm, generating a modularized javascript "glue" file,
|
|
50
|
+
using embind. This is the current build target
|
|
51
|
+
- `mlsGen_module` compiles the cpp files to wasm, generating a modularized javascript "glue" file.
|
|
52
|
+
- `mlsGen_wasm` compiles the cpp file to a stand-alone wasm without a javascript "clue" file.
|
|
53
|
+
- `clean` cleans up and generated code
|
|
54
|
+
- `rebuild` cleans and rebuilds the output. Run this after making changes to the cpp files.
|
|
55
|
+
|
|
56
|
+
### Documentation
|
|
57
|
+
|
|
58
|
+
We use [jsdoc](https://jsdoc.app/) standards to document our library.
|
|
59
|
+
|
|
60
|
+
### Listing
|
|
61
|
+
|
|
62
|
+
We use [ESLint](https://eslint.org/) to lint our code and enforce best practices. We are currently
|
|
63
|
+
using [AirBnB's JavaScript Style Guide](https://airbnb.io/javascript/)
|
|
64
|
+
|
|
65
|
+
### Styling
|
|
66
|
+
|
|
67
|
+
We use [Prettier](https://prettier.io/) to format our code.
|
|
68
|
+
|
|
69
|
+
## Deployment
|
|
70
|
+
|
|
71
|
+
Changes publshed to `main` will automatically trigger a deploy on the `netlify` project TODO: Fix
|
|
72
|
+
netlify deploy not serving the /dist & /example folders
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html class="no-js" lang="">
|
|
3
|
+
|
|
4
|
+
<head>
|
|
5
|
+
<meta charset="utf-8">
|
|
6
|
+
<meta http-equiv="x-ua-compatible" content="ie=edge">
|
|
7
|
+
<title>Sound Check</title>
|
|
8
|
+
<meta name="description" content="">
|
|
9
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
10
|
+
|
|
11
|
+
<link rel="apple-touch-icon" href="/apple-touch-icon.png">
|
|
12
|
+
<!--CSS-->
|
|
13
|
+
<link href="../example/styles.css" rel="stylesheet" typ="text/css">
|
|
14
|
+
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet"
|
|
15
|
+
integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">
|
|
16
|
+
|
|
17
|
+
</head>
|
|
18
|
+
|
|
19
|
+
<body>
|
|
20
|
+
<!--[if lt IE 8]>
|
|
21
|
+
<p class="browserupgrade">
|
|
22
|
+
You are using an <strong>outdated</strong> browser. Please
|
|
23
|
+
<a href="http://browsehappy.com/">upgrade your browser</a> to improve
|
|
24
|
+
your experience.
|
|
25
|
+
</p>
|
|
26
|
+
<![endif]-->
|
|
27
|
+
<div class="container">
|
|
28
|
+
<h1>Check out /speaker</h1>
|
|
29
|
+
<p class="lead">
|
|
30
|
+
Go to <a id="speakerLink">/speaker</a> to simulate calibrating as part
|
|
31
|
+
of an experiment running on a participant's computer.
|
|
32
|
+
|
|
33
|
+
The page will instruct the user on how to use their mobile device as a
|
|
34
|
+
calibration microphone.
|
|
35
|
+
</p>
|
|
36
|
+
</div>
|
|
37
|
+
<script type="text/javascript">
|
|
38
|
+
const speakerLink = "/speaker";
|
|
39
|
+
const baseURL = location.href.substring(0, location.href.lastIndexOf('/'));
|
|
40
|
+
document.getElementById("speakerLink").setAttribute("href", baseURL + speakerLink);
|
|
41
|
+
</script>
|
|
42
|
+
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js"
|
|
43
|
+
integrity="sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p"
|
|
44
|
+
crossorigin="anonymous"></script>
|
|
45
|
+
</body>
|
|
46
|
+
|
|
47
|
+
</html>
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html class="no-js" lang="">
|
|
3
|
+
|
|
4
|
+
<head>
|
|
5
|
+
<meta charset="utf-8" />
|
|
6
|
+
<meta http-equiv="x-ua-compatible" content="ie=edge" />
|
|
7
|
+
<title>Listener</title>
|
|
8
|
+
<meta name="description" content="" />
|
|
9
|
+
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
10
|
+
|
|
11
|
+
<link rel="apple-touch-icon" href="/apple-touch-icon.png" />
|
|
12
|
+
|
|
13
|
+
<!-- CSS -->
|
|
14
|
+
<link href="../example/styles.css" rel="stylesheet" typ="text/css">
|
|
15
|
+
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet"
|
|
16
|
+
integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
<!--<script src="https://www.unpkg.com/sound-check"> </script>-->
|
|
20
|
+
<script src="../main.js"></script>
|
|
21
|
+
</head>
|
|
22
|
+
|
|
23
|
+
<body>
|
|
24
|
+
<!--[if lt IE 8]>
|
|
25
|
+
<p class="browserupgrade">
|
|
26
|
+
You are using an <strong>outdated</strong> browser. Please
|
|
27
|
+
<a href="http://browsehappy.com/">upgrade your browser</a> to improve
|
|
28
|
+
your experience.
|
|
29
|
+
</p>
|
|
30
|
+
<![endif]-->
|
|
31
|
+
<div class="container">
|
|
32
|
+
<h1>Listener Page</h1>
|
|
33
|
+
<p class="lead">Lorem ipsum dolor sit amet, consectetur adipisicing elit. Officia maxime sapiente repudiandae est,
|
|
34
|
+
magnam ex sint iure quo porro ullam debitis inventore at temporibus quod ducimus nesciunt dolorem laboriosam.
|
|
35
|
+
Eius!</p>
|
|
36
|
+
<div class="row">
|
|
37
|
+
<div class="col-6">
|
|
38
|
+
<button id="calibrationBeginButton" type="button" class="btn btn-primary">Calibrate Speakers</button>
|
|
39
|
+
</div>
|
|
40
|
+
<div class="col-6">
|
|
41
|
+
<div id="display"></div>
|
|
42
|
+
</div>
|
|
43
|
+
</div>
|
|
44
|
+
</div>
|
|
45
|
+
<script type="text/javascript">
|
|
46
|
+
const listenerParameters = {
|
|
47
|
+
targetElementId: "display"
|
|
48
|
+
};
|
|
49
|
+
document.getElementById("calibrationBeginButton").onclick = () => {
|
|
50
|
+
window.listener = new speakerCalibrator.Listener(listenerParameters);
|
|
51
|
+
console.log(window.listener)
|
|
52
|
+
};
|
|
53
|
+
</script>
|
|
54
|
+
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js"
|
|
55
|
+
integrity="sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p"
|
|
56
|
+
crossorigin="anonymous"></script>
|
|
57
|
+
</body>
|
|
58
|
+
|
|
59
|
+
</html>
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
|
|
2
|
+
// eslint-disable-next-line import/no-extraneous-dependencies
|
|
3
|
+
const express = require('express');
|
|
4
|
+
const path = require('path');
|
|
5
|
+
|
|
6
|
+
const app = express();
|
|
7
|
+
const port = 3000;
|
|
8
|
+
|
|
9
|
+
app.use('/', express.static(path.join(__dirname, '/../'))); // serve the distribution folder
|
|
10
|
+
|
|
11
|
+
// Middleware to check we have all the params we need
|
|
12
|
+
const checkParams = (req, res, next) => {
|
|
13
|
+
if (!Object.prototype.hasOwnProperty.call(req.query, 'speakerPeerId')) {
|
|
14
|
+
console.log('No peerID given.');
|
|
15
|
+
throw new Error('No peerID given -- unable to connect to peer.');
|
|
16
|
+
}
|
|
17
|
+
next();
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
// Simple Routing
|
|
21
|
+
app.get('/', (req, res) => {
|
|
22
|
+
res.sendFile(path.join(__dirname, 'index.html'));
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
app.get('/speaker', (req, res) => {
|
|
26
|
+
res.sendFile(path.join(__dirname, 'speaker.html'));
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
app.get('/listener', checkParams, (req, res) => {
|
|
30
|
+
res.sendFile(path.join(__dirname, 'listener.html'));
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
app.use((err, req, res) => {
|
|
34
|
+
res.status(err.status || 500);
|
|
35
|
+
res.send({
|
|
36
|
+
error: err.message,
|
|
37
|
+
});
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
app.use((req, res) => {
|
|
41
|
+
res.status(404);
|
|
42
|
+
res.send({
|
|
43
|
+
error: '404 not found',
|
|
44
|
+
});
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
if (!module.parent) {
|
|
48
|
+
app.listen(port);
|
|
49
|
+
console.log(`Express started on port ${port}`);
|
|
50
|
+
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html class="no-js" lang="">
|
|
3
|
+
|
|
4
|
+
<head>
|
|
5
|
+
<meta charset="utf-8" />
|
|
6
|
+
<meta http-equiv="x-ua-compatible" content="ie=edge" />
|
|
7
|
+
<title>Speaker</title>
|
|
8
|
+
<meta name="description" content="" />
|
|
9
|
+
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
10
|
+
<!--CSS-->
|
|
11
|
+
<link href="../example/styles.css" rel="stylesheet" typ="text/css">
|
|
12
|
+
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet"
|
|
13
|
+
integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">
|
|
14
|
+
<script src="../main.js"></script>
|
|
15
|
+
<link rel="icon"
|
|
16
|
+
href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><text y=%22.9em%22 font-size=%2290%22>🔈</text></svg>" />
|
|
17
|
+
<!--<script src="https://www.unpkg.com/sound-check"></script>-->
|
|
18
|
+
<!-- <script src="https://cdn.jsdelivr.net/npm/chart.js@3.7.1/dist/chart.min.js"
|
|
19
|
+
integrity="sha256-ErZ09KkZnzjpqcane4SCyyHsKAXMvID9/xwbl/Aq1pc=" crossorigin="anonymous"></script> -->
|
|
20
|
+
</head>
|
|
21
|
+
|
|
22
|
+
<body>
|
|
23
|
+
<div class="container">
|
|
24
|
+
<h1>Speaker Page</h1>
|
|
25
|
+
<p class="lead">Lorem ipsum dolor sit amet, consectetur adipisicing elit. Officia maxime sapiente repudiandae est,
|
|
26
|
+
magnam ex sint iure quo porro ullam debitis inventore at temporibus quod ducimus nesciunt dolorem laboriosam.
|
|
27
|
+
Eius!</p>
|
|
28
|
+
<div class="row">
|
|
29
|
+
<div class="col-4">
|
|
30
|
+
<button id="calibrationBeginButton" type="button" class="btn btn-primary">Calibrate Speakers</button>
|
|
31
|
+
</div>
|
|
32
|
+
<div class="col-4">
|
|
33
|
+
<div id="display"></div>
|
|
34
|
+
</div>
|
|
35
|
+
<div class="col-4">
|
|
36
|
+
<div class="d-flex align-items-center d-none" id="spinner">
|
|
37
|
+
<strong>Calibrating Volume...</strong>
|
|
38
|
+
<div class="spinner-border ml-auto" role="status" aria-hidden="true"></div>
|
|
39
|
+
</div>
|
|
40
|
+
<h4 id="volumeCalibrationResult" class="d-none"></h4>
|
|
41
|
+
</div>
|
|
42
|
+
</div>
|
|
43
|
+
<div class="row">
|
|
44
|
+
<div class="col" id="d3-select">
|
|
45
|
+
<div id="generated-signal-chart"></div>
|
|
46
|
+
</div>
|
|
47
|
+
</div>
|
|
48
|
+
<div class="row">
|
|
49
|
+
<div class="col">
|
|
50
|
+
<div id="captured-signal-chart""></div>
|
|
51
|
+
</div>
|
|
52
|
+
</div>
|
|
53
|
+
<div class=" row">
|
|
54
|
+
<div class="col">
|
|
55
|
+
<div id="ir-chart"></div>
|
|
56
|
+
</div>
|
|
57
|
+
</div>
|
|
58
|
+
</div>
|
|
59
|
+
<script>
|
|
60
|
+
document.getElementById("calibrationBeginButton").onclick = async () => {
|
|
61
|
+
const spinner = document.getElementById("spinner");
|
|
62
|
+
const volumeCalibrationResult = document.getElementById("volumeCalibrationResult");
|
|
63
|
+
const speakerParameters = {
|
|
64
|
+
siteUrl: window.location.href.substring(
|
|
65
|
+
0,
|
|
66
|
+
location.href.lastIndexOf("/")
|
|
67
|
+
),
|
|
68
|
+
targetElementId: "display",
|
|
69
|
+
};
|
|
70
|
+
const { Speaker, VolumeCalibration } = speakerCalibrator;
|
|
71
|
+
const dbSPL = await Speaker.startCalibration(speakerParameters, VolumeCalibration);
|
|
72
|
+
volumeCalibrationResult.innerText = `Sound Gain ${dbSPL.toFixed(3)} dB SPL`;
|
|
73
|
+
volumeCalibrationResult.classList.remove("d-none");
|
|
74
|
+
}
|
|
75
|
+
</script>
|
|
76
|
+
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js"
|
|
77
|
+
integrity="sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p"
|
|
78
|
+
crossorigin="anonymous"></script>
|
|
79
|
+
</body>
|
|
80
|
+
|
|
81
|
+
</html>
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
body {
|
|
2
|
+
padding-top: 2rem;
|
|
3
|
+
padding-bottom: 2rem;
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
.row {
|
|
7
|
+
margin-bottom: 1rem;
|
|
8
|
+
}
|
|
9
|
+
.row .row {
|
|
10
|
+
margin-top: 1rem;
|
|
11
|
+
margin-bottom: 0;
|
|
12
|
+
}
|
|
13
|
+
[class*="col"] {
|
|
14
|
+
padding-top: 1rem;
|
|
15
|
+
padding-bottom: 1rem;
|
|
16
|
+
/* background-color: rgba(86, 61, 124, .15); */
|
|
17
|
+
border: 1px solid rgba(86, 61, 124, .2);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
hr {
|
|
21
|
+
margin-top: 2rem;
|
|
22
|
+
margin-bottom: 2rem;
|
|
23
|
+
}
|