-
Notifications
You must be signed in to change notification settings - Fork 0
/
index.html
410 lines (386 loc) · 16.6 KB
/
index.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
<!DOCTYPE html>
<html lang="en">
<head>
<title>Tactile Waves</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
<link href="https://fonts.googleapis.com/css?family=Montserrat" rel="stylesheet" type="text/css">
<link href="https://fonts.googleapis.com/css?family=Lato" rel="stylesheet" type="text/css">
<link href="https://fonts.googleapis.com/css?family=Roboto|Roboto+Mono" rel="stylesheet" type="text/css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.0/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
<style>
html {
font-size: 100%;
}
body {
font-size: 0.625em;
font: Roboto;
line-height: 1.8;
color: #fffae2;
background-color: #252525;
}
h1 {
font-size: 3.2em;
text-transform: uppercase;
color: #DADEE1;
font-weight: 600;
margin-bottom: 30px;
}
h2 {
font-size: 2.4em;
text-transform: uppercase;
color: #DADEE1;
font-weight: 600;
margin-bottom: 30px;
}
h3 {
font-size: 2em;
font-weight: 400;
margin-bottom: 25px;
}
h4 {
font-size: 1.8em;
line-height: 1.375em;
font-weight: 200;
margin-bottom: 25px;
}
p {
font-size: 1.4em;
margin-bottom: 25px;
}
a {
color: #ceb212;
}
pre {
font: 400 1.4em Roboto Mono;
background-color: #191919;
color: #AF782B;
margin-bottom: 30px;
}
code {
font: 200 1em Roboto Mono;
background-color: #424242;
color: #DADEE1;
}
.navbar {
margin-bottom: 0;
background-color: #221e28;
color: #DADEE1;
z-index: 9999;
border: 0;
font-size: 1.2em !important;
line-height: 1.42857143 !important;
letter-spacing: 0.4em;
border-radius: 0;
}
.navbar li a, .navbar .navbar-brand {
color: #fff !important;
}
.navbar-nav li a:hover, .navbar-nav li.active a {
color: #AF782B !important;
background-color: #DADEE1 !important;
}
.navbar-default .navbar-toggle {
border-color: transparent;
color: #fffae2 !important;
}
.jumbotron {
background-color: #43394f;
color: #DADEE1;
padding: 100px 100px 0px;
font-family: Montserrat, sans-serif;
}
.container-fluid {
padding: 20px 25px 30px;
}
.bg-purple {
background-color: #62636d;
}
.bg-grey {
background-color: #252525;
}
.logo-small {
color: #3bceae;
font-size: 50px;
}
.logo {
color: #3bceae;
font-size: 200px;
}
.thumbnail {
padding: 10px 10px 15px 10px;
border: none;
border-radius: 0;
}
.thumbnail img {
width: 100%;
height: 100%;
margin-bottom: 10px;
}
footer .glyphicon {
font-size: 20px;
margin-bottom: 20px;
color: #AF782B;
}
.slideanim {visibility:hidden;}
.slide {
/* The name of the animation */
animation-name: slide;
-webkit-animation-name: slide;
/* The duration of the animation */
animation-duration: 1s;
-webkit-animation-duration: 1s;
/* Make the element visible */
visibility: visible;
}
/* Go from 0% to 100% opacity (see-through) and specify the percentage from when to slide in the element along the Y-axis */
@keyframes slide {
0% {
opacity: 0;
transform: translateY(70%);
}
100% {
opacity: 1;
transform: translateY(0%);
}
}
@-webkit-keyframes slide {
0% {
opacity: 0;
-webkit-transform: translateY(70%);
}
100% {
opacity: 1;
-webkit-transform: translateY(0%);
}
}
@media screen and (min-width: 768px) {
.container {
max-width: 800px;
}
.container-fluid {
max-width: 800px;
}
}
@media screen and (max-width: 768px) {
.col-sm-4 {
text-align: center;
margin: 25px 0;
}
.btn-lg {
width: 100%;
margin-bottom: 35px;
}
}
@media screen and (max-width: 480px) {
.logo {
font-size: 150px;
}
}
</style>
</head>
<body id="myPage" data-spy="scroll" data-target=".navbar" data-offset="60">
<nav class="navbar navbar-default navbar-fixed-top">
<div class="container">
<div class="navbar-header">
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target="#myNavbar">
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="#myPage">Tactile Waves</a>
</div>
<div class="collapse navbar-collapse" id="myNavbar">
<ul class="nav navbar-nav navbar-right">
<li><a href="https://github.com/Funkatronics/TactileWaves">GITHUB</a></li>
<li><a href="https://bintray.com/funkatronics/tactilewaves/tactilewaves">DOWNLOAD</a></li>
<li><a href="doc/index.html">DOCS</a></li>
<li><a href="#contact">CONTACT</a></li>
</ul>
</div>
</div>
</nav>
<!--
<div class="jumbotron text-center" style="background-color: #f4d142; color: #000; padding: 75px 25px 25px;">
<span class="glyphicon glyphicon-alert" style="font-size: 30px"></span>
<h4 style="color: #000;">This site is currently under construction</h4>
<h5 style="color: #000;">I appreciate your patience</h5>
</div>
-->
<!-- Title -->
<div class="container">
<div class="jumbotron text-center">
<h1>Tactile Waves</h1>
<p>Sound-to-Touch Sensory Substituion in Java</p>
<hr>
</div>
</div>
<!-- Introduction -->
<div id="intro" class="container-fluid text-left">
<div>
<p>Tactile Waves is an open source digital signal processing (DSP) library for sound-to-touch sensory substitution research and development. It has been designed to enable mobile devices to be used as the 'back end' of a sound-to-touch sensory substitution system. Using Tactile Waves, audio can be acquired and preprocessed, and important features can be extracted and sent to sensory substitution hardware worn on the body via Bluetooth.
</p>
<p>Tactile Waves can be useful even if you are'nt interested in sensory substitution. As required by sensory substitution applications, Tactile Waves provides a plethora of speech processing functions and audio stream management. These can be used to build audio analysis and feature extraction applications for Android and Java such as a Pitch Detector or Formant Frequency Estimator. Tactile Waves could also be used as a preprocessor and feature extractor for an Automatic Speech Recognition (ASR) system. The possibilities are endless, and it is my hope that users will be encouraged to push the boundaries of the library (and contribute their extensions!).
</p>
</div>
</div>
<!-- Instalation -->
<div id="install" class="container-fluid text-left">
<h2>Installation</h2>
<hr>
<p>Tactile Waves is available as a remote Android Library, as well as a standard JAR file.</p>
<p>If you are developing an Android Application, the easiest way to use Tactile waves is to add a dependency to the remote library.</p>
<p>Add the following dependency to your apps build.gradle file:</p>
<pre>dependencies {
implementation 'com.funkatronics.code:tactilewaves:1.0.0'
}</pre>
</div>
<!-- Getting Started -->
<div id="start" class="container-fluid text-left">
<h2>Getting Started with Tactile Waves</h2>
<hr>
<p>Tactile Waves provides a system for handling audio recording, buffering, windowing and processing in a few easy to use objects within the <code>tactilewaves.dsp</code> package.</p>
<h3>WaveManager</h3>
<p>The <code>WaveManager</code> object represents the core of Tactile Waves' audio engine. It reads audio samples from a <code>WaveInputStream</code>, and generates a <code>WaveFrame</code> for each frame of audio acquired. Each <code>WaveFrame</code> is passed through a chain of <code>WaveProcessor</code> objects that perform some useful processing on the frame, and optionally store extracted audio features in the frame's feature set. Processed frames are then sent to any <code>WaveListener</code> objects that have been added to the <code>WaveManager</code>. These listeners can be used to trigger UI updates, or send extracted audio features to sensory substitution hardware.</p>
<h3>WaveInputStream</h3>
<p><code>WaveInputStream</code> is an abstract class that contains an underlying <code>InputStream</code> to acquire audio bytes from a stream and convert them audio samples. A <code>WaveManager</code> object is used to read a <code>WaveInputStream</code> and generate windowed frames of audio.</p>
<h3>WaveFrame</h3>
<p>The <code>WaveFrame</code> object represents a single frame of audio. A <code>WaveManager</code> will create <code>WaveFrame</code> objects according the the buffer and overlap length provided. Each <code>WaveFrame</code> is then passed through the <code>WaveManager</code>'s processing chain</p>
<h3>WaveProcessor</h3>
<p>Tactile Waves uses the <code>WaveProcessor</code> interface to build objects that can be inserted into a <code>WaveManager</code>'s processing chain. Any object that implements this interface can be added to the chain to perform some type of processing or analysis on each frame of audio.</p>
<h3>WaveFrameListener</h3>
<p>After a <code>WaveFrame</code> has been passed through the entire processing chain, it is sent to any subscribed <code>WaveFrameListener</code> objects. This can be used to trigger events that are dependent on processed audio frames such as UI updates or Bluetooth transmission.</p>
<h2>Putting it all Together</h2>
<p>A <code>WaveManager</code> is initialized with a <code>WaveInputStream</code> to read audio from, along with a buffer and overlap length.</p>
<p>To obtain a stream from an Android device's microphone use:</p>
<pre>WaveInputStream inputStream = new AndroidWaveInputStream(bufferSize);</pre>
<p>A <code>WaveManager</code> can then be instantiated:</p>
<pre>WaveManager waveManager = new WaveManager(inputStream, bufferSize, overlap);</pre>
<p>A newly instantiated <code>WaveManager</code> will have an empty processing chain. To add processing to the chain, use the <code>addEffectToChain</code> method to add any object that implements the <code>WaveProcessor</code> interface. Tactile Waves provides several ready to use processors, and users can easily build their own.</p>
<p>For example, to estimate the pitch of incoming audio, a <code>PitchProcessor</code> can be used. Add a new <code>PitchProcessor</code> the the <code>Wave Manager</code>'s processing chain:</p>
<pre>waveManager.addEffectToChain(new PitchProcessor(bufferSize));</pre>
<p>Add any listeners to the <code>WaveManager</code> using the <code>addListener()</code> method:</p>
<pre>waveManager.addListener(listener);</pre>
<p>The <code>WaveManager</code> is now ready to be started. Calling <code>start()</code> will start processing audio in a new thread.</p>
<pre>waveManager.start();</pre>
<p>Calling <code>stop()</code> will stop this thread.</p>
<pre>waveManager.stop();</pre>
</div>
<!-- Versioning -->
<div id="deployment" class="container-fluid text-left">
<h2>Depoyment</h2>
<hr>
<p>Tactile Waves has been tested on a Moto G5 Plus running Android 7.0 on a Snapdragon 625 as well as a Windows laptop with an Intel i7-8550U processor. Real-time operation has been confirmed on these devices. More Android device tests will be performed in the near future, but any modern Android device should be more than capable of processing audio in real-time with Tactile Waves.</p>
<p>The built-in StopWatch class can be used in a WaveFrameListener object to measure the elapsed time between completed audio frames, to ensure real-time operation on your device/system.</p>
</div>
<!-- Versioning -->
<div id="versions" class="container-fluid text-left">
<h2>Versioning</h2>
<ul style="list-style-type:square">
<li><p>Version 1.0.1 - 2018-03-22<br>Minor changes and fixes, see the <a href="https://github.com/Funkatronics/TactileWaves/blob/master/Changelog.md">changelog</a> for more info</p></li>
</ul>
<ul style="list-style-type:square">
<li><p>Version 1.0.0 - 2018-03-09<br>First public release</p></li>
</ul>
</div>
<!-- Authors -->
<div id="authors" class="container-fluid text-left">
<h2>Authors</h2>
<ul style="list-style-type:square">
<li><p>Marco Martinez (Funkatronics) - <a href="https://funkatronics.github.io">website</a></p></li>
</ul>
</div>
<!-- License -->
<div id="license" class="container-fluid text-left">
<h2>License</h2>
<p>This software is licensed under the GNU General Public License - see the <a href="https://github.com/Funkatronics/TactileWaves/blob/master/license.txt">license.txt</a> file for details</p>
</div>
<!-- Funding -->
<div id="funding" class="container-fluid text-left">
<h2>Funding</h2>
<p>This project was funded by a Creative Works Award from <a href="http://csuventures.org">CSU Ventures</a>.</p>
</div>
<!-- Acknowledgments -->
<div id="credits" class="container-fluid text-left">
<h2>Acknowledgments</h2>
<ul style="list-style-type:square">
<li><p>Joren Six for his <a href="https://github.com/JorenSix/TarsosDSP">TarsosDSP</a> Library that provided an excellent learning resource in the early days of my thesis</p></li>
<li><p>JJ Moritz at <a href="http://www.sapienllc.com/">Sapien, LLC</a> for bringing me into CSU's sensory substitution research and providing assistance and resources throughout the project</p></li>
<li><p>Dr. Leslie Stone-Roy and Dr. John Williams at Colorado State University for their advice and guidance</p></li>
</ul>
</div>
<!-- Contact -->
<div id="contact" class="container-fluid text-left bg-grey" style="background-color: #424242;">
<h2>CONTACT</h2>
<hr>
<div class="row">
<div class="col-sm-5">
<p>Drop me a note:</p>
<p><span class="glyphicon glyphicon-map-marker"></span> Denver, CO</p>
<p><span class="glyphicon glyphicon-envelope"></span> [email protected]</p>
</div>
<div class="col-sm-7 slideanim">
<form action="https://formspree.io/[email protected]" method="POST">
<input type="hidden" name="_subject" value="New Contact from Tactile Waves Web Page" />
<input type="hidden" name="_format" value="plain" />
<input type="hidden" name="_next" value="//Funkatronics.github.io/TactileWaves/web/thankyou.html" />
<div class="row">
<div class="col-sm-6 form-group">
<input class="form-control" name="name" placeholder="Name" type="text" required autofocus />
</div>
<div class="col-sm-6 form-group">
<input class="form-control" name="email" placeholder="Email" type="email" required />
</div>
</div>
<textarea class="form-control" name="comments" placeholder="Comment" rows="5" required ></textarea>
<br>
<div class="row">
<div class="col-sm-12 form-group">
<input class="btn btn-default pull-right" type="submit" value="Send">
</div>
</div>
</form>
</div>
</div>
</div>
<!-- Footer -->
<footer class="container-fluid text-center">
<a href="#myPage" title="To Top">
<span class="glyphicon glyphicon-chevron-up"></span>
</a>
</footer>
<script>
$(document).ready(function(){
// Add smooth scrolling to all links in navbar + footer link
$(".navbar a, footer a[href='#myPage']").on('click', function(event) {
// Make sure this.hash has a value before overriding default behavior
if (this.hash !== "") {
// Prevent default anchor click behavior
event.preventDefault();
// Store hash
var hash = this.hash;
// Using jQuery's animate() method to add smooth page scroll
// The optional number (900) specifies the number of milliseconds it takes to scroll to the specified area
$('html, body').animate({
scrollTop: $(hash).offset().top
}, 900, function(){
// Add hash (#) to URL when done scrolling (default click behavior)
window.location.hash = hash;
});
} // End if
});
$(window).scroll(function() {
$(".slideanim").each(function(){
var pos = $(this).offset().top;
var winTop = $(window).scrollTop();
if (pos < winTop + 600) {
$(this).addClass("slide");
}
});
});
})
</script>
</body>
</html>