├── README.md
├── css
└── styles.css
├── index.html
└── js
└── main.js
/README.md:
--------------------------------------------------------------------------------
1 | # speech-jammer
2 | Speech Jammer using getUserMedia and Web Audio API
3 |
4 | Point a web server to the folder
5 |
--------------------------------------------------------------------------------
/css/styles.css:
--------------------------------------------------------------------------------
1 | * {
2 | box-sizing: border-box;
3 | font-family: 'Roboto Slab', sans-serif;
4 | font-weight: 100;
5 | margin: 0;
6 | padding: 0;
7 | }
8 |
9 | html {
10 | height: 100%;
11 | }
12 |
13 | body {
14 | margin: 0;
15 | padding: 0;
16 | background-color: #232323;
17 | color: #ffffff;
18 | line-height: 20px;
19 | height: 100%;
20 | overflow: hidden;
21 | font-family: 'Roboto Slab', sans-serif;
22 | font-size: 13px;
23 | font-weight: 100;
24 | }
25 |
26 | b {
27 | font-weight: bold;
28 | }
29 |
30 | div.panel {
31 | position: absolute;
32 | left: 50%;
33 | top: 50%;
34 | transform: translate3d(-50%, -50%, 0);
35 | line-height: 1.4em;
36 | font-size: 3vw;
37 | white-space: nowrap;
38 | }
39 |
40 | note {
41 | font-size: 2vw;
42 | display: block;
43 | line-height: 1.4em
44 | }
45 |
46 | .controls {}
47 |
48 | .controls p {
49 | font-size: 2vw;
50 | position: relative;
51 | margin: 20px 0;
52 | }
53 |
54 | .controls input[type=range] {
55 | position: absolute;
56 | left: 30%;
57 | right: 0;
58 | top: 50%;
59 | margin-top: -10px;
60 | width: 70%;
61 | }
62 |
63 | .click {
64 | position: absolute;
65 | left: 0;
66 | top: 0;
67 | right: 0;
68 | bottom: 0;
69 | background-color: rgba(0, 0, 0, .9);
70 | color: white;
71 | z-index: 100;
72 | width: 100%;
73 | height: 100%;
74 | pointer-events: auto;
75 | }
76 |
77 | .click p {
78 | position: absolute;
79 | left: 50%;
80 | top: 50%;
81 | transform: translate3d(-50%, -50%, 0);
82 | text-align: center;
83 | }
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Speech Jammer
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
Welcome!
We need to run some audio
Click to start
16 |
17 |
18 |
Speech Jammer
19 |
1. Plug your headphones
20 |
2. Allow the browser access to your microphone
21 |
3. Raise the volume of your headphones
22 |
4. Try talking like a sane person
23 |
27 |
Uses Web Audio API and WebRTC getUserMedia.
Chrome and Firefox only
28 |
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/js/main.js:
--------------------------------------------------------------------------------
1 | function init() {
2 |
3 | window.AudioContext = window.AudioContext || window.webkitAudioContext || window.mozAudioContext;
4 |
5 | var context = new AudioContext();
6 |
7 | var delayValue = document.getElementById('delayValue');
8 | var delayRange = document.getElementById('delayRange');
9 |
10 | var gainValue = document.getElementById('gainValue');
11 | var gainRange = document.getElementById('gainRange');
12 |
13 | var gain = context.createGain();
14 | gain.connect(context.destination);
15 | gain.gain.value = 1;
16 | if (localStorage['gainValue']) {
17 | var v = parseFloat(localStorage['gainValue']);
18 | if (v < 1) v = 1;
19 | if (v > 10) v = 10;
20 | gain.gain.value = v;
21 | gainRange.value = v;
22 | gainValue.textContent = parseFloat(v).toFixed(1);
23 | }
24 |
25 | var delay = context.createDelay();
26 | delay.connect(gain);
27 | delay.delayTime.value = .15;
28 | if (localStorage['delayValue']) {
29 | var v = parseFloat(localStorage['delayValue']);
30 | if (v < 0) v = 0;
31 | if (v > 1) v = 1;
32 | delay.delayTime.value = v;
33 | delayRange.value = v * 1000;
34 | delayValue.textContent = v * 1000;
35 | }
36 |
37 | navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia;
38 |
39 | var mediaStreamSource;
40 |
41 | if (navigator.getUserMedia) {
42 | navigator.getUserMedia({ audio: true },
43 | function(stream) {
44 | mediaStreamSource = context.createMediaStreamSource(stream);
45 | mediaStreamSource.connect(delay);
46 | },
47 | function(err) {
48 | console.log("The following error occured: " + err.name);
49 | }
50 | );
51 | } else {
52 | console.log("getUserMedia not supported");
53 | }
54 |
55 | delayRange.addEventListener('input', function(e) {
56 |
57 | delay.delayTime.value = this.value / 1000;
58 | delayValue.textContent = this.value;
59 | localStorage['delayValue'] = this.value / 1000;
60 |
61 | });
62 |
63 | gainRange.addEventListener('input', function(e) {
64 |
65 | gain.gain.value = this.value;
66 | gainValue.textContent = parseFloat(this.value).toFixed(1);
67 | localStorage['gainValue'] = this.value;
68 |
69 | });
70 |
71 | }
72 |
73 | window.AudioContext = window.AudioContext || window.webkitAudioContext || window.mozAudioContext;
74 |
75 | var overlay = document.getElementById('overlay');
76 | overlay.addEventListener('click', onClick);
77 |
78 | var test = new AudioContext();
79 | if (test.state === 'running') {
80 | onClick();
81 | }
82 |
83 | function onClick() {
84 | overlay.removeEventListener('click', onClick);
85 | overlay.style.display = 'none';
86 | init();
87 | }
--------------------------------------------------------------------------------