├── .gitignore ├── Makefile ├── README.md ├── build ├── application.css └── application.js ├── css ├── font-awesome.css ├── nanoscroller.css └── style.css ├── debug.html ├── fonts ├── fontawesome-webfont.eot ├── fontawesome-webfont.svg ├── fontawesome-webfont.svgz ├── fontawesome-webfont.ttf └── fontawesome-webfont.woff ├── index.html ├── lib ├── Detector.js ├── MIDI.js │ ├── Color.js │ ├── DOMLoader.XMLHttp.js │ ├── DOMLoader.script.js │ ├── MIDI.Player.js │ ├── MIDI.Plugin.js │ ├── MIDI.audioDetect.js │ ├── MIDI.loadPlugin.js │ ├── MusicTheory.Synesthesia.js │ ├── MusicTheory.js │ ├── VersionControl.Base64.js │ └── lib │ │ ├── base64binary.js │ │ └── jasmid │ │ ├── LICENSE │ │ ├── midifile.js │ │ ├── replayer.js │ │ └── stream.js ├── OrbitControls.js ├── Three.js ├── async.min.js ├── jquery-1.7.1.min.js ├── jquery.easing.js ├── jquery.nanoscroller.min.js ├── spin.min.js └── state-machine.min.js ├── notsupported.html ├── soundfont ├── soundfont-mp3.js └── soundfont-ogg.js ├── src ├── coffee │ ├── Euphony.coffee │ ├── LoaderWidget.coffee │ ├── Main.coffee │ ├── NoteParticles.coffee │ ├── NoteRain.coffee │ ├── PianoKeyboard.coffee │ ├── PlayerWidget.coffee │ └── Scene.coffee └── compiled │ ├── Euphony.js │ ├── LoaderWidget.js │ ├── Main.js │ ├── NoteParticles.js │ ├── NoteRain.js │ ├── PianoKeyboard.js │ ├── PlayerWidget.js │ └── Scene.js └── tracks ├── 001-Albeniz I - Tango ├── 002-Bach, JS - Aria (Goldberg Variations) ├── 003-Bach, JS - Fugue (WTC Bk-1 No-21) ├── 004-Bach, JS - Fugue (WTC Bk-1 No-3) ├── 005-Bach, JS - Fugue (WTC Bk-1 No-5) ├── 006-Bach, JS - Fugue (WTC Bk-1 No-7) ├── 007-Bach, JS - Gavotte (French Suite No-5) ├── 008-Bach, JS - Italian Concerto Mvt-1 ├── 009-Bach, JS - Italian Concerto Mvt-2 ├── 010-Bach, JS - Italian Concerto Mvt-3 ├── 011-Bach, JS - Jesu Joy of Mans Desiring ├── 012-Bach, JS - March in D ├── 013-Bach, JS - Minuet in G (2) ├── 014-Bach, JS - Minuet in G ├── 015-Bach, JS - Musette in D ├── 016-Bach, JS - Prelude (WTC Bk-1 No-21) ├── 017-Bach, JS - Prelude (WTC Bk-1 No-3) ├── 018-Bach, JS - Prelude (WTC Bk-1 No-5 ├── 019-Bach, JS - Prelude (WTC Bk-1 No-7) ├── 020-Bach, JS - Prelude in C (WTC) Bk.1) ├── 021-Bach, JS - Toccata and Fugue in D ├── 022-Balakirev - Islamey ├── 023-Beethoven - Bagatelle Op-33 No-1 ├── 024-Beethoven - Bagatelle Op-33 No-4 ├── 025-Beethoven - Fuer Elise ├── 026-Beethoven - Moonlight Sonata Op-27 No-2 Mvt-1 ├── 027-Beethoven - Moonlight Sonata Op-27 No-2 Mvt-2 ├── 028-Beethoven - Moonlight Sonata Op-27 No-2 Mvt-3 ├── 029-Beethoven - Pathetique Sonata Op-13 Mvt-1 ├── 030-Beethoven - Pathetique Sonata Op-13 Mvt-2 ├── 031-Beethoven - Pathetique Sonata Op-13 Mvt-3 ├── 032-Beethoven - Symphony No-5 Mvt-1 ├── 033-Boccherini - Minuet ├── 034-Brahms - Ballade in D Op-10 No-1 ├── 035-Brahms - Ballade in G Op-118 No-3 ├── 036-Brahms - Capriccio in BOp-76 No-2 ├── 037-Brahms - Intermezzo in A Op-118 No-2 ├── 038-Brahms - Intermezzo in B-flat Op-117 No-2 ├── 039-Brahms - Intermezzo in C-sharp Op-117 No-3 ├── 040-Brahms - Intermezzo in E-flat Op-117 No-1 ├── 041-Brahms - Intermezzo in E-flat Op-118 No-6 ├── 042-Brahms - Rhapsody in G Op-79 No-2 ├── 043-Brahms - Waltz in A-flat Op-39 No-15 ├── 044-Chaminade - Automne (Etude de Concert) Op-35 No-2 ├── 045-Chopin - Ballade No-1 in G Op-23 ├── 046-Chopin - Barcarolle Op-60 ├── 047-Chopin - Etude in A op.25 No-11 ├── 048-Chopin - Etude in A-flat Op-25 No-1 ├── 049-Chopin - Etude in C Op-10 No-12 (Revolutionary) ├── 050-Chopin - Etude in C-sharp Op-25 No-7 (Cello) ├── 051-Chopin - Etude in E Op-10 No-3 ├── 052-Chopin - Etude in G-flat Op-10 No-5 (Black Key) ├── 053-Chopin - Etude in G-sharp Op-25 No-6 ├── 054-Chopin - Fantaisie-Impromptu in C-sharp Op-66 ├── 055-Chopin - Mazurka in B Op-33 No-4 ├── 056-Chopin - Mazurka in B-flat Op-7 No-1 ├── 057-Chopin - Mazurka in C-sharp Op-63 No-3 ├── 058-Chopin - Mazurka in F-sharp Op-6 No-1 ├── 059-Chopin - Nocturne in B Op-32 No-1 ├── 060-Chopin - Nocturne in D-flat Op-27 No-2 ├── 061-Chopin - Nocturne in E Op-62 No-2 ├── 062-Chopin - Nocturne in E-flat Op-9 No-2 ├── 063-Chopin - Nocturne in F-sharp Op-15 No-2 ├── 064-Chopin - Nocturne in G Op-37 No-1 ├── 065-Chopin - Polonaise in A Op-40 No-1 (Military) ├── 066-Chopin - Polonaise in A-flat Op-53 ├── 067-Chopin - Prelude in A Op-28 No-7 ├── 068-Chopin - Prelude in B Op-28 No-5 ├── 069-Chopin - Prelude in D-flat Op-28 No-15 (Raindrop) ├── 070-Chopin - Prelude in E Op-28 No-4 ├── 071-Chopin - Prelude in F-sharp Op-28 No-8 ├── 072-Chopin - Scherzo in C-sharp ├── 073-Chopin - Waltz in C-sharp Op-64 No-2 ├── 074-Chopin - Waltz in D-flat Op-64 No-1 (Minute) ├── 075-Chopin - Waltz in E Op-Posth. ├── 076-Chopin - Waltz in E-flat Op-18 ├── 077-Debussy - Arabesque No-1 in E ├── 078-Debussy - Arabesque No-2 in G ├── 079-Debussy - Clair de lune ├── 080-Debussy - Danse ├── 081-Debussy - Doctor Gradys ad Parnassum (Childrens Corner ├── 082-Debussy - Golliwogs Cake Walk (Childrens Corner) ├── 083-Debussy - Jimbos Lullaby (Childrens Corner) ├── 084-Debussy - Reflections in the Water ├── 085-Debussy - Reverie ├── 086-Debussy - Serenade for the Doll (Childrens Corner) ├── 087-Debussy - The Engulfed Cathedral ├── 088-Debussy - The Girl With The Flaxen Hair ├── 089-Debussy - The Little Shepherd (Childrens Corner) ├── 090-Debussy - The Snow is Dancing (Childrens Corner) ├── 091-Debussy - Valse - La plus que lente ├── 092-Elgar - Pomp and Circumstance No-1 ├── 093-Faure - Claire de lune Op-46 No-2 ├── 094-Faure - Impromptu in F minor Op-31 No-2 ├── 095-Grainger - Country Gardens ├── 096-Grainger - Irish tune from County Derry ├── 097-Grainger - Shepherds Hey ├── 098-Granados - Oriental ├── 099-Grieg - Air (Holberg) ├── 100-Grieg - Anitras Dance (Peer Gynt) ├── 101-Grieg - Arietta Op-12 No-1 ├── 102-Grieg - Ases Death (Peer Gynt) ├── 103-Grieg - Elfin Dance Op-12 ├── 104-Grieg - Gavotte (Holberg) ├── 105-Grieg - I Love Thee ├── 106-Grieg - In the Hall of the Mountain King (Peer Gynt) ├── 107-Grieg - March of the Dwarfs Op-54 No-3 ├── 108-Grieg - Morning Mood (Peer Gynt) ├── 109-Grieg - Nocturne Op-54 No-4 ├── 110-Grieg - Preludium (Holberg) ├── 111-Grieg - Rigaudon (Holberg) ├── 112-Grieg - Sarabande (Holberg) ├── 113-Grieg - Solvejgs Song Op-52 No-4 ├── 114-Grieg - The Bird Op-43 No-4 ├── 115-Grieg - The Butterfly Op-43 No-1 ├── 116-Grieg - To the Spring Op-43 No-6 ├── 117-Grieg - Wedding Day at Troldhaugen Op-65 No-6 ├── 118-Haydn - Sonata in E-flat Mvt-1 (Hob.XVI-52) ├── 119-Haydn - Sonata in E-flat Mvt-2 (Hob.XVI-52) ├── 120-Haydn - Sonata in E-flat Mvt-3 (Hob.XVI-52) ├── 121-Joplin S-- The Entertainer ├── 122-Ketelbey - in A Monastery Garden ├── 123-Liszt - Ave Maria ├── 124-Liszt - Concert Etude No-3 in D-flat (Un Sospiro) ├── 125-Liszt - Hungarian Rhapsody No-2 ├── 126-Liszt - Liebestraume No-1 ├── 127-Liszt - Liebestraume No-3 ├── 128-Liszt - Mephisto Waltz ├── 129-Liszt - On the Edge Of a Spring ├── 130-Liszt - Paganini Etude No-3 (La Campanella) ├── 131-Liszt - Valse Oubliee ├── 132-Liszt - Valse-Impromptu ├── 133-MacDowell E - To a Wild Rose Op-51 ├── 134-Mendelssohn - Andante and Rondo Capriciosso Op-14 ├── 135-Mendelssohn - Song of Spring Op-62 No-6 ├── 136-Mendelssohn - Song without Words Op-19 No-1 ├── 137-Mendelssohn - Song without Words Op-38 No-2 ├── 138-Mendelssohn - Song without Words Op-85 No-1 ├── 139-Mendelssohn - Spinners Song Op-67 No-4 ├── 140-Mendelssohn - Wedding March ├── 141-Mozart - Fantasy in C K-475 ├── 142-Mozart - Fantasy in D K-397 ├── 143-Mozart - Sonata in A 1st Mvt. K-331 ├── 144-Mozart - Sonata in A 2nd Mvt. K-331 ├── 145-Mozart - Sonata in A 3rd Mvt-(Alla Turca) K-331 ├── 146-Mozart - Sonata in C Allegro K.545 ├── 147-Mozart - Sonata in C Andante K.545 ├── 148-Mozart - Sonata in C Rondo K.545 ├── 149-Mozart - Variations on Ah vous dirais-je maman ├── 150-Mussorgsky - Ballet of the Unhatched Chickens (Pictures) ├── 151-Mussorgsky - Bydlo (Pictures) ├── 152-Mussorgsky - Promenade (Pictures) ├── 153-Mussorgsky - The Old Castle (Pictures) ├── 154-Mussorgsky - Tuileries (Pictures) ├── 155-Poulenc - Mouvement perpetuels ├── 156-Prokofiev - Prelude Op-12 No-7 ├── 157-Rachmaninov - Flight of the Bumblebee ├── 158-Rachmaninov - Prelude in C-sharp Op-3 No-2 ├── 159-Rachmaninov - Prelude in G Op-23 No-5 ├── 160-Ravel - Jeux deau (Fountains) ├── 161-Ravel - Menuet on the Name of Haydn (Sonatina) ├── 162-Ravel - Pavane For A Dead Princess ├── 163-Satie Eric - Gymnopedie No-1 ├── 164-Satie Eric - Gymnopedie No-2 ├── 165-Satie Eric - Gymnopedie No-3 ├── 166-Scarlatti - Sonata in C L.104 K.159 ├── 167-Scarlatti - Sonata in D ├── 168-Scarlatti - Sonata in F ├── 169-Schubert - Impromptu in A-flat minor Op-90 No-4 ├── 170-Schubert - Impromptu in E-flat Op-90 No-2 ├── 171-Schubert - Impromptu in G-flat Op-90 No-3 ├── 172-Schumann - About Foreign Lands and People Op-15 No-1 ├── 173-Schumann - Almost Too Serious Op-15 No-10 ├── 174-Schumann - Arabeske Op-18 ├── 175-Schumann - By the Fireside Op-15 No-8 ├── 176-Schumann - Catch Me! Op-15 No-3 ├── 177-Schumann - Child Falling Asleep Op-15 No-12 ├── 178-Schumann - Curious Story Op-15 No-2 ├── 179-Schumann - Frightening Op-15 No-11 ├── 180-Schumann - Important Event Op-15 No-6 ├── 181-Schumann - In the Evening Op-12 No-1 ├── 182-Schumann - In the Night Op-12 No-5 ├── 183-Schumann - King of the Rocking-Horse Op-15 No-9 ├── 184-Schumann - Perfect Happiness Op-15 No-5 ├── 185-Schumann - Pleading Child Op-15 No-4 ├── 186-Schumann - Restless Dreams Op-12 No-7 ├── 187-Schumann - Reverie Op-15 No-7 ├── 188-Schumann - Romanze in F-sharp Op-28 No-2 ├── 189-Schumann - Soaring Op-12 No-2 ├── 190-Schumann - The Happy Farmer ├── 191-Schumann - The Poet Speaks Op-15 No-13 ├── 192-Schumann - The Songs End Op-12 No-8 ├── 193-Schumann - Whims Op-12 No-4 ├── 194-Schumann - Why Op-12 No-3 ├── 195-Scriabin - Etude in C-sharpop.2no 11 ├── 196-Sibelius - Romance in D-flat ├── 197-Sibelius - Valse Triste ├── 198-Sinding - Rustles of Spring Op-32 No-3 ├── 199-Tchaikovsky - Arabian Dance (Nutcracker) ├── 200-Tchaikovsky - Chinese Dance (Nutcracker) ├── 201-Tchaikovsky - Dance of the Reed Flutes (Nutcracker) ├── 202-Tchaikovsky - Dance of the Sugar-Plum Fairy (Nutcracker) ├── 203-Tchaikovsky - June (Barcarolle) Op-37 No-6 ├── 204-Tchaikovsky - March (Nutcracker) ├── 205-Tchaikovsky - Mazurka Op-39 No-10 ├── 206-Tchaikovsky - Neapolitan Song Op-39 No-18 ├── 207-Tchaikovsky - Old French Song Op-39 No-16 ├── 208-Tchaikovsky - Overture (Nutcracker) ├── 209-Tchaikovsky - Russian Dance (Nutcracker) ├── 210-Tchaikovsky - Song of the Lark Op-39 No-22 ├── 211-Tchaikovsky - Sweet Dream Op-39 No-21 ├── 212-Tchaikovsky - Waltz of the Flowers (Nutcracker) ├── 213-Tchaikovsky - Waltz Op-39 No-8 ├── 214-Villa-Lobos - Punch (Le Polichinelle) ├── 215-Von Weber - Rondo Brilliant in E-flat Op-62 └── index.json /.gitignore: -------------------------------------------------------------------------------- 1 | *.swp 2 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | all: $(shell find src/coffee -name "*.coffee" -type f) 2 | coffee -o src/compiled src/coffee 3 | 4 | build: 5 | @cat \ 6 | css/font-awesome.css \ 7 | css/nanoscroller.css \ 8 | css/style.css \ 9 | > build/application.css 10 | @cat \ 11 | lib/MIDI.js/VersionControl.Base64.js \ 12 | lib/MIDI.js/lib/base64binary.js \ 13 | lib/MIDI.js/lib/jasmid/stream.js \ 14 | lib/MIDI.js/lib/jasmid/midifile.js \ 15 | lib/MIDI.js/lib/jasmid/replayer.js \ 16 | lib/MIDI.js/DOMLoader.XMLHttp.js \ 17 | lib/MIDI.js/DOMLoader.script.js \ 18 | lib/MIDI.js/MIDI.audioDetect.js \ 19 | lib/MIDI.js/MIDI.loadPlugin.js \ 20 | lib/MIDI.js/MIDI.Plugin.js \ 21 | lib/MIDI.js/MIDI.Player.js \ 22 | lib/MIDI.js/Color.js \ 23 | lib/MIDI.js/MusicTheory.js \ 24 | lib/MIDI.js/MusicTheory.Synesthesia.js \ 25 | lib/jquery-1.7.1.min.js \ 26 | lib/jquery.easing.js \ 27 | lib/jquery.nanoscroller.min.js \ 28 | lib/Three.js \ 29 | lib/OrbitControls.js \ 30 | lib/state-machine.min.js \ 31 | lib/spin.min.js \ 32 | lib/async.min.js \ 33 | src/compiled/PianoKeyboard.js \ 34 | src/compiled/NoteRain.js \ 35 | src/compiled/NoteParticles.js \ 36 | src/compiled/Scene.js \ 37 | src/compiled/LoaderWidget.js \ 38 | src/compiled/PlayerWidget.js \ 39 | src/compiled/Euphony.js \ 40 | src/compiled/Main.js \ 41 | > build/application.js 42 | @uglifyjs -o build/application.js build/application.js 43 | 44 | 45 | watch: 46 | coffee -wo src/compiled src/coffee 47 | 48 | server: 49 | python -m SimpleHTTPServer 50 | 51 | .PHONY: build watch server 52 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Euphony 2 | ======= 3 | 4 | Euphony is a web-based MIDI player and visualizer. 5 | 6 | Please visit http://qiao.github.com/euphony to start playing. (Chrome only) 7 | 8 | [![](http://i.imgur.com/7QOiW.png)](http://qiao.github.com/euphony) 9 | 10 | Thanks to the authors and contributors of the following projects, without whom this project would not have been possible: 11 | 12 | Libraries: 13 | 14 | * [three.js](https://github.com/mrdoob/three.js) - JavaScript 3D library 15 | * [MIDI.js](http://mudcu.be/midi-js/) - Sequencing in JavaScript 16 | * [jasmid](https://github.com/gasman/jasmid) - A MIDI file reader and synthesiser in JavaScript 17 | * [base642binary.js](http://blog.danguer.com/2011/10/24/base64-binary-decoding-in-javascript/) - Base64 binary decoding in JavaScript 18 | * [async.js](https://github.com/caolan/async) - Async utilities 19 | * [spin.js](https://github.com/fgnass/spin.js) - A spinning activity indicator 20 | * [javascript-state-machine](https://github.com/jakesgordon/javascript-state-machine) - A finite state machine javascript micro framework 21 | * [jQuery](http://jquery.com) - Duh 22 | * [jQuery Easing Plugin](http://gsgd.co.uk/sandbox/jquery/easing/) - A jQuery plugin from GSGD to give advanced easing options 23 | * [nanoScrollerJS](https://github.com/jamesflorentino/nanoScrollerJS) - A jQuery plugin that offers Mac OS X Lion-styled scrollbars 24 | 25 | Iconfont: 26 | 27 | * [Font Awesome](http://fortawesome.github.com/Font-Awesome/) - The iconic font designed for use with Twitter Bootstrap 28 | 29 | Soundfont: 30 | 31 | * [PersonalCopy](http://www.personalcopy.com/) - High quality soundfonts 32 | 33 | Also: 34 | 35 | * [MIDITrail](http://en.sourceforge.jp/projects/miditrail/) - A MIDI player which provides 3D visualization of MIDI datasets. (This is the project that Euphony mimics. And its source code is the most beautiful one that I have ever read). 36 | 37 | License 38 | ------- 39 | 40 | [MIT License](http://www.opensource.org/licenses/mit-license.php) 41 | 42 | © 2012 Xueqiao Xu <xueqiaoxu@gmail.com> 43 | 44 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 45 | 46 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 47 | 48 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 49 | -------------------------------------------------------------------------------- /css/nanoscroller.css: -------------------------------------------------------------------------------- 1 | /** initial setup **/ 2 | .nano { 3 | position : relative; 4 | overflow : hidden; 5 | width : 100%; 6 | height : 100%; 7 | } 8 | .nano .content { 9 | position : absolute; 10 | overflow : scroll; 11 | overflow-x : hidden; 12 | top : 0; 13 | right : 0; 14 | bottom : 0; 15 | left : 0; 16 | } 17 | .nano .content::-webkit-scrollbar { 18 | -webkit-appearance: none; 19 | } 20 | .nano > .pane { 21 | background : rgba(0,0,0,.25); 22 | position : absolute; 23 | width : 9px; 24 | right : 0; 25 | top : 0; 26 | bottom : 0; 27 | visibility : hidden\9; /* Target only IE7 and IE8 with this hack */ 28 | opacity : .01; 29 | -webkit-transition : .2s; 30 | -moz-transition : .2s; 31 | -ms-transition : .2s; 32 | -o-transition : .2s; 33 | transition : .2s; 34 | } 35 | .nano > .pane > .slider { 36 | background: rgba(200,200,200,0.15); 37 | position : relative; 38 | margin : 0 1px; 39 | } 40 | .nano:hover > .pane, .pane.active { 41 | visibility : visible\9; /* Target only IE7 and IE8 with this hack */ 42 | opacity : 1; 43 | } 44 | -------------------------------------------------------------------------------- /css/style.css: -------------------------------------------------------------------------------- 1 | body, html { 2 | padding: 0px; 3 | margin: 0px; 4 | height: 100%; 5 | width: 100%; 6 | background: #000000; 7 | color: #ccc; 8 | overflow: hidden; 9 | } 10 | 11 | ul, ol { 12 | list-style: none; 13 | margin: 0px; 14 | padding: 0px; 15 | } 16 | 17 | a { 18 | color: #bbb; 19 | } 20 | a:hover { 21 | color: #ddd; 22 | } 23 | 24 | #canvas { 25 | position: absolute; 26 | left: 0px; 27 | top: 0; 28 | right: 0; 29 | bottom: 0; 30 | } 31 | 32 | #player { 33 | position: absolute; 34 | top: 0px; 35 | bottom: 0px; 36 | width: 300px; 37 | left: -300px; 38 | margin: 0px; 39 | padding: 0; 40 | color: #ddd; 41 | background: rgba(100, 100, 100, 0.3); 42 | } 43 | 44 | .player-controls { 45 | line-height: 30px; 46 | text-align: center; 47 | padding-top: 3px; 48 | } 49 | 50 | .player-controls>li { 51 | display: inline-block; 52 | width: 22%; 53 | cursor: pointer; 54 | -webkit-transition: text-shadow 0.5s, color 0.2s; 55 | -moz-transition: text-shadow 0.5s, color 0.2s; 56 | -o-transition: text-shadow 0.5s, color 0.2s; 57 | -ms-transition: text-shadow 0.5s, color 0.2s; 58 | transition: text-shadow 0.5s, color 0.2s; 59 | } 60 | 61 | .player-controls>li:hover { 62 | color: #f3f3f3; 63 | text-shadow: 0px 0px 20px rgba(255, 255, 255, 0.8); 64 | } 65 | 66 | .player-progress-container { 67 | margin-top: 3px; 68 | height: 20px; 69 | margin-left: 10px; 70 | margin-right: 10px; 71 | width: 280px; 72 | } 73 | 74 | .player-progress-bar { 75 | position: absolute; 76 | height: 8px; 77 | background: rgba(200, 200, 200, 0.15); 78 | } 79 | 80 | .player-progress-text { 81 | color: #ddd; 82 | position: absolute; 83 | right: 15px; 84 | font-size: 9px; 85 | cursor: default; 86 | margin-top: -1px; 87 | } 88 | 89 | 90 | .player-playlist-container { 91 | line-height: 21px; 92 | text-indent: 10px; 93 | font-size: 11px; 94 | display: block; 95 | } 96 | 97 | .player-playlist>li { 98 | cursor: pointer; 99 | border-top: 1px solid rgba(0, 0, 0, 0.2); 100 | white-space: nowrap; 101 | overflow: hidden; 102 | text-overflow: ellipsis; 103 | -webkit-transition: text-shadow 0.5s, background 0.2s; 104 | -moz-transition: text-shadow 0.5s, background 0.2s; 105 | -o-transition: text-shadow 0.5s, background 0.2s; 106 | -ms-transition: text-shadow 0.5s, background 0.2s; 107 | transition: text-shadow 0.5s, background 0.2s; 108 | } 109 | 110 | .player-playlist>li:hover { 111 | color: #fff; 112 | text-shadow: 0px 0px 10px rgba(255, 255, 255, 0.7); 113 | background-color: rgba(0, 0, 0, 0.55); 114 | } 115 | 116 | .player-current-track { 117 | background-color: rgba(200, 200, 200, 0.2) !important; 118 | } 119 | 120 | .hover { 121 | background-color: rgba(200, 200, 200, 0.2) !important; 122 | } 123 | 124 | #about { 125 | position: absolute; 126 | right: 20px; 127 | bottom: 10px; 128 | font-size: 11px; 129 | line-height: 17px; 130 | color: #aaa; 131 | cursor: default; 132 | text-align: right; 133 | } 134 | -------------------------------------------------------------------------------- /debug.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Euphony 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 | 64 | 65 |
66 |
67 | 68 |
69 | 70 | 75 |
76 | 77 | 78 | 82 | 83 | 84 | 85 | -------------------------------------------------------------------------------- /fonts/fontawesome-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qiao/euphony/4cf35cb09c9af5b7a9a6c81a79a205ecd02acbf8/fonts/fontawesome-webfont.eot -------------------------------------------------------------------------------- /fonts/fontawesome-webfont.svgz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qiao/euphony/4cf35cb09c9af5b7a9a6c81a79a205ecd02acbf8/fonts/fontawesome-webfont.svgz -------------------------------------------------------------------------------- /fonts/fontawesome-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qiao/euphony/4cf35cb09c9af5b7a9a6c81a79a205ecd02acbf8/fonts/fontawesome-webfont.ttf -------------------------------------------------------------------------------- /fonts/fontawesome-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qiao/euphony/4cf35cb09c9af5b7a9a6c81a79a205ecd02acbf8/fonts/fontawesome-webfont.woff -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Euphony 6 | 7 | 8 | 9 | 14 | 15 | 16 | 17 | 18 |
19 | 20 |
21 | 28 | 29 |
30 |
31 | 32 |
33 | 34 | 39 |
40 | 41 | 42 | 46 | 47 | 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /lib/Detector.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author alteredq / http://alteredqualia.com/ 3 | * @author mr.doob / http://mrdoob.com/ 4 | */ 5 | 6 | Detector = { 7 | 8 | chrome: window.navigator.userAgent.toLowerCase().indexOf('chrome') > -1, 9 | canvas: !! window.CanvasRenderingContext2D, 10 | webgl: ( function () { try { return !! window.WebGLRenderingContext && !! document.createElement( 'canvas' ).getContext( 'experimental-webgl' ); } catch( e ) { return false; } } )(), 11 | workers: !! window.Worker, 12 | fileapi: window.File && window.FileReader && window.FileList && window.Blob, 13 | 14 | getNotChromeMessage: function () { 15 | 16 | var element = document.createElement( 'div' ); 17 | element.id = 'webgl-error-message'; 18 | 19 | element.innerHTML = 'Sorry, this demo only supports Google Chrome'; 20 | 21 | return element; 22 | 23 | }, 24 | 25 | getWebGLErrorMessage: function () { 26 | 27 | var element = document.createElement( 'div' ); 28 | element.id = 'webgl-error-message'; 29 | 30 | if ( ! this.webgl ) { 31 | 32 | element.innerHTML = window.WebGLRenderingContext ? [ 33 | 'Your graphics card does not seem to support WebGL.
', 34 | 'Find out how to get it here.' 35 | ].join( '\n' ) : [ 36 | 'Your browser does not seem to support WebGL.
', 37 | 'Find out how to get it here.' 38 | ].join( '\n' ); 39 | 40 | } 41 | 42 | return element; 43 | 44 | }, 45 | 46 | addGetWebGLMessage: function ( parameters ) { 47 | 48 | var parent, id, element; 49 | 50 | parameters = parameters || {}; 51 | 52 | parent = parameters.parent !== undefined ? parameters.parent : document.body; 53 | id = parameters.id !== undefined ? parameters.id : 'oldie'; 54 | 55 | element = Detector.getWebGLErrorMessage(); 56 | element.id = id; 57 | 58 | parent.appendChild( element ); 59 | 60 | } 61 | 62 | }; 63 | -------------------------------------------------------------------------------- /lib/MIDI.js/Color.js: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Color.Space : 0.3 : mudcu.be 4 | ----------------------------- 5 | STRING <-> HEX <-> RGB <-> HSL 6 | ----------------------------- 7 | var HEX = 0xFF0000; 8 | var HSL = Color.Space(HEX, "HEX>RGB>HSL"); 9 | 10 | */ 11 | 12 | if (!window.Color) Color = {}; 13 | if (!window.Color.Space) Color.Space = {}; 14 | 15 | (function () { 16 | 17 | var DEG_RAD = Math.PI / 180; 18 | var RAD_DEG = 1 / DEG_RAD; 19 | 20 | var shortcuts = { }; 21 | var root = Color.Space = function(color, route) { 22 | if (shortcuts[route]) { 23 | route = shortcuts[route]; 24 | } 25 | var arr = route.split(">"); 26 | var key = ""; 27 | for (var n = 0; n < arr.length; n ++) { 28 | if (n > 1) { 29 | key = key.split("_"); 30 | key.shift(); 31 | key = key.join("_"); 32 | } 33 | key += (n == 0 ? "" : "_") + arr[n]; 34 | if (n > 0) color = root[key](color); 35 | } 36 | return color; 37 | }; 38 | 39 | // STRING = 'FFFFFF' | 'FFFFFFFF' 40 | 41 | root.STRING_HEX = function (o) { 42 | return parseInt('0x' + o); 43 | }; 44 | 45 | // HEX = 0x000000 -> 0xFFFFFF 46 | 47 | root.HEX_STRING = function (o, maxLength) { 48 | if (!maxLength) maxLength = 6; 49 | if (!o) o = 0; 50 | var z = o.toString(16); 51 | // when string is lesser than maxLength 52 | var n = z.length; 53 | while (n < maxLength) { 54 | z = '0' + z; 55 | n++; 56 | } 57 | // when string is greater than maxLength 58 | var n = z.length; 59 | while (n > maxLength) { 60 | z = z.substr(1); 61 | n--; 62 | } 63 | return z; 64 | }; 65 | 66 | root.HEX_RGB = function (o) { 67 | return { 68 | R: (o >> 16), 69 | G: (o >> 8) & 0xFF, 70 | B: o & 0xFF 71 | }; 72 | }; 73 | 74 | // RGB = R: Red / G: Green / B: Blue 75 | 76 | root.RGB_HEX = function (o) { 77 | if (o.R < 0) o.R = 0; 78 | if (o.G < 0) o.G = 0; 79 | if (o.B < 0) o.B = 0; 80 | if (o.R > 255) o.R = 255; 81 | if (o.G > 255) o.G = 255; 82 | if (o.B > 255) o.B = 255; 83 | return o.R << 16 | o.G << 8 | o.B; 84 | }; 85 | 86 | root.RGB_HSL = function (o) { // RGB from 0 to 1 87 | // http://www.easyrgb.com/index.php?X=MATH&H=18#text18 88 | var _R = o.R / 255, 89 | _G = o.G / 255, 90 | _B = o.B / 255, 91 | min = Math.min(_R, _G, _B), 92 | max = Math.max(_R, _G, _B), 93 | D = max - min, 94 | H, 95 | S, 96 | L = (max + min) / 2; 97 | if (D == 0) { // No chroma 98 | H = 0; 99 | S = 0; 100 | } else { // Chromatic data 101 | if (L < 0.5) S = D / (max + min); 102 | else S = D / (2 - max - min); 103 | var DR = (((max - _R) / 6) + (D / 2)) / D; 104 | var DG = (((max - _G) / 6) + (D / 2)) / D; 105 | var DB = (((max - _B) / 6) + (D / 2)) / D; 106 | if (_R == max) H = DB - DG; 107 | else if (_G == max) H = (1 / 3) + DR - DB; 108 | else if (_B == max) H = (2 / 3) + DG - DR; 109 | if (H < 0) H += 1; 110 | if (H > 1) H -= 1; 111 | } 112 | return { 113 | H: H * 360, 114 | S: S * 100, 115 | L: L * 100 116 | }; 117 | }; 118 | 119 | // HSL (1978) = H: Hue / S: Saturation / L: Lightess 120 | 121 | root.HSL_RGB = function (o) { 122 | // http://www.easyrgb.com/index.php?X=MATH&H=19 123 | var H = o.H / 360, 124 | S = o.S / 100, 125 | L = o.L / 100, 126 | R, G, B, _1, _2; 127 | function Hue_2_RGB(v1, v2, vH) { 128 | if (vH < 0) vH += 1; 129 | if (vH > 1) vH -= 1; 130 | if ((6 * vH) < 1) return v1 + (v2 - v1) * 6 * vH; 131 | if ((2 * vH) < 1) return v2; 132 | if ((3 * vH) < 2) return v1 + (v2 - v1) * ((2 / 3) - vH) * 6; 133 | return v1; 134 | } 135 | if (S == 0) { // HSL from 0 to 1 136 | R = L * 255; 137 | G = L * 255; 138 | B = L * 255; 139 | } else { 140 | if (L < 0.5) _2 = L * (1 + S); 141 | else _2 = (L + S) - (S * L); 142 | _1 = 2 * L - _2; 143 | R = 255 * Hue_2_RGB(_1, _2, H + (1 / 3)); 144 | G = 255 * Hue_2_RGB(_1, _2, H); 145 | B = 255 * Hue_2_RGB(_1, _2, H - (1 / 3)); 146 | } 147 | return { 148 | R: R, 149 | G: G, 150 | B: B 151 | }; 152 | }; 153 | 154 | })(); -------------------------------------------------------------------------------- /lib/MIDI.js/DOMLoader.XMLHttp.js: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | DOMLoader.XMLHttp : 0.1 : mudcu.be 4 | ----------------------------------- 5 | DOMLoader.sendRequest({ 6 | url: "./dir/something.extension", 7 | error: function(event) { 8 | console.log(event); 9 | }, 10 | callback: function(response) { 11 | console.log(response.responseText); 12 | }, 13 | progress: function (event) { 14 | var percent = event.loaded / event.total * 100 >> 0; 15 | loader.message("loading: " + percent + "%"); 16 | } 17 | }); 18 | 19 | */ 20 | 21 | if (typeof(DOMLoader) === "undefined") DOMLoader = {}; 22 | 23 | (function() { "use strict"; 24 | 25 | // Add XMLHttpRequest when not available 26 | 27 | if (typeof (window.XMLHttpRequest) === "undefined") { 28 | (function () { // http://www.quirksmode.org/js/xmlhttp.html 29 | var factories = [ 30 | function () { 31 | return new ActiveXObject("Msxml2.XMLHTTP"); 32 | }, function () { 33 | return new ActiveXObject("Msxml3.XMLHTTP"); 34 | }, function () { 35 | return new ActiveXObject("Microsoft.XMLHTTP"); 36 | }]; 37 | for (var i = 0; i < factories.length; i++) { 38 | try { 39 | factories[i](); 40 | } catch (e) { 41 | continue; 42 | } 43 | break; 44 | } 45 | window.XMLHttpRequest = factories[i]; 46 | })(); 47 | } 48 | 49 | if (typeof ((new XMLHttpRequest()).responseText) === "undefined") { 50 | // http://stackoverflow.com/questions/1919972/how-do-i-access-xhr-responsebody-for-binary-data-from-javascript-in-ie 51 | var IEBinaryToArray_ByteStr_Script = 52 | "\r\n"+ 53 | "\r\n"; 67 | 68 | // inject VBScript 69 | document.write(IEBinaryToArray_ByteStr_Script); 70 | 71 | DOMLoader.sendRequest = function(config) { 72 | // helper to convert from responseBody to a "responseText" like thing 73 | function getResponseText(binary) { 74 | var byteMapping = {}; 75 | for (var i = 0; i < 256; i++) { 76 | for (var j = 0; j < 256; j++) { 77 | byteMapping[String.fromCharCode(i + j * 256)] = String.fromCharCode(i) + String.fromCharCode(j); 78 | } 79 | } 80 | // call into VBScript utility fns 81 | var rawBytes = IEBinaryToArray_ByteStr(binary); 82 | var lastChr = IEBinaryToArray_ByteStr_Last(binary); 83 | return rawBytes.replace(/[\s\S]/g, function (match) { 84 | return byteMapping[match]; 85 | }) + lastChr; 86 | } 87 | // 88 | var req = new XMLHttpRequest(); 89 | req.open("GET", config.url, true); 90 | req.setRequestHeader("Accept-Charset", "x-user-defined"); 91 | if (config.responseType) req.responseType = config.responseType; 92 | if (config.error) req.onerror = config.error; 93 | if (config.progress) req.onprogress = config.progress; 94 | req.onreadystatechange = function (event) { 95 | if (req.readyState === 4) { 96 | if (req.status === 200) { 97 | req.responseText = getResponseText(req.responseBody); 98 | } else { 99 | req = false; 100 | } 101 | if (config.callback) config.callback(req); 102 | } 103 | }; 104 | req.send(null); 105 | return req; 106 | } 107 | } else { 108 | DOMLoader.sendRequest = function(config) { 109 | var req = new XMLHttpRequest(); 110 | req.open('GET', config.url, true); 111 | if (req.overrideMimeType) req.overrideMimeType("text/plain; charset=x-user-defined"); 112 | if (config.responseType) req.responseType = config.responseType; 113 | if (config.error) req.onerror = config.error; 114 | if (config.progress) req.onprogress = config.progress; 115 | req.onreadystatechange = function (event) { 116 | if (req.readyState === 4) { 117 | if (req.status !== 200) req = false; 118 | if (config.callback) config.callback(req); 119 | } 120 | }; 121 | req.send(""); 122 | return req; 123 | }; 124 | } 125 | 126 | })(); -------------------------------------------------------------------------------- /lib/MIDI.js/DOMLoader.script.js: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | DOMLoader : 0.2 : mudcu.be 4 | --------------------------- 5 | DOMLoader.script.add({ 6 | strictOrder: true, 7 | srcs: [ 8 | { 9 | src: "../js/jszip/jszip.js", 10 | verify: "JSZip", 11 | callback: function() { 12 | console.log(1) 13 | } 14 | }, 15 | { 16 | src: "../inc/downloadify/js/swfobject.js", 17 | verify: "swfobject", 18 | callback: function() { 19 | console.log(2) 20 | } 21 | } 22 | ], 23 | callback: function() { 24 | console.log(3) 25 | } 26 | }); 27 | 28 | */ 29 | 30 | if (typeof(DOMLoader) === "undefined") DOMLoader = {}; 31 | 32 | DOMLoader.script = function() { 33 | this.loaded = {}; 34 | this.loading = {}; 35 | return this; 36 | }; 37 | 38 | DOMLoader.script.prototype.add = function(config) { 39 | var that = this; 40 | var srcs = config.srcs; 41 | if (typeof(srcs) === "undefined") { 42 | srcs = [{ 43 | src: config.src, 44 | verify: config.verify 45 | }]; 46 | } 47 | /// adding the elements to the head 48 | var doc = document.getElementsByTagName("head")[0]; 49 | /// 50 | var testElement = function(element, test) { 51 | if (that.loaded[element.src]) return; 52 | if (test && !eval(test)) return; 53 | that.loaded[element.src] = true; 54 | // 55 | if (that.loading[element.src]) that.loading[element.src](); 56 | delete that.loading[element.src]; 57 | // 58 | if (element.callback) element.callback(); 59 | if (typeof(getNext) !== "undefined") getNext(); 60 | }; 61 | /// 62 | var batchTest = []; 63 | var addElement = function(element) { 64 | if (/([\w\d.\[\]])$/.test(element.verify)) { // check whether its a variable reference 65 | element.test = "(typeof(" + element.verify + ") !== \"undefined\")"; 66 | batchTest.push(element.test); 67 | } 68 | var script = document.createElement("script"); 69 | script.onreadystatechange = function() { 70 | if (this.readyState !== "loaded" && this.readyState !== "complete") return; 71 | testElement(element); 72 | }; 73 | script.onload = function() { 74 | testElement(element); 75 | }; 76 | script.setAttribute("type", "text/javascript"); 77 | script.setAttribute("src", element.src); 78 | doc.appendChild(script); 79 | that.loading[element.src] = function() {}; 80 | }; 81 | /// checking to see whether everything loaded properly 82 | var onLoad = function(element) { 83 | if (element) { 84 | testElement(element, element.test); 85 | } else { 86 | for (var n = 0; n < srcs.length; n ++) { 87 | testElement(srcs[n], srcs[n].test); 88 | } 89 | } 90 | if (!config.strictOrder && eval(batchTest.join(" && "))) { // finished loading all the requested scripts 91 | if (config.callback) config.callback(); 92 | } else { // keep calling back the function 93 | setTimeout(function() { //- should get slower over time? 94 | onLoad(element); 95 | }, 10); 96 | } 97 | }; 98 | /// loading methods; strict ordering or loose ordering 99 | if (config.strictOrder) { 100 | var ID = -1; 101 | var getNext = function() { 102 | ID ++; 103 | if (!srcs[ID]) { // all elements are loaded 104 | if (config.callback) config.callback(); 105 | } else { // loading new script 106 | var element = srcs[ID]; 107 | var src = element.src; 108 | if (that.loading[src]) { // already loading from another call (attach to event) 109 | that.loading[src] = function() { 110 | if (element.callback) element.callback(); 111 | getNext(); 112 | } 113 | } else if (!that.loaded[src]) { // create script element 114 | addElement(element); 115 | onLoad(element); 116 | } else { // it's already been successfully loaded 117 | getNext(); 118 | } 119 | } 120 | }; 121 | getNext(); 122 | } else { // loose ordering 123 | for (var ID = 0; ID < srcs.length; ID ++) { 124 | if (that.loaded[srcs[ID].src]) return; 125 | addElement(srcs[ID]); 126 | } 127 | onLoad(); 128 | } 129 | }; 130 | 131 | DOMLoader.script = (new DOMLoader.script()); -------------------------------------------------------------------------------- /lib/MIDI.js/MIDI.audioDetect.js: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | MIDI.audioDetect : 0.3 4 | ------------------------------------- 5 | https://github.com/mudx/MIDI.js 6 | ------------------------------------- 7 | Probably, Maybe, No... Absolutely! 8 | ------------------------------------- 9 | Test to see what types of