├── .gitignore ├── .postcssrc ├── LICENSE ├── README.md ├── old ├── css │ ├── buttonStyle.css │ ├── normalize.css │ ├── rangeStyle.css │ └── style.css ├── images │ └── favicon.ico ├── index.html ├── js │ └── functions.js └── php │ ├── getSources.php │ └── upload.php ├── package-lock.json ├── package.json └── src ├── demo-songs ├── 0.mp3 ├── 1.mp3 ├── 2.mp3 ├── 3.mp3 ├── 4.mp3 └── 5.mp3 ├── favicon.png ├── index.html ├── index.js ├── index.styl ├── logo.svg └── preview.png /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .cache 3 | dist 4 | -------------------------------------------------------------------------------- /.postcssrc: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": { 3 | "autoprefixer": {} 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Tanasoaia Teodor Andrei 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. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 |
5 |
6 | 7 | # audio-visualizer 8 | 9 | ![Preview](./src/preview.png) 10 | 11 | A web audio visualizer experiment 12 | 13 | You can find the working website here: https://teoxoy.github.io/audio-visualizer 14 | 15 | I recommend using the Stereo Mix feature in Windows to route the sound to the visualizer 16 | PS: Stereo Mix doesn't work with digital audio sources 17 | 18 | The `old` folder contains the original project I wrote in highschool 19 | 20 | ## Demo Songs (Free Copyright Music) 21 | 22 | | Nr | Title | Artist | Link | 23 | | --- | ---------------- | ---------------- | ---------------------------------------------------------------- | 24 | | 0 | And So It Begins | Artificial.Music | https://soundcloud.com/artificial-music/and-so-it-begins | 25 | | 1 | Dreams | Joakim Karud | https://soundcloud.com/joakimkarud/dreams-1 | 26 | | 2 | Vibe With Me | Joakim Karud | https://soundcloud.com/joakimkarud/vibe-with-me/ | 27 | | 3 | Rêveur | Peyruis | https://soundcloud.com/peyruis/peyruis-reveur-1/ | 28 | | 4 | Focused | Kontekst | https://soundcloud.com/kontekstmusic/focused | 29 | | 5 | Crying Over You | Chris Morrow 4 | https://soundcloud.com/chris-morrow-3/hip-hop-rap-instrumental-2 | 30 | 31 | # Copyright notice 32 | 33 | All audio assets used in this project belong to their respective artists and 34 | are subject to the Creative Commons License. 35 | -------------------------------------------------------------------------------- /old/css/buttonStyle.css: -------------------------------------------------------------------------------- 1 | .styledButton { 2 | background-color:#ffffff; 3 | border:1px solid #000000; 4 | display:inline-block; 5 | cursor:pointer; 6 | color:#000000; 7 | font-family:Arial; 8 | font-size:15px; 9 | padding:6px 28px; 10 | text-decoration:none; 11 | } 12 | .styledButton:hover { 13 | background-color: lightgray; 14 | } 15 | .styledButton:active { 16 | position:relative; 17 | top:1px; 18 | } 19 | 20 | input[type=file].styledButton { 21 | box-sizing: border-box; 22 | } 23 | 24 | input[type=file].styledButton::-webkit-file-upload-button { 25 | width: 0; 26 | padding: 0; 27 | margin: 0; 28 | -webkit-appearance: none; 29 | border: none; 30 | } 31 | 32 | .lightGreyBackground { 33 | background-color: lightgrey; 34 | } -------------------------------------------------------------------------------- /old/css/normalize.css: -------------------------------------------------------------------------------- 1 | /*! normalize.css v4.1.1 | MIT License | github.com/necolas/normalize.css */ 2 | 3 | /** 4 | * 1. Change the default font family in all browsers (opinionated). 5 | * 2. Prevent adjustments of font size after orientation changes in IE and iOS. 6 | */ 7 | 8 | html { 9 | font-family: sans-serif; /* 1 */ 10 | -ms-text-size-adjust: 100%; /* 2 */ 11 | -webkit-text-size-adjust: 100%; /* 2 */ 12 | } 13 | 14 | /** 15 | * Remove the margin in all browsers (opinionated). 16 | */ 17 | 18 | body { 19 | margin: 0; 20 | } 21 | 22 | /* HTML5 display definitions 23 | ========================================================================== */ 24 | 25 | /** 26 | * Add the correct display in IE 9-. 27 | * 1. Add the correct display in Edge, IE, and Firefox. 28 | * 2. Add the correct display in IE. 29 | */ 30 | 31 | article, 32 | aside, 33 | details, /* 1 */ 34 | figcaption, 35 | figure, 36 | footer, 37 | header, 38 | main, /* 2 */ 39 | menu, 40 | nav, 41 | section, 42 | summary { /* 1 */ 43 | display: block; 44 | } 45 | 46 | /** 47 | * Add the correct display in IE 9-. 48 | */ 49 | 50 | audio, 51 | canvas, 52 | progress, 53 | video { 54 | display: inline-block; 55 | } 56 | 57 | /** 58 | * Add the correct display in iOS 4-7. 59 | */ 60 | 61 | audio:not([controls]) { 62 | display: none; 63 | height: 0; 64 | } 65 | 66 | /** 67 | * Add the correct vertical alignment in Chrome, Firefox, and Opera. 68 | */ 69 | 70 | progress { 71 | vertical-align: baseline; 72 | } 73 | 74 | /** 75 | * Add the correct display in IE 10-. 76 | * 1. Add the correct display in IE. 77 | */ 78 | 79 | template, /* 1 */ 80 | [hidden] { 81 | display: none; 82 | } 83 | 84 | /* Links 85 | ========================================================================== */ 86 | 87 | /** 88 | * 1. Remove the gray background on active links in IE 10. 89 | * 2. Remove gaps in links underline in iOS 8+ and Safari 8+. 90 | */ 91 | 92 | a { 93 | background-color: transparent; /* 1 */ 94 | -webkit-text-decoration-skip: objects; /* 2 */ 95 | } 96 | 97 | /** 98 | * Remove the outline on focused links when they are also active or hovered 99 | * in all browsers (opinionated). 100 | */ 101 | 102 | a:active, 103 | a:hover { 104 | outline-width: 0; 105 | } 106 | 107 | /* Text-level semantics 108 | ========================================================================== */ 109 | 110 | /** 111 | * 1. Remove the bottom border in Firefox 39-. 112 | * 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari. 113 | */ 114 | 115 | abbr[title] { 116 | border-bottom: none; /* 1 */ 117 | text-decoration: underline; /* 2 */ 118 | text-decoration: underline dotted; /* 2 */ 119 | } 120 | 121 | /** 122 | * Prevent the duplicate application of `bolder` by the next rule in Safari 6. 123 | */ 124 | 125 | b, 126 | strong { 127 | font-weight: inherit; 128 | } 129 | 130 | /** 131 | * Add the correct font weight in Chrome, Edge, and Safari. 132 | */ 133 | 134 | b, 135 | strong { 136 | font-weight: bolder; 137 | } 138 | 139 | /** 140 | * Add the correct font style in Android 4.3-. 141 | */ 142 | 143 | dfn { 144 | font-style: italic; 145 | } 146 | 147 | /** 148 | * Correct the font size and margin on `h1` elements within `section` and 149 | * `article` contexts in Chrome, Firefox, and Safari. 150 | */ 151 | 152 | h1 { 153 | font-size: 2em; 154 | margin: 0.67em 0; 155 | } 156 | 157 | /** 158 | * Add the correct background and color in IE 9-. 159 | */ 160 | 161 | mark { 162 | background-color: #ff0; 163 | color: #000; 164 | } 165 | 166 | /** 167 | * Add the correct font size in all browsers. 168 | */ 169 | 170 | small { 171 | font-size: 80%; 172 | } 173 | 174 | /** 175 | * Prevent `sub` and `sup` elements from affecting the line height in 176 | * all browsers. 177 | */ 178 | 179 | sub, 180 | sup { 181 | font-size: 75%; 182 | line-height: 0; 183 | position: relative; 184 | vertical-align: baseline; 185 | } 186 | 187 | sub { 188 | bottom: -0.25em; 189 | } 190 | 191 | sup { 192 | top: -0.5em; 193 | } 194 | 195 | /* Embedded content 196 | ========================================================================== */ 197 | 198 | /** 199 | * Remove the border on images inside links in IE 10-. 200 | */ 201 | 202 | img { 203 | border-style: none; 204 | } 205 | 206 | /** 207 | * Hide the overflow in IE. 208 | */ 209 | 210 | svg:not(:root) { 211 | overflow: hidden; 212 | } 213 | 214 | /* Grouping content 215 | ========================================================================== */ 216 | 217 | /** 218 | * 1. Correct the inheritance and scaling of font size in all browsers. 219 | * 2. Correct the odd `em` font sizing in all browsers. 220 | */ 221 | 222 | code, 223 | kbd, 224 | pre, 225 | samp { 226 | font-family: monospace, monospace; /* 1 */ 227 | font-size: 1em; /* 2 */ 228 | } 229 | 230 | /** 231 | * Add the correct margin in IE 8. 232 | */ 233 | 234 | figure { 235 | margin: 1em 40px; 236 | } 237 | 238 | /** 239 | * 1. Add the correct box sizing in Firefox. 240 | * 2. Show the overflow in Edge and IE. 241 | */ 242 | 243 | hr { 244 | box-sizing: content-box; /* 1 */ 245 | height: 0; /* 1 */ 246 | overflow: visible; /* 2 */ 247 | } 248 | 249 | /* Forms 250 | ========================================================================== */ 251 | 252 | /** 253 | * 1. Change font properties to `inherit` in all browsers (opinionated). 254 | * 2. Remove the margin in Firefox and Safari. 255 | */ 256 | 257 | button, 258 | input, 259 | select, 260 | textarea { 261 | font: inherit; /* 1 */ 262 | margin: 0; /* 2 */ 263 | } 264 | 265 | /** 266 | * Restore the font weight unset by the previous rule. 267 | */ 268 | 269 | optgroup { 270 | font-weight: bold; 271 | } 272 | 273 | /** 274 | * Show the overflow in IE. 275 | * 1. Show the overflow in Edge. 276 | */ 277 | 278 | button, 279 | input { /* 1 */ 280 | overflow: visible; 281 | } 282 | 283 | /** 284 | * Remove the inheritance of text transform in Edge, Firefox, and IE. 285 | * 1. Remove the inheritance of text transform in Firefox. 286 | */ 287 | 288 | button, 289 | select { /* 1 */ 290 | text-transform: none; 291 | } 292 | 293 | /** 294 | * 1. Prevent a WebKit bug where (2) destroys native `audio` and `video` 295 | * controls in Android 4. 296 | * 2. Correct the inability to style clickable types in iOS and Safari. 297 | */ 298 | 299 | button, 300 | html [type="button"], /* 1 */ 301 | [type="reset"], 302 | [type="submit"] { 303 | -webkit-appearance: button; /* 2 */ 304 | } 305 | 306 | /** 307 | * Remove the inner border and padding in Firefox. 308 | */ 309 | 310 | button::-moz-focus-inner, 311 | [type="button"]::-moz-focus-inner, 312 | [type="reset"]::-moz-focus-inner, 313 | [type="submit"]::-moz-focus-inner { 314 | border-style: none; 315 | padding: 0; 316 | } 317 | 318 | /** 319 | * Restore the focus styles unset by the previous rule. 320 | */ 321 | 322 | button:-moz-focusring, 323 | [type="button"]:-moz-focusring, 324 | [type="reset"]:-moz-focusring, 325 | [type="submit"]:-moz-focusring { 326 | outline: 1px dotted ButtonText; 327 | } 328 | 329 | /** 330 | * Change the border, margin, and padding in all browsers (opinionated). 331 | */ 332 | 333 | fieldset { 334 | border: 1px solid #c0c0c0; 335 | margin: 0 2px; 336 | padding: 0.35em 0.625em 0.75em; 337 | } 338 | 339 | /** 340 | * 1. Correct the text wrapping in Edge and IE. 341 | * 2. Correct the color inheritance from `fieldset` elements in IE. 342 | * 3. Remove the padding so developers are not caught out when they zero out 343 | * `fieldset` elements in all browsers. 344 | */ 345 | 346 | legend { 347 | box-sizing: border-box; /* 1 */ 348 | color: inherit; /* 2 */ 349 | display: table; /* 1 */ 350 | max-width: 100%; /* 1 */ 351 | padding: 0; /* 3 */ 352 | white-space: normal; /* 1 */ 353 | } 354 | 355 | /** 356 | * Remove the default vertical scrollbar in IE. 357 | */ 358 | 359 | textarea { 360 | overflow: auto; 361 | } 362 | 363 | /** 364 | * 1. Add the correct box sizing in IE 10-. 365 | * 2. Remove the padding in IE 10-. 366 | */ 367 | 368 | [type="checkbox"], 369 | [type="radio"] { 370 | box-sizing: border-box; /* 1 */ 371 | padding: 0; /* 2 */ 372 | } 373 | 374 | /** 375 | * Correct the cursor style of increment and decrement buttons in Chrome. 376 | */ 377 | 378 | [type="number"]::-webkit-inner-spin-button, 379 | [type="number"]::-webkit-outer-spin-button { 380 | height: auto; 381 | } 382 | 383 | /** 384 | * 1. Correct the odd appearance in Chrome and Safari. 385 | * 2. Correct the outline style in Safari. 386 | */ 387 | 388 | [type="search"] { 389 | -webkit-appearance: textfield; /* 1 */ 390 | outline-offset: -2px; /* 2 */ 391 | } 392 | 393 | /** 394 | * Remove the inner padding and cancel buttons in Chrome and Safari on OS X. 395 | */ 396 | 397 | [type="search"]::-webkit-search-cancel-button, 398 | [type="search"]::-webkit-search-decoration { 399 | -webkit-appearance: none; 400 | } 401 | 402 | /** 403 | * Correct the text style of placeholders in Chrome, Edge, and Safari. 404 | */ 405 | 406 | ::-webkit-input-placeholder { 407 | color: inherit; 408 | opacity: 0.54; 409 | } 410 | 411 | /** 412 | * 1. Correct the inability to style clickable types in iOS and Safari. 413 | * 2. Change font properties to `inherit` in Safari. 414 | */ 415 | 416 | ::-webkit-file-upload-button { 417 | -webkit-appearance: button; /* 1 */ 418 | font: inherit; /* 2 */ 419 | } -------------------------------------------------------------------------------- /old/css/rangeStyle.css: -------------------------------------------------------------------------------- 1 | input[type=range].styledRange { 2 | -webkit-appearance: none; 3 | width: 100%; 4 | margin: 6.5px 0; 5 | } 6 | input[type=range][orient=vertical].styledRange { 7 | transform:rotate(270deg); 8 | } 9 | input[type=range].styledRange::-webkit-slider-runnable-track { 10 | width: 100%; 11 | height: 9px; 12 | cursor: pointer; 13 | box-shadow: 1px 1px 1px rgba(0, 0, 0, 0), 0px 0px 1px rgba(13, 13, 13, 0); 14 | border-radius: 0px; 15 | border: 1px solid #010101; 16 | } 17 | .fullBackground{ 18 | background: linear-gradient(to right, black 100%, white 100%); 19 | } 20 | input[type=range].styledRange::-webkit-slider-thumb { 21 | box-shadow: 1px 1px 1px rgba(0, 0, 0, 0), 0px 0px 1px rgba(13, 13, 13, 0); 22 | border: 1px solid #000000; 23 | height: 22px; 24 | width: 9px; 25 | border-radius: 0px; 26 | background: #ffffff; 27 | cursor: pointer; 28 | -webkit-appearance: none; 29 | margin-top: -7.5px; 30 | } 31 | input[type=range].styledRange::-moz-range-track { 32 | width: 100%; 33 | height: 9px; 34 | cursor: pointer; 35 | box-shadow: 1px 1px 1px rgba(0, 0, 0, 0), 0px 0px 1px rgba(13, 13, 13, 0); 36 | background: #ffffff; 37 | border-radius: 0px; 38 | border: 1px solid #010101; 39 | } 40 | input[type=range].styledRange::-moz-range-thumb { 41 | box-shadow: 1px 1px 1px rgba(0, 0, 0, 0), 0px 0px 1px rgba(13, 13, 13, 0); 42 | border: 1px solid #000000; 43 | height: 22px; 44 | width: 9px; 45 | border-radius: 0px; 46 | background: #ffffff; 47 | cursor: pointer; 48 | } 49 | input[type=range].styledRange::-ms-track { 50 | width: 100%; 51 | height: 9px; 52 | cursor: pointer; 53 | background: transparent; 54 | border-color: transparent; 55 | color: transparent; 56 | } 57 | input[type=range].styledRange::-ms-fill-lower { 58 | background: #e6e6e6; 59 | border: 1px solid #010101; 60 | border-radius: 0px; 61 | box-shadow: 1px 1px 1px rgba(0, 0, 0, 0), 0px 0px 1px rgba(13, 13, 13, 0); 62 | } 63 | input[type=range].styledRange::-ms-fill-upper { 64 | background: #ffffff; 65 | border: 1px solid #010101; 66 | border-radius: 0px; 67 | box-shadow: 1px 1px 1px rgba(0, 0, 0, 0), 0px 0px 1px rgba(13, 13, 13, 0); 68 | } 69 | input[type=range].styledRange::-ms-thumb { 70 | box-shadow: 1px 1px 1px rgba(0, 0, 0, 0), 0px 0px 1px rgba(13, 13, 13, 0); 71 | border: 1px solid #000000; 72 | height: 22px; 73 | width: 9px; 74 | border-radius: 0px; 75 | background: #ffffff; 76 | cursor: pointer; 77 | height: 9px; 78 | } 79 | input[type=range].styledRange:focus::-ms-fill-lower { 80 | background: #ffffff; 81 | } 82 | input[type=range].styledRange:focus::-ms-fill-upper { 83 | background: #ffffff; 84 | } -------------------------------------------------------------------------------- /old/css/style.css: -------------------------------------------------------------------------------- 1 | .wrap { 2 | display: block; 3 | width: 1600px; 4 | margin: 0 auto; 5 | } 6 | 7 | html { 8 | font-family: Arial; 9 | } 10 | 11 | * { 12 | user-select: none; 13 | outline: none; 14 | } 15 | 16 | #header{ 17 | padding: 10px; 18 | } 19 | 20 | #header p{ 21 | font-size: 50px; 22 | text-align: center; 23 | margin: 0px; 24 | } 25 | 26 | #content{ 27 | min-width: 1600px; 28 | border-left: 1px solid black; 29 | border-right: 1px solid black; 30 | } 31 | 32 | /*Canvas*/ 33 | #canvas{ 34 | width: 1600px; 35 | height: 1024px; 36 | display: block; 37 | } 38 | 39 | /*Timeline*/ 40 | #timelineDiv{ 41 | position: relative; 42 | height: 30px; 43 | margin: 0; 44 | } 45 | 46 | #timeline{ 47 | top: 0px; 48 | position: absolute; 49 | display: block; 50 | margin: 0; 51 | } 52 | 53 | #timeline::-webkit-slider-runnable-track{ 54 | height: 22px; 55 | border-left: 0px; 56 | border-right: 0px; 57 | } 58 | 59 | #timeline::-webkit-slider-thumb{ 60 | margin-top: -1px; 61 | } 62 | 63 | #currentTimeLabel{ 64 | display: inline-block; 65 | padding-left: 10px; 66 | left: 0px; 67 | top: 30px; 68 | margin: 0; 69 | position: absolute; 70 | } 71 | 72 | #durationLabel{ 73 | right: 0px; 74 | position: absolute; 75 | display: inline-block; 76 | padding-right: 10px; 77 | top: 30px; 78 | margin: 0; 79 | } 80 | 81 | /*EQ*/ 82 | #eq{ 83 | height: 140px; 84 | width: 600px; 85 | display: block; 86 | position: relative; 87 | margin: 0 auto; 88 | } 89 | 90 | /*Control Buttons*/ 91 | #controlButtons{ 92 | left: 172.5px; 93 | position: absolute; 94 | width: 255px; 95 | display: inline-block; 96 | top: 0px; 97 | } 98 | 99 | /*Sliders*/ 100 | .sliders{ 101 | position: absolute; 102 | top: 20px; 103 | width: 100px; 104 | height: 120px; 105 | } 106 | 107 | .sliders input{ 108 | position: absolute; 109 | top: 50px; 110 | width: 100px; 111 | } 112 | 113 | /*Slider Labels*/ 114 | #labels{ 115 | width: 600px; 116 | height: 20px; 117 | } 118 | 119 | #labels p{ 120 | text-align: center; 121 | margin-top: 0; 122 | margin-bottom: 0; 123 | font-weight: bold; 124 | font-size: 18px; 125 | width: 20px; 126 | height: 20px; 127 | position: absolute; 128 | } 129 | 130 | #labels p:nth-child(1){ 131 | left: 8.5px; 132 | } 133 | 134 | #labels p:nth-child(2){ 135 | left: 39px; 136 | } 137 | 138 | #labels p:nth-child(3){ 139 | left: 69.5px; 140 | } 141 | 142 | #labels p:nth-child(4){ 143 | right: 69.5px; 144 | } 145 | 146 | #labels p:nth-child(5){ 147 | right: 39px; 148 | } 149 | 150 | #labels p:nth-child(6){ 151 | right: 8.5px; 152 | } 153 | 154 | /*First set of sliders*/ 155 | #eqSliders{ 156 | left: 0px; 157 | } 158 | #eqHigh{ 159 | left: -30px; 160 | } 161 | #eqMid{ 162 | left: 0px; 163 | } 164 | #eqLow{ 165 | left: 30px; 166 | } 167 | 168 | /*Second set of sliders*/ 169 | #gainSliders{ 170 | right: 0px; 171 | } 172 | #eqLeft{ 173 | left: -30px; 174 | } 175 | #eqRight{ 176 | left: 0px; 177 | } 178 | #eqMain{ 179 | left: 30px; 180 | } 181 | 182 | /*Form*/ 183 | #uploadForm { 184 | height: 35px; 185 | width: 600px; 186 | margin: 0 auto; 187 | display: block; 188 | } 189 | 190 | #uploadForm p{ 191 | width: 91px; 192 | display: inline-block; 193 | margin: 0; 194 | } 195 | 196 | #uploadForm input[type=file]{ 197 | width: 400px; 198 | display: inline-block; 199 | } 200 | 201 | #uploadForm input[type=submit]{ 202 | width: 100px; 203 | display: inline-block; 204 | } 205 | 206 | /*Sources*/ 207 | #sourceList { 208 | margin-top: 20px; 209 | display: block; 210 | width: 600px; 211 | margin: 0 auto; 212 | padding: 0; 213 | list-style: none; 214 | } 215 | 216 | #sourceList button{ 217 | width: 600px; 218 | border-bottom: 0; 219 | } -------------------------------------------------------------------------------- /old/images/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/teoxoy/audio-visualizer/e785922dbb71ab3c85f80840f8d0fc522b2118d1/old/images/favicon.ico -------------------------------------------------------------------------------- /old/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Audio Visualizer 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 22 | 23 | 24 |
25 | 26 |

0:00

27 |

0:00

28 |
29 |
30 |
31 |

H

32 |

M

33 |

L

34 |

L

35 |

R

36 |

M

37 |
38 |
39 | 40 | 41 | 42 |
43 |
44 | 45 | 46 | 47 |
48 |
49 | 50 | 51 | 52 |
53 |
54 |
55 |

Upload:

56 | 57 | 58 |
59 | 60 |
61 | 62 | 63 | -------------------------------------------------------------------------------- /old/js/functions.js: -------------------------------------------------------------------------------- 1 | //HTML IDs 2 | const MEDIA_ID = '#audio', 3 | TIMELINE_ID = '#timeline'; 4 | 5 | //Cookie Functions 6 | // function writeCookie(name, value, days) { 7 | // var date, expires; 8 | // if (days) { 9 | // date = new Date(); 10 | // date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000)); 11 | // expires = "; expires=" + date.toGMTString(); 12 | // } else { 13 | // expires = ""; 14 | // } 15 | // document.cookie = name + "=" + value + expires + "; path=/"; 16 | // } 17 | 18 | // function readCookie(name) { 19 | // var i, c, ca, nameEQ = name + "="; 20 | // ca = document.cookie.split(';'); 21 | // for (i = 0; i < ca.length; i++) { 22 | // c = ca[i]; 23 | // while (c.charAt(0) == ' ') { 24 | // c = c.substring(1, c.length); 25 | // } 26 | // if (c.indexOf(nameEQ) == 0) { 27 | // return c.substring(nameEQ.length, c.length); 28 | // } 29 | // } 30 | // return ''; 31 | // } 32 | 33 | $(document).ready(function () { 34 | var _buffered = 0; 35 | var _currentTrack = 0; 36 | var _totalTracks = 0; 37 | var _media = $(MEDIA_ID)[0]; 38 | var _audioContext = new AudioContext(); 39 | var _canvas = $("#canvas")[0]; 40 | var _canvasContext = _canvas.getContext("2d"); 41 | var _nextUnusedID = 0; 42 | 43 | var gainDb = -40.0; 44 | var bandSplit = [360, 3600]; 45 | 46 | //Dynamic CSS Sheet 47 | var _styleSheet = (function () { 48 | var style = document.createElement("style"); 49 | style.appendChild(document.createTextNode("")); 50 | document.head.appendChild(style); 51 | return style.sheet; 52 | })(); 53 | 54 | setInterval(update, 16.6); 55 | setInterval(getSources, 5000); 56 | 57 | function getSources() { 58 | $.ajax({ 59 | type: 'GET', 60 | url: '/audioVisualizer/php/getSources.php', 61 | success: function (sources) { 62 | var existent = []; 63 | $(".sources").each(function (i, e) { existent[i] = e.innerHTML; }); 64 | var newSources = []; 65 | $.each(JSON.parse(sources), function (i, source) { 66 | if ($.inArray(source, existent) == -1) { 67 | newSources[newSources.length] = source; 68 | } 69 | }); 70 | var unavailableSources = []; 71 | $.each(existent, function (i, source) { 72 | if ($.inArray(source, JSON.parse(sources)) == -1) { 73 | unavailableSources[unavailableSources.length] = source; 74 | } 75 | }); 76 | $.each(newSources, function (i, source) { 77 | $("#sourceList").append("
  • "); 78 | $("#source_" + _nextUnusedID).click(function () { 79 | _media.src = "uploads/" + this.innerHTML; 80 | if (_currentTrack < _totalTracks) 81 | $("#source_" + _currentTrack).removeClass("lightGreyBackground"); 82 | _currentTrack = this.id.split("_")[1]; 83 | $("#" + this.id).addClass("lightGreyBackground"); 84 | _media.load(); 85 | _media.play(); 86 | }); 87 | _nextUnusedID++; 88 | }); 89 | $(".sources").each(function (i, e) { 90 | if ($.inArray(e.innerHTML, unavailableSources) != -1) { 91 | $(e).parent().remove(); 92 | } 93 | }); 94 | regenerateSourceIDs() 95 | } 96 | }); 97 | } 98 | 99 | getSources(); 100 | 101 | function regenerateSourceIDs() { 102 | var id = 0; 103 | $(".sources").each(function (i, e) { 104 | e.id = "source_" + id; 105 | id++; 106 | }); 107 | _totalTracks = id; 108 | } 109 | 110 | $("#uploadForm").submit(function () { 111 | event.preventDefault(); 112 | for (var i = 0; i < $("#fileToUpload").prop("files").length; i++) { 113 | var formData = new FormData($(this)[0]); 114 | formData.append("fileToUpload", $("#fileToUpload").prop("files")[i]); 115 | $.ajax({ 116 | type: 'POST', 117 | url: '/audioVisualizer/php/upload.php', 118 | data: formData, 119 | processData: false, 120 | contentType: false 121 | }); 122 | } 123 | $("#fileToUpload").val(""); 124 | }); 125 | 126 | //Left Analyzer 127 | var leftAnalyser = _audioContext.createAnalyser(); 128 | leftAnalyser.fftSize = 2048; 129 | leftAnalyser.smoothingTimeConstant = 0.95; 130 | 131 | //Right Analyzer 132 | var rightAnalyser = _audioContext.createAnalyser(); 133 | rightAnalyser.fftSize = 2048; 134 | rightAnalyser.smoothingTimeConstant = 0.95; 135 | 136 | //Low Analyzer 137 | var lowAnalyzer = _audioContext.createAnalyser(); 138 | lowAnalyzer.fftSize = 64; 139 | lowAnalyzer.smoothingTimeConstant = 0.95; 140 | 141 | //////////////////////EQ////////////////////// 142 | 143 | //HighFilter 144 | var highBand = _audioContext.createBiquadFilter(); 145 | highBand.type = "lowshelf"; 146 | highBand.frequency.value = bandSplit[0]; 147 | highBand.gain.value = gainDb; 148 | 149 | //LowFilter 150 | var lowBand = _audioContext.createBiquadFilter(); 151 | lowBand.type = "highshelf"; 152 | lowBand.frequency.value = bandSplit[1]; 153 | lowBand.gain.value = gainDb; 154 | 155 | //MidFilter 156 | var midBand = _audioContext.createGain(); 157 | var hInvert = _audioContext.createGain(); 158 | hInvert.gain.value = -1.0; 159 | var lInvert = _audioContext.createGain(); 160 | lInvert.gain.value = -1.0; 161 | 162 | //Connections 163 | var audioSrc = _audioContext.createMediaElementSource(_media); 164 | audioSrc.connect(highBand); 165 | audioSrc.connect(lowBand); 166 | audioSrc.connect(midBand); 167 | 168 | highBand.connect(hInvert); 169 | lowBand.connect(lInvert); 170 | hInvert.connect(midBand); 171 | lInvert.connect(midBand); 172 | 173 | //HighGain, MidGain, LowGain 174 | var highGain = _audioContext.createGain(); 175 | var midGain = _audioContext.createGain(); 176 | var lowGain = _audioContext.createGain(); 177 | 178 | highBand.connect(highGain); 179 | midBand.connect(midGain); 180 | lowBand.connect(lowGain); 181 | 182 | var sum = _audioContext.createGain(); 183 | lowGain.connect(lowAnalyzer); 184 | lowAnalyzer.connect(sum); 185 | midGain.connect(sum); 186 | highGain.connect(sum); 187 | 188 | //LeftGain, RightGain, MainGain 189 | var leftGain = _audioContext.createGain(); 190 | var rightGain = _audioContext.createGain(); 191 | var mainGain = _audioContext.createGain(); 192 | 193 | var splitter = _audioContext.createChannelSplitter(2); 194 | var merger = _audioContext.createChannelMerger(2); 195 | 196 | sum.connect(mainGain); 197 | mainGain.connect(splitter); 198 | 199 | splitter.connect(leftGain, 0, 0); 200 | splitter.connect(rightGain, 1, 0); 201 | 202 | leftGain.connect(leftAnalyser); 203 | rightGain.connect(rightAnalyser); 204 | 205 | leftAnalyser.connect(merger, 0, 0); 206 | rightAnalyser.connect(merger, 0, 1); 207 | 208 | merger.connect(_audioContext.destination); 209 | 210 | var frequencyData0 = new Uint8Array(leftAnalyser.frequencyBinCount); 211 | var frequencyData1 = new Uint8Array(rightAnalyser.frequencyBinCount); 212 | var frequencyData2 = new Uint8Array(lowAnalyzer.frequencyBinCount); 213 | 214 | //EQ Inputs 215 | function changeGain(type, value) { 216 | switch (type) { 217 | case 'lowGain': lowGain.gain.value = value; break; 218 | case 'midGain': midGain.gain.value = value; break; 219 | case 'highGain': highGain.gain.value = value; break; 220 | case 'leftGain': leftGain.gain.value = value; break; 221 | case 'rightGain': rightGain.gain.value = value; break; 222 | case 'mainGain': mainGain.gain.value = value; break; 223 | } 224 | } 225 | //////////////////////////////////////////////////// 226 | 227 | function drawSliderProgress(slider) { 228 | var p = (slider.value / slider.max * 100).toFixed(2); 229 | var parts = ["background: linear-gradient(to right", " black " + p + "%", " white " + p + "%);"]; 230 | for (var i = 0; i < _styleSheet.rules.length; i++) { 231 | if (new RegExp("^#" + slider.id).test(_styleSheet.rules[i].selectorText)) { 232 | if ("#" + slider.id == TIMELINE_ID) { 233 | parts[2] = " lightgrey " + p + "%"; 234 | parts[3] = " lightgrey " + _buffered + "%"; 235 | parts[4] = " white " + _buffered + "%);"; 236 | } 237 | _styleSheet.removeRule(i); 238 | } 239 | } 240 | _styleSheet.addRule("#" + slider.id + "::-webkit-slider-runnable-track", parts.join(",")); 241 | } 242 | 243 | //Events 244 | $(TIMELINE_ID).on("input", function () { if ($(MEDIA_ID).attr('src')) _media.currentTime = this.value; else this.value = 0; }); 245 | $(MEDIA_ID).on("timeupdate", function () { 246 | $(TIMELINE_ID).val(this.currentTime); 247 | drawSliderProgress($(TIMELINE_ID)[0]); 248 | }) 249 | .on("progress", function () { if (_media.buffered.length > 0) _buffered = (_media.buffered.end(_media.buffered.length - 1) / _media.duration * 100).toFixed(2); }) 250 | .on("loadedmetadata", function () { this.currentTime = 0; _buffered = 0; $(TIMELINE_ID).attr('max', this.duration); $('#durationLabel').html((this.duration / 60).toFixed(2).replace(".", ":")); }) 251 | .on("ended", function () { $("#nextTrackButton").trigger("click"); }) 252 | .on("play", function () { $("#playPauseButton i").html("pause"); }) 253 | .on("pause", function () { $("#playPauseButton i").html("play_arrow"); }); 254 | $("#eqHigh").on("input", function () { changeGain("highGain", this.value); drawSliderProgress(this); }); 255 | $("#eqMid").on("input", function () { changeGain("midGain", this.value); drawSliderProgress(this); }); 256 | $("#eqLow").on("input", function () { changeGain("lowGain", this.value); drawSliderProgress(this); }); 257 | $("#eqLeft").on("input", function () { changeGain("leftGain", this.value); drawSliderProgress(this); }); 258 | $("#eqRight").on("input", function () { changeGain("rightGain", this.value); drawSliderProgress(this); }); 259 | $("#eqMain").on("input", function () { changeGain("mainGain", this.value); drawSliderProgress(this); }); 260 | $("#playPauseButton").click(function () { if (_media.paused) _media.play(); else _media.pause(); }); 261 | $("#previousTrackButton").click(function () { 262 | var id = _currentTrack == 0 ? _totalTracks - 1 : _currentTrack - 1; 263 | $("#source_" + id).trigger("click"); 264 | }); 265 | $("#nextTrackButton").click(function () { 266 | var id = _currentTrack == _totalTracks - 1 ? 0 : parseInt(_currentTrack) + 1; 267 | $("#source_" + id).trigger("click"); 268 | }); 269 | 270 | //Canvas Functions 271 | function drawCanvasLine(x0, x1, y) { 272 | _canvasContext.beginPath(); 273 | _canvasContext.moveTo(x0, y); 274 | _canvasContext.lineTo(x1, y); 275 | _canvasContext.stroke(); 276 | } 277 | 278 | function drawCanvasArc(i, w, h, r, a, b) { 279 | var m = Math.PI / 12; //15 degrees 280 | var o = m * (i % 24); 281 | _canvasContext.beginPath(); 282 | _canvasContext.arc(w, h, r, m * a + o, m * b + o); 283 | _canvasContext.stroke(); 284 | } 285 | //var test = 0; 286 | 287 | //Update Function 288 | function update() { 289 | //Get Frequency Data 290 | leftAnalyser.getByteFrequencyData(frequencyData0); 291 | rightAnalyser.getByteFrequencyData(frequencyData1); 292 | lowAnalyzer.getByteFrequencyData(frequencyData2); 293 | 294 | //if(test % 60 == 0 && _media.paused == false) console.log(frequencyData0); //for(var i = 0; i < frequencyData2.length; i++) console.log(eArr.next().value); 295 | var cT = _media.currentTime / 60; 296 | $('#currentTimeLabel').html(cT.toFixed(2).replace(".", ":")); 297 | 298 | _canvasContext.clearRect(0, 0, _canvas.width, _canvas.height); 299 | for (var i = 0; i < frequencyData0.length; i++) { 300 | drawCanvasLine(0, frequencyData0[i], _canvas.height - i); 301 | drawCanvasLine(_canvas.width, _canvas.width - frequencyData1[i], _canvas.height - i); 302 | } 303 | for (var i = 0; i < frequencyData2.length; i++) { 304 | var w = _canvas.width / 2; 305 | var h = _canvas.height / 2; 306 | var r = frequencyData2[i] * _canvas.height / 512; 307 | drawCanvasArc(i, w, h, r, 1, 5); 308 | drawCanvasArc(i, w, h, r, 7, 11); 309 | drawCanvasArc(i, w, h, r, 13, 17); 310 | drawCanvasArc(i, w, h, r, 19, 23); 311 | } 312 | } 313 | }); 314 | -------------------------------------------------------------------------------- /old/php/getSources.php: -------------------------------------------------------------------------------- 1 | 12 | -------------------------------------------------------------------------------- /old/php/upload.php: -------------------------------------------------------------------------------- 1 | 500000000) { 14 | echo "Your file is too large."; 15 | $uploadOk = 0; 16 | } 17 | // Allow certain file formats 18 | if($fileType != "mp3") { 19 | echo "Only mp3 files are allowed."; 20 | $uploadOk = 0; 21 | } 22 | // Check if $uploadOk is set to 0 by an error 23 | if ($uploadOk == 0) { 24 | echo "Your file was not uploaded."; 25 | // if everything is ok, try to upload file 26 | } else { 27 | if (move_uploaded_file($_FILES["fileToUpload"]["tmp_name"], $target_file)) { 28 | echo "The file ". basename( $_FILES["fileToUpload"]["name"]). " has been uploaded."; 29 | } else { 30 | echo "There was an error uploading your file."; 31 | } 32 | } 33 | ?> -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "audio-visualizer", 3 | "version": "1.0.0", 4 | "description": "A JS audio visualizer", 5 | "main": "index.js", 6 | "scripts": { 7 | "start": "parcel src/index.html --port 8080", 8 | "prebuild": "rimraf dist/*", 9 | "build": "parcel build src/index.html --public-url ./", 10 | "setupDist": "git worktree add dist gh-pages", 11 | "deploy": "cd dist && git add --all && git reset -- stats && git commit -m \"new version\" && git push origin gh-pages" 12 | }, 13 | "author": "Teoxoy", 14 | "license": "MIT", 15 | "browserslist": [ 16 | "last 2 Chrome versions", 17 | "last 2 Firefox versions", 18 | "last 2 Safari versions", 19 | "last 2 Edge versions" 20 | ], 21 | "dependencies": { 22 | "pixi.js": "^5.1.5" 23 | }, 24 | "devDependencies": { 25 | "autoprefixer": "^9.6.4", 26 | "parcel-bundler": "^1.12.4", 27 | "rimraf": "^3.0.0", 28 | "stylus": "^0.54.7" 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/demo-songs/0.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/teoxoy/audio-visualizer/e785922dbb71ab3c85f80840f8d0fc522b2118d1/src/demo-songs/0.mp3 -------------------------------------------------------------------------------- /src/demo-songs/1.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/teoxoy/audio-visualizer/e785922dbb71ab3c85f80840f8d0fc522b2118d1/src/demo-songs/1.mp3 -------------------------------------------------------------------------------- /src/demo-songs/2.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/teoxoy/audio-visualizer/e785922dbb71ab3c85f80840f8d0fc522b2118d1/src/demo-songs/2.mp3 -------------------------------------------------------------------------------- /src/demo-songs/3.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/teoxoy/audio-visualizer/e785922dbb71ab3c85f80840f8d0fc522b2118d1/src/demo-songs/3.mp3 -------------------------------------------------------------------------------- /src/demo-songs/4.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/teoxoy/audio-visualizer/e785922dbb71ab3c85f80840f8d0fc522b2118d1/src/demo-songs/4.mp3 -------------------------------------------------------------------------------- /src/demo-songs/5.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/teoxoy/audio-visualizer/e785922dbb71ab3c85f80840f8d0fc522b2118d1/src/demo-songs/5.mp3 -------------------------------------------------------------------------------- /src/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/teoxoy/audio-visualizer/e785922dbb71ab3c85f80840f8d0fc522b2118d1/src/favicon.png -------------------------------------------------------------------------------- /src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 9 | 10 | 11 | 12 | AudioVisualizer 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 |
    22 | 28 | 42 | 43 | 44 | 57 | 58 |

    Press H to toggle the UI

    59 |
    60 | 61 | 62 | 63 | 64 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import * as PIXI from 'pixi.js' 2 | import demoSongs from './demo-songs/*.mp3' 3 | 4 | const MARGIN = 8 5 | let trippyMode = false 6 | const rad15deg = Math.PI / 12 7 | let smallerSide 8 | 9 | PIXI.GRAPHICS_CURVES.adaptive = true 10 | PIXI.GRAPHICS_CURVES.maxLength = 5 11 | 12 | const app = new PIXI.Application({ 13 | view: document.getElementById('canvas'), 14 | antialias: true, 15 | resolution: window.devicePixelRatio, 16 | backgroundColor: 0x0f0f0f, 17 | autoDensity: true 18 | }) 19 | 20 | app.ticker.speed = 2 21 | 22 | window.addEventListener('resize', resize, false) 23 | resize() 24 | function resize() { 25 | app.renderer.resize(window.innerWidth, window.innerHeight) 26 | smallerSide = Math.min(window.innerWidth, window.innerHeight) 27 | } 28 | 29 | const graphics = new PIXI.Graphics() 30 | app.stage.addChild(graphics) 31 | 32 | const UI = document.getElementById('ui') 33 | function toggleUI() { 34 | if (!UI.style.visibility || UI.style.visibility === 'visible') UI.style.visibility = 'hidden' 35 | else UI.style.visibility = 'visible' 36 | } 37 | document.addEventListener('keydown', e => { 38 | if (e.keyCode === 72) toggleUI() 39 | }) 40 | 41 | document.getElementById('record').onclick = e => { 42 | if (navigator.mediaDevices) { 43 | navigator.mediaDevices 44 | .getUserMedia({ audio: true }) 45 | .then(stream => changeInput(e.target, stream)) 46 | .catch(err => console.log('The following gUM error occured: ' + err)) 47 | } else { 48 | console.log('getUserMedia not supported on your browser!') 49 | } 50 | } 51 | 52 | const songs = document.getElementsByClassName('song') 53 | for (const song of songs) { 54 | song.addEventListener('pointerdown', () => { 55 | changeInput(song, audioEl) 56 | }) 57 | } 58 | 59 | document.getElementById('trippy').onclick = e => { 60 | initAudioContext() 61 | 62 | trippyMode = !trippyMode 63 | if (trippyMode) { 64 | e.target.classList.add('active') 65 | 66 | lowAnalyzer.smoothingTimeConstant = 0.8 67 | highAnalyzer.smoothingTimeConstant = 0.88 68 | } else { 69 | e.target.classList.remove('active') 70 | 71 | lowAnalyzer.smoothingTimeConstant = 0.89 72 | highAnalyzer.smoothingTimeConstant = 0.87 73 | } 74 | } 75 | 76 | const audioEl = document.createElement('audio') 77 | document.body.appendChild(audioEl) 78 | 79 | let activeSongEl 80 | let audioSourceNode 81 | let mediaStreamAudioSourceNode 82 | let mediaElementAudioSourceNode 83 | 84 | function changeInput(htmlEl, input) { 85 | if (activeSongEl === htmlEl) return 86 | 87 | if (activeSongEl) activeSongEl.classList.remove('active') 88 | htmlEl.classList.add('active') 89 | activeSongEl = htmlEl 90 | 91 | initAudioContext() 92 | 93 | if (audioSourceNode !== undefined) audioSourceNode.disconnect() 94 | 95 | if (input instanceof MediaStream) { 96 | audioEl.pause() 97 | 98 | if (mediaStreamAudioSourceNode === undefined) { 99 | mediaStreamAudioSourceNode = audioCtx.createMediaStreamSource(input) 100 | } 101 | 102 | mediaStreamAudioSourceNode.connect(lowFilter) 103 | mediaStreamAudioSourceNode.connect(highFilter) 104 | audioSourceNode = mediaStreamAudioSourceNode 105 | } else if (input instanceof HTMLAudioElement) { 106 | audioEl.src = demoSongs[htmlEl.dataset.id] 107 | audioEl.play() 108 | 109 | if (mediaElementAudioSourceNode === undefined) { 110 | mediaElementAudioSourceNode = audioCtx.createMediaElementSource(input) 111 | } 112 | 113 | mediaElementAudioSourceNode.connect(lowFilter) 114 | mediaElementAudioSourceNode.connect(highFilter) 115 | mediaElementAudioSourceNode.connect(audioCtx.destination) 116 | audioSourceNode = mediaElementAudioSourceNode 117 | } 118 | } 119 | 120 | let audioCtx 121 | let lowFilter 122 | let highFilter 123 | let lowAnalyzer 124 | let highAnalyzer 125 | 126 | function initAudioContext() { 127 | if (audioCtx) return 128 | 129 | audioCtx = new AudioContext() 130 | 131 | lowAnalyzer = audioCtx.createAnalyser() 132 | lowAnalyzer.minDecibels = -80 133 | lowAnalyzer.maxDecibels = -20 134 | lowAnalyzer.fftSize = 32 135 | lowAnalyzer.smoothingTimeConstant = 0.89 136 | const lowFrequencyData = new Uint8Array(lowAnalyzer.frequencyBinCount) 137 | 138 | highAnalyzer = audioCtx.createAnalyser() 139 | highAnalyzer.minDecibels = -80 140 | highAnalyzer.maxDecibels = -20 141 | highAnalyzer.fftSize = 32 142 | highAnalyzer.smoothingTimeConstant = 0.87 143 | const highFrequencyData = new Uint8Array(highAnalyzer.frequencyBinCount) 144 | 145 | lowFilter = audioCtx.createBiquadFilter() 146 | lowFilter.type = 'lowpass' 147 | lowFilter.frequency.setValueAtTime(200, 0) 148 | 149 | highFilter = audioCtx.createBiquadFilter() 150 | highFilter.type = 'highpass' 151 | highFilter.frequency.setValueAtTime(200, 0) 152 | 153 | lowFilter.connect(lowAnalyzer) 154 | highFilter.connect(highAnalyzer) 155 | 156 | app.ticker.add(() => { 157 | graphics.clear() 158 | 159 | lowAnalyzer.getByteFrequencyData(lowFrequencyData) 160 | highAnalyzer.getByteFrequencyData(highFrequencyData) 161 | 162 | graphics.lineStyle(1.5, 0x009688) 163 | for (let i = 0; i < lowFrequencyData.length; i++) { 164 | if (lowFrequencyData[i] !== 0) { 165 | const R = (lowFrequencyData[i] * smallerSide) / 512 166 | if (trippyMode) graphics.lineStyle(1.5, 0xffffff * Math.random()) 167 | drawArcV1(R, 1, 5) 168 | drawArcV1(R, 7, 11) 169 | drawArcV1(R, 13, 17) 170 | drawArcV1(R, 19, 23) 171 | } 172 | } 173 | 174 | graphics.lineStyle(1.5, 0xff9800) 175 | for (let i = 0; i < highFrequencyData.length; i++) { 176 | if (highFrequencyData[i] !== 0) { 177 | const R = (highFrequencyData[i] * smallerSide) / 1024 178 | if (trippyMode) graphics.lineStyle(1.5, 0xffffff * Math.random()) 179 | drawArcV2(i, R, 1, 5) 180 | drawArcV2(i, R, 7, 11) 181 | drawArcV2(i, R, 13, 17) 182 | drawArcV2(i, R, 19, 23) 183 | } 184 | } 185 | }) 186 | } 187 | 188 | function drawArcV1(r, a, b) { 189 | const v = 0.75 - r / (smallerSide / 2 - MARGIN) 190 | const A = rad15deg * a + v 191 | const B = rad15deg * b - v 192 | if (B > A) { 193 | drawArc(r, A, B) 194 | } 195 | } 196 | 197 | function drawArcV2(i, r, a, b) { 198 | drawArc(r, rad15deg * (a + i), rad15deg * (b + i), true) 199 | } 200 | 201 | function drawArc(radius, startAngle, endAngle, spikes = false) { 202 | const X = window.innerWidth / 2 203 | const Y = window.innerHeight / 2 204 | const startX = X + Math.cos(startAngle) * (radius - MARGIN) 205 | const startY = Y + Math.sin(startAngle) * (radius - MARGIN) 206 | graphics.moveTo(startX, startY) 207 | graphics.arc(X, Y, radius - MARGIN - (spikes ? 4 : 0), startAngle, endAngle) 208 | } 209 | -------------------------------------------------------------------------------- /src/index.styl: -------------------------------------------------------------------------------- 1 | /* Minimal CSS Reset */ 2 | 3 | * 4 | box-sizing: border-box 5 | 6 | html 7 | font-size: 12px 8 | 9 | body, h1, h2, h3, h4, h5, h6, p, ol, ul 10 | margin: 0 11 | padding: 0 12 | font-weight: normal 13 | 14 | ol, ul 15 | list-style: none 16 | 17 | img 18 | max-width: 100% 19 | height: auto 20 | 21 | a 22 | text-decoration: none 23 | 24 | 25 | html 26 | color: white 27 | font-family: 'Roboto', sans-serif 28 | cursor: default 29 | 30 | 31 | #menu 32 | font-size: 1.2em 33 | position: fixed 34 | top: 8px 35 | left: 8px 36 | h1 37 | margin-bottom: 4px 38 | #record 39 | cursor: pointer 40 | &:hover 41 | color: rgba(244, 67, 54, 0.5) 42 | &.active 43 | color: #F44336 44 | .song 45 | margin-left: 16px 46 | cursor: pointer 47 | &:hover 48 | color: rgba(0, 150, 136, 0.5) 49 | &.active 50 | color: #009688 51 | #trippy 52 | margin-top: 16px 53 | cursor: pointer 54 | &.active 55 | color: transparent 56 | background-clip: text 57 | background-image: linear-gradient(to right, red, orange, yellow, green, blue, indigo, violet) 58 | 59 | 60 | #hide 61 | position: fixed 62 | bottom: 8px 63 | left: 8px 64 | 65 | 66 | #canvas 67 | display: block 68 | position: fixed 69 | 70 | 71 | /* Github Corner */ 72 | .github-corner 73 | position: absolute 74 | top: 0 75 | right: 0 76 | cursor: default 77 | 78 | .octo-arm 79 | .octo-body 80 | pointer-events: none 81 | 82 | .triangle:hover 83 | cursor: pointer 84 | &+ .octo-arm 85 | animation:octocat-wave 560ms ease-in-out 86 | 87 | @media (max-width:500px) 88 | .triangle:hover + .octo-arm 89 | animation:none 90 | .octo-arm 91 | animation:octocat-wave 560ms ease-in-out 92 | 93 | @keyframes octocat-wave 94 | 0%,100% 95 | transform:rotate(0) 96 | 97 | 20%,60% 98 | transform:rotate(-25deg) 99 | 100 | 40%,80% 101 | transform:rotate(10deg) 102 | 103 | 104 | 105 | 106 | 107 | -------------------------------------------------------------------------------- /src/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/preview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/teoxoy/audio-visualizer/e785922dbb71ab3c85f80840f8d0fc522b2118d1/src/preview.png --------------------------------------------------------------------------------