From f92c9896e4044c818c96656e42cbd5b03ff758f2 Mon Sep 17 00:00:00 2001 From: Egor Date: Sun, 25 Oct 2015 22:55:09 -0700 Subject: [PATCH] visualizations --- README.md | 1 - .../components/add-group-modal/component.js | 1 + .../add-soundcloud-sound-modal/template.hbs | 2 +- .../components/bridge-finder/component.js | 2 +- .../components/bridge-finder/template.hbs | 2 +- app/pods/components/music-tab/component.js | 67 +++-- .../components/music-tab/mixins/helpers.js | 16 +- .../components/music-tab/mixins/visualizer.js | 275 +++++------------- app/pods/components/music-tab/template.hbs | 251 ++++++++-------- app/styles/app.scss | 23 +- bower.json | 3 +- ember-cli-build.js | 1 - .../assets/images/favicons/favicon-90x90.png | Bin 0 -> 8295 bytes 13 files changed, 256 insertions(+), 388 deletions(-) create mode 100644 public/assets/images/favicons/favicon-90x90.png diff --git a/README.md b/README.md index 413c21f..cb1be8a 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,6 @@ Music awesomeness for hue lights. # TODO ## FEATURES - app intro with intro.js -- music visualizations with three.js - microphone mode - about, help page, youtube video diff --git a/app/pods/components/add-group-modal/component.js b/app/pods/components/add-group-modal/component.js index 3e85965..86dc8d0 100644 --- a/app/pods/components/add-group-modal/component.js +++ b/app/pods/components/add-group-modal/component.js @@ -14,6 +14,7 @@ export default Em.Component.extend({ type: 'POST' }); + // crappy code to redraw the lights newGroupsData['9999'] = newGroupData; this.setProperties({ diff --git a/app/pods/components/add-soundcloud-sound-modal/template.hbs b/app/pods/components/add-soundcloud-sound-modal/template.hbs index cafb712..74f38df 100644 --- a/app/pods/components/add-soundcloud-sound-modal/template.hbs +++ b/app/pods/components/add-soundcloud-sound-modal/template.hbs @@ -2,7 +2,7 @@ {{#modal-dialog close="close" alignment="center" translucentOverlay=true attachment="center" targetAttachment="center"}}

Enter a SoundCloud track or playlist/set URL

-

( ex. https://soundcloud.com/mrsuicidesheep/danrell-x-smaland-hostage )

+

( ex. https://soundcloud.com/mrsuicidesheep/tracks )

{{paper-input label="SoundCloud URL" icon="search" value=url}} diff --git a/app/pods/components/bridge-finder/component.js b/app/pods/components/bridge-finder/component.js index 629f55a..d5b10f1 100644 --- a/app/pods/components/bridge-finder/component.js +++ b/app/pods/components/bridge-finder/component.js @@ -32,7 +32,7 @@ export default Em.Component.extend({ findBridgeByIp() { var manualBridgeIp = this.get('manualBridgeIp'), self = this; - if (manualBridgeIp.toLowerCase() === 'trial') { + if (manualBridgeIp.toLowerCase() === 'trial' || manualBridgeIp.toLowerCase() === 'offline') { this.setProperties({ trial: true, bridgeIp: 'trial', diff --git a/app/pods/components/bridge-finder/template.hbs b/app/pods/components/bridge-finder/template.hbs index 39bf998..e1e0ff1 100644 --- a/app/pods/components/bridge-finder/template.hbs +++ b/app/pods/components/bridge-finder/template.hbs @@ -28,7 +28,7 @@ {{#if bridgeFindFail}}

A hue bridge could not be automatically found on your network.
Enter one manually?

- ( or enter trial to look around ) + ( or type offline to look around )

diff --git a/app/pods/components/music-tab/component.js b/app/pods/components/music-tab/component.js index 637a6df..ded2570 100644 --- a/app/pods/components/music-tab/component.js +++ b/app/pods/components/music-tab/component.js @@ -16,11 +16,22 @@ export default Em.Component.extend(helperMixin, visualizerMixin, { }.observes('active'), actions: { + clearPlaylist(){ + this.get('playQueue').clear(); + }, setVisName(name){ this.set('currentVisName', name); }, hideTooltip(){ - Em.$(event.target).parent().parent().find('.tooltip').remove() + Em.$(event.target).parent().parent().find('.tooltip').remove(); + }, + gotoSCURL(URL){ + // need to pause the music since soundcloud is going to start playing this song anyways + if(this.get('playing')){ + this.send('play'); + } + + this.send('gotoURL', URL); }, gotoURL(URL){ Em.$('.tooltip').remove(); @@ -66,8 +77,12 @@ export default Em.Component.extend(helperMixin, visualizerMixin, { processResult(resultObj); } - if(this.get('playQueuePointer') === -1 && !this.get('firstVisit')){ - this.send('next'); + if(this.get('playQueuePointer') === -1){ + if(this.get('firstVisit')){ + this.send('goToSong', 0); + } else { + this.send('next'); + } } }, () => { this.get('notify').alert({html: this.get('urlNotFoundHtml')(URL)}); @@ -125,13 +140,17 @@ export default Em.Component.extend(helperMixin, visualizerMixin, { audio.oncanplay = ()=>{ this.set('timeTotal', Math.floor(audio.duration)); }; - audio.onerror = ()=>{ + audio.onerror = (event)=>{ var playQueuePointer =this.get('playQueuePointer'), song = this.get('playQueue')[playQueuePointer]; this.send('removeAudio', playQueuePointer); - this.get('notify').alert({html: this.get('failedToPlayFileHtml')(song.fileName)}); + if(event.target.error.code){ + this.get('notify').alert({html: this.get('failedToDecodeFileHtml')(song.fileName)}); + } else { + this.get('notify').alert({html: this.get('failedToPlayFileHtml')(song.fileName)}); + } }; audio.ontimeupdate = ()=>{ this.set('timeElapsed', Math.floor(audio.currentTime)); @@ -157,7 +176,7 @@ export default Em.Component.extend(helperMixin, visualizerMixin, { Em.run.later(()=>{ var track = Em.$('.track'+index); - if(!Em.isNone(track)) { + if(!Em.isNone(track) && !Em.isNone(track.offset)) { playListArea.animate({ scrollTop: track.offset().top - playListArea.offset().top + playListArea.scrollTop() }); @@ -212,7 +231,8 @@ export default Em.Component.extend(helperMixin, visualizerMixin, { // replay song if(this.get('timeElapsed') === timeTotal && timeTotal !== 0){ - this.send('seekChanged', 0); + this.send('next', true); + return; } dancer.play(); @@ -626,6 +646,10 @@ export default Em.Component.extend(helperMixin, visualizerMixin, { init() { this._super(); + window.requestAnimationFrame = window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.msRequestAnimationFrame; + window.cancelAnimationFrame = window.cancelAnimationFrame || window.webkitCancelAnimationFrame || window.mozCancelAnimationFrame || window.msCancelAnimationFrame; + navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia; + var dancer = new Dancer(), self = this, storage = this.get('storage'), @@ -642,31 +666,16 @@ export default Em.Component.extend(helperMixin, visualizerMixin, { kick.on(); - //dancer.bind('update', function(){ - // var waveform = this.getWaveform(), spectrum = this.getSpectrum(), sumS = 0, sumW = 0; - // for (let i = 0, l = spectrum.length; i < l && i < 512; i++ ) { - // sumS += spectrum[i]; - // } - // - // for (let i = 0, l = waveform.length; i < l && i < 512; i++ ) { - // sumW += waveform[i]; - // } - // - // //console.log('sumW: ' + sumW + ', sumS: ' + sumS); - //}); - this.setProperties({ dancer: dancer, kick: kick }); - navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia; - if(navigator.getUserMedia === undefined){ this.set('usingMicSupported', false); } - ['volume', 'shuffle', 'repeat', 'volumeMuted', 'threshold', 'interval', 'frequency', 'speakerViewed', 'transitionTime', 'randomTransition', 'playerBottomDisplayed', 'onBeatBriAndColor', 'audioMode', 'songBeatPreferences', 'debugFiltered', 'firstVisit', 'currentVisName'].forEach(function (item) { + ['volume', 'shuffle', 'repeat', 'volumeMuted', 'threshold', 'interval', 'frequency', 'speakerViewed', 'transitionTime', 'randomTransition', 'playerBottomDisplayed', 'onBeatBriAndColor', 'audioMode', 'songBeatPreferences', 'debugFiltered', 'firstVisit', 'currentVisName', 'playQueue', 'playQueuePointer'].forEach(function (item) { if (!Em.isNone(storage.get('huegasm.' + item))) { var itemVal = storage.get('huegasm.' + item); @@ -684,6 +693,8 @@ export default Em.Component.extend(helperMixin, visualizerMixin, { }, didInsertElement() { + this._super(); + var self = this; Em.$('#fileInput').on('change', function () { @@ -712,13 +723,11 @@ export default Em.Component.extend(helperMixin, visualizerMixin, { } }); - // demo tracks + // demo tracks if(this.get('firstVisit')){ - this.send('handleNewSoundCloudURL', 'https://soundcloud.com/jacobanthony43/jacobychillcatalystbarstommisch'); - this.send('handleNewSoundCloudURL', 'https://soundcloud.com/odesza/light-feat-little-dragon'); - this.send('handleNewSoundCloudURL', 'https://soundcloud.com/sinusic-prod/lisboa'); - // TODO: uncomment and test - //this.get('storage').set('huegasm.firstVisit', false); + this.send('handleNewSoundCloudURL', 'https://soundcloud.com/mrsuicidesheep/tracks'); + + this.get('storage').set('huegasm.firstVisit', false); } if(!this.get('playerBottomDisplayed')) { diff --git a/app/pods/components/music-tab/mixins/helpers.js b/app/pods/components/music-tab/mixins/helpers.js index 4c1969f..bae2dac 100644 --- a/app/pods/components/music-tab/mixins/helpers.js +++ b/app/pods/components/music-tab/mixins/helpers.js @@ -77,7 +77,7 @@ export default Em.Mixin.create({ timeTotal: 0, lastLightBopIndex: 0, - usingMicSupported: false, + usingMicSupported: true, // 0 - local, 1 - mic, possibly more to come audioMode: 0, usingLocalAudio: Em.computed.equal('audioMode', 0), @@ -105,6 +105,9 @@ export default Em.Mixin.create({ failedToPlayFileHtml: function(fileName){ return ''; }, + failedToDecodeFileHtml: function(fileName){ + return ''; + }, scUrl: function(){ var rtn = null, @@ -214,10 +217,10 @@ export default Em.Mixin.create({ }.property('repeat'), playingIcon: function () { - if(this.get('timeElapsed') === this.get('timeTotal') && this.get('timeTotal') !== 0){ - return 'replay'; - } else if (this.get('playing')) { + if(this.get('playing')){ return 'pause'; + } else if(this.get('timeElapsed') === this.get('timeTotal') && this.get('timeTotal') !== 0){ + return 'replay'; } else { return 'play-arrow'; } @@ -286,8 +289,9 @@ export default Em.Mixin.create({ }.property('volumeMuted', 'volume'), onOptionChange: function(self, option){ - this.get('storage').set('huegasm.' + option, this.get(option)); - }.observes('randomTransition', 'onBeatBriAndColor'), + option = option.replace('.[]', ''); + this.get('storage').set('huegasm.' + option, this.get(option), { compress: true }); + }.observes('randomTransition', 'onBeatBriAndColor', 'playQueue.[]', 'playQueuePointer'), onRepeatChange: function () { var tooltipTxt = 'Repeat all', type = 'repeat'; diff --git a/app/pods/components/music-tab/mixins/visualizer.js b/app/pods/components/music-tab/mixins/visualizer.js index a557ed5..29a6670 100644 --- a/app/pods/components/music-tab/mixins/visualizer.js +++ b/app/pods/components/music-tab/mixins/visualizer.js @@ -1,219 +1,74 @@ import Em from 'ember'; export default Em.Mixin.create({ - currentVisName: 'None', + currentVisName: 'Wave', - currentVisSettings: function () { - var name = this.get('currentVisName'); + visNames: ['None', 'Bars', 'Wave'], - this.get('storage').set('huegasm.currentVisName', name); + onCurrentVisNameChange: function () { + var currentVisName = this.get('currentVisName'); - if (Em.isNone(name)) { - return null; - } else { - return this.get('visSettings').filter(function (vis) { - return vis.name === name - }); + if(currentVisName === 'None'){ + var canvasEl = Em.$('#visualization')[0], + ctx = canvasEl.getContext('2d'); + + ctx.clearRect(0, 0, canvasEl.width, canvasEl.height); } - }.property('currentVisName'), - visNames: function () { - return this.get('visSettings').map(function (vis) { - return vis.name; + this.get('storage').set('huegasm.currentVisName', currentVisName); + }.observes('currentVisName'), + + didInsertElement(){ + var dancer = this.get('dancer'), + canvasEl = Em.$('#visualization')[0], + ctx = canvasEl.getContext('2d'), + spacing = 0, + h = canvasEl.height, + w = canvasEl.width; + + dancer.bind('update', () => { + var currentVisName = this.get('currentVisName'); + if(currentVisName === 'None'){ + return; + } + + ctx.clearRect(0, 0, w, h); + + if (currentVisName === 'Wave') { + let width = 2, + count = 1024, + gradient = ctx.createLinearGradient(0, 0, 0, 300); + + gradient.addColorStop(0, '#0036FA'); + gradient.addColorStop(0.3, 'white'); + + ctx.lineWidth = 1; + ctx.strokeStyle = gradient; + var waveform = dancer.getWaveform(); + + ctx.beginPath(); + ctx.moveTo(0, h / 2); + for (let i = 0, l = waveform.length; i < l && i < count; i++) { + ctx.lineTo(i * ( spacing + width ), ( h / 2 ) + waveform[i] * ( h / 2 )); + } + ctx.stroke(); + ctx.closePath(); + } else if (currentVisName === 'Bars') { + let width = 4, + count = 128, + gradient = ctx.createLinearGradient(0, 0, 0, 300); + + gradient.addColorStop(0.5, '#0f0'); + gradient.addColorStop(0.4, '#ff0'); + gradient.addColorStop(0, '#F12B24'); + + ctx.fillStyle = gradient; + var spectrum = dancer.getSpectrum(); + for (let i = 0, l = spectrum.length; i < l && i < count; i++) { + ctx.fillRect(i * ( spacing + width ), h, width, -spectrum[i] * h - 23); + } + } }); - }.property('visSettings'), - - visSettings: [{ - name: "None", - set: null - }, { - name: "Borealis", - set: { - controls: { - seuilAudible: 0.002942, - radiusAmplitude: 0, - radius: 116, - radiusVar: 0.16, - amplitudeOnMag: -1.02, - colors: {r: 0.91, g: 0.6, b: 0.75}, - burningColors: {r: 8.7, g: 4.64, b: 3.29}, - burningColorsMax: {r: 0.898, g: 0.665, b: 0.258}, - spectralColors: {r: -1.24, g: -0.98, b: -1.6}, - bgColors: {r: 0, g: 0, b: 4}, - speed: -0.13, - picture: "assets/images/flares/flare4.png", - colorsDecr: {r: 0.04787, g: -0.00097, b: -0.00281}, - dots: 288, - maxSize: 758, - rotation: {x: 0, y: 0, z: 0}, - position: {x: 0, y: 0, z: 0}, - radiusIncr: -1.24, - speedIncr: 4, - opacityBase: 0.471, - opacityAmp: 1.5, - opacityDecr: 0.0048, - centerAmp: 0, - sizeAmp: 0.73, - sizeDecr: -0.00289, - freqSpeedIncr: 7.6313, - magSpeedIncr: 0, - baseRotate: -910.3086207435979, - autoRotate: 0, - rotateAmp: -0.029517, - textureRotateDecr: 0.128881, - textureRotateAmp: -0.7313, - equalizer: 263, - gravity: {x: -0.00558, y: 0.0068, z: 0.0121}, - showAmp: 0, - blending: 2, - autoTraveler: 1, - camera: { - positionIncr: {x: 0, y: 0, z: 0}, - traveler: { - freq: {x: 0, y: 0.01, z: 0.01, x2: 0, y2: 0, z2: 0}, - phase: {x: 0, y: 0.01, z: 0.01, x2: 0, y2: 0, z2: 0}, - width: {x: 0, y: 0.1, z: 0.1, x2: 0, y2: 0, z2: 0}, - center: {x: 0, y: 0, z: 0, x2: 0, y2: 0, z2: 0} - } - } - }, - camera: { - position: {x: 40, y: 13.218400900933863, z: -9.516315737622158}, - rotation: {x: -2.194772871513226, y: 1.184106819993227, z: 2.2315573880289308} - }, - particles: { - position: {x: -198.4052190636108, y: -37.40200000000022, z: 15.228000000000227}, - rotation: {x: 4.733931634852215, y: 1.9666500000000078, z: -0.16421999999999976} - } - } - }, - { - name: "Lightwave", - set: [{ - controls: { - seuilAudible: 0.002088, - radiusAmplitude: -7.852, - radius: 120, - radiusVar: 0.012, - radiusVarAmp: 0, - amplitudeOnMag: 0, - colors: {r: 0.81, g: 0.81, b: 0.94}, - burningColors: {r: 7.24, g: 4.02, b: 9.42}, - burningColorsMax: {r: 0.206, g: 0.299, b: 0.9}, - spectralColors: {r: -0.28, g: 0, b: 0.19}, - bgColors: {r: 0, g: 0, b: -1}, - speed: -0.48, - picture: "assets/images/flares/vor8.2.png", - colorsDecr: {r: 0.00057, g: 0.00364, b: 0.02}, - dots: 482, - maxSize: 464, - rotation: {x: 0, y: 0, z: 0}, - position: {x: 0, y: 0, z: 0}, - radiusIncr: -1.89, - radiusIncrAmp: 4.8, - speedIncr: -37, - opacityBase: 0.986, - opacityAmp: 6.7, - opacityDecr: 0.0086, - centerAmp: 0, - sizeAmp: 2.63, - sizeDecr: 0, - freqSpeedIncr: 0, - magSpeedIncr: 0, - baseRotate: -910.8242890837017, - autoRotate: 0.0011, - rotateAmp: -0.179517, - textureRotateDecr: 0.02761, - textureRotateAmp: 0, - equalizer: -145, - gravity: {x: -0.00011, y: -0.0116, z: 0.0154}, - gravityAmp: {x: 0, y: 0, z: 1.97}, - showAmp: 0, - blending: 2, - autoTraveler: 1, - camera: { - positionIncr: {x: 0, y: 0, z: 0}, - traveler: { - freq: {x: 0.0191, y: 0.01, z: 0.01, x2: 0, y2: 0.008925, z2: 0.00265}, - phase: {x: 0.0154, y: 0.01, z: 0.01, x2: 0, y2: 0.0125, z2: 0.003525}, - width: {x: 0.84, y: -0.02, z: -0.02, x2: 0, y2: 0.005, z2: 0}, - center: {x: 0, y: 0, z: 0, x2: 0, y2: 0, z2: 0} - } - } - }, - camera: { - position: {x: 28.290507810306817, y: -79.05312595414983, z: 148.26913157117622}, - rotation: {x: 0.4898326329313103, y: 0.16680418921697668, z: -0.08829352787105102} - }, - particles: { - position: {x: 31, y: 35.789000000000456, z: 30.221000000000057}, - rotation: {x: 1.5, y: 3.813987739867519, z: 10.34557348383392} - } - }] - }, - { - name: "Neutrino", - set: { - controls: { - seuilAudible: 0.001, - radiusAmplitude: 0.422, - radius: 207, - radiusVar: 0.008, - radiusVarAmp: -4510, - amplitudeOnMag: 0, - colors: {r: 0.38, g: 0.84, b: 0.87}, - burningColors: {r: 9.42, g: 8.17, b: 1.5}, - burningColorsMax: {r: 1, g: 0.583, b: 0.183}, - spectralColors: {r: -0.3, g: 0.23, b: -0.13}, - bgColors: {r: 0, g: 0, b: -1}, - speed: 8.49, - picture: "assets/images/flares/colo.png", - colorsDecr: {r: 0, g: 0, b: 0}, - dots: 478, - maxSize: 392, - rotation: {x: 0, y: 0, z: 0}, - position: {x: 0, y: 0, z: 0}, - radiusIncr: -1.13, - radiusIncrAmp: -14.48, - speedIncr: 0, - opacityBase: 0.88, - opacityAmp: 1.3, - opacityDecr: 0.0152, - centerAmp: 0, - sizeAmp: 2.625, - sizeDecr: 0, - freqSpeedIncr: 2.6026, - magSpeedIncr: 0.3834, - baseRotate: -543.1624876256562, - autoRotate: 0, - rotateAmp: 0, - textureRotateDecr: 0.02761, - textureRotateAmp: 0, - equalizer: 83, - gravity: {x: -0.00281, y: 0.0136, z: 0.0196}, - gravityAmp: {x: -4.2, y: -0.15, z: 1.02}, - showAmp: 0, - blending: 2, - autoTraveler: 0, - camera: { - positionIncr: {x: 0, y: 0, z: 0}, - traveler: { - freq: {x: 0, y: 0.01, z: 0.01, x2: 0, y2: 0.008925, z2: 0.00265}, - phase: {x: 0, y: 0.01, z: 0.01, x2: 0, y2: 0.0125, z2: 0.003525}, - width: {x: 0, y: -0.02, z: -0.02, x2: 0, y2: 0.005, z2: 0}, - center: {x: 0, y: 0, z: 0, x2: 0, y2: 0, z2: 0} - } - } - }, - camera: { - position: {x: 40, y: -305.0573302931556, z: -176.2810417210021}, - rotation: {x: 2.094778817564933, y: 0.11304655916704225, z: -2.9488045979781217} - }, - particles: { - position: {x: -20, y: 62.67200000000026, z: 77.36300000000016}, - rotation: {x: 1.5, y: 4.53220881574775, z: 12.23706348383359} - } - } - } - ] -}); + } +}) +; diff --git a/app/pods/components/music-tab/template.hbs b/app/pods/components/music-tab/template.hbs index 95ac2c4..e30e9fc 100644 --- a/app/pods/components/music-tab/template.hbs +++ b/app/pods/components/music-tab/template.hbs @@ -26,7 +26,7 @@ {{#if scUrl}} - + {{/if}} @@ -41,148 +41,147 @@ {{#each visNames as |name|}}
  • {{name}} {{#if (eq currentVisName name)}}{{paper-icon icon="check"}}{{/if}}
  • {{/each}} - -
  • Music visualizations by Vor
  • - {{paper-icon icon="fullscreen" class="playerControllIcon"}} -
    - - +{{!--{{paper-icon icon="fullscreen" class="playerControllIcon"}}--}} + + + -
    - +
    + -
    - {{#if usingLocalAudio}} - +
    +{{#if usingLocalAudio}} + - + - {{paper-icon icon="shuffle" class=shuffleClass}} - {{paper-icon icon=repeatIcon class=repeatClass}} - {{/if}} +{{paper-icon icon="shuffle" class=shuffleClass}} +{{paper-icon icon=repeatIcon class=repeatClass}} +{{paper-icon icon="clear-all" class="playerControllIcon"}} +{{/if}} - {{#if usingMicSupported}} - {{paper-icon icon=micIcon class=usingMicAudioClass}} +{{#if usingMicSupported}} +{{paper-icon icon=micIcon class=usingMicAudioClass}} +{{/if}} +
    + +{{#if usingMicAudio}} +
    +{{paper-icon icon="mic"}} +
    +{{else}} +{{#if usingLocalAudio}} +
    + {{#if (or playQueueEmpty dragging)}} +
    + {{#if dragging}} + Drag your music files here + {{else}} + Add your music files here {{/if}}
    + {{paper-icon icon="library-music" class=dimmerOnClass}} + {{/if}} - {{#if usingMicAudio}} -
    - {{paper-icon icon="mic"}} + {{#each playQueue as |item index|}} +
    + {{#if item.picture}} + + {{else}} + + {{/if}} + +
    + {{#if item.title}} +
    {{item.title}}
    +
    + {{#if item.artistUrl}} + {{item.artist}} + {{else}} + {{item.artist}} + {{/if}} +
    + {{else}} + {{item.filename}} + {{/if}}
    - {{else}} - {{#if usingLocalAudio}} -
    - {{#if (or playQueueEmpty dragging)}} -
    - {{#if dragging}} - Drag your music files here - {{else}} - Add your music files here - {{/if}} -
    - {{paper-icon icon="library-music" class=dimmerOnClass}} - {{/if}} - {{#each playQueue as |item index|}} -
    - {{#if item.picture}} - - {{else}} - - {{/if}} - -
    - {{#if item.title}} -
    {{item.title}}
    -
    - {{#if item.artistUrl}} - {{item.artist}} - {{else}} - {{item.artist}} - {{/if}} -
    - {{else}} - {{item.filename}} - {{/if}} -
    - - {{paper-icon icon="close"}} -
    - {{/each}} -
    - {{/if}} - {{/if}} -
    + {{paper-icon icon="close"}} +
    + {{/each}} +
    +{{/if}} +{{/if}} +
    -
    - {{paper-icon icon=beatDetectionArrowIcon}} -
    +
    +{{paper-icon icon=beatDetectionArrowIcon}} +
    -
    - {{#if usingBeatPreferences}} - - {{paper-icon id="saveBeatPreferencesStar" icon="star"}} - - {{/if}} - -
    -
    - Beat Threshold - {{range-slider start=threshold orientation="vertical" step=beatOptions.threshold.step range=beatOptions.threshold.range slide="thresholdChanged" pips=beatOptions.threshold.pips}} -
    {{threshold}}
    -
    - -
    - Beat Interval - {{range-slider start=interval orientation="vertical" step=beatOptions.interval.step range=beatOptions.interval.range slide="intervalChanged" pips=beatOptions.interval.pips}} -
    {{interval}} sec
    -
    +
    +{{#if usingBeatPreferences}} + +{{paper-icon id="saveBeatPreferencesStar" icon="star"}} + +{{/if}} +
    - Frequency Range - {{range-slider start=frequency orientation="vertical" step=beatOptions.frequency.step range=beatOptions.frequency.range connect=true slide="frequencyChanged" pips=beatOptions.frequency.pips}} -
    [{{#each frequency as |item index|}}{{item}}{{#unless index}} - ,{{/unless}}{{/each}} - ] -
    + Beat Threshold +{{range-slider start=threshold orientation="vertical" step=beatOptions.threshold.step range=beatOptions.threshold.range slide="thresholdChanged" pips=beatOptions.threshold.pips}} +
    {{threshold}}
    - Transition Time - {{range-slider start=transitionTime orientation="vertical" step=beatOptions.transitionTime.step range=beatOptions.transitionTime.range slide="transitionTimeChanged" pips=beatOptions.transitionTime.pips}} -
    {{transitionTime}} sec
    +Beat Interval +{{range-slider start=interval orientation="vertical" step=beatOptions.interval.step range=beatOptions.interval.range slide="intervalChanged" pips=beatOptions.interval.pips}} +
    {{interval}} sec
    +
    + +
    +Frequency Range +{{range-slider start=frequency orientation="vertical" step=beatOptions.frequency.step range=beatOptions.frequency.range connect=true slide="frequencyChanged" pips=beatOptions.frequency.pips}} +
    [{{#each frequency as |item index|}}{{item}}{{#unless index}} +,{{/unless}}{{/each}} +] +
    +
    + +
    +Transition Time +{{range-slider start=transitionTime orientation="vertical" step=beatOptions.transitionTime.step range=beatOptions.transitionTime.range slide="transitionTimeChanged" pips=beatOptions.transitionTime.pips}} +
    {{transitionTime}} sec
    - {{#paper-button raised=true warn=true action="defaultControls"}}Default{{/paper-button}} +{{#paper-button raised=true warn=true action="defaultControls"}}Default{{/paper-button}}
    - {{#paper-switch checked=randomTransition disabled=trial}}{{randomTransitionLabel}}{{/paper-switch}} +{{#paper-switch checked=randomTransition disabled=trial}}{{randomTransitionLabel}}{{/paper-switch}}
    - {{#paper-switch checked=onBeatBriAndColor disabled=trial}} {{onBeatBriAndColorLabel}}{{/paper-switch}} +{{#paper-switch checked=onBeatBriAndColor disabled=trial}} {{onBeatBriAndColorLabel}}{{/paper-switch}}
    @@ -190,27 +189,27 @@
    {{#if speakerViewed}}
    -
    -
    -
    -
    -
    -
    -
    -
    +
    +
    +
    +
    +
    +
    +
    +
    -
    -
    -
    -
    +
    +
    +
    +
    {{else}}
    - {{#each beatHistory as |item|}} -

    {{{item}}}

    - {{/each}} +{{#each beatHistory as |item|}} +

    {{{item}}}

    +{{/each}}
    - {{#paper-switch checked=debugFiltered class="debugFilteredSwitch"}} {{debugFilteredText}} {{/paper-switch}} +{{#paper-switch checked=debugFiltered class="debugFilteredSwitch"}} {{debugFilteredText}} {{/paper-switch}} {{/if}} {{#paper-switch checked=speakerViewed class="speakerSwitch"}} {{speakerLabel}} {{/paper-switch}} diff --git a/app/styles/app.scss b/app/styles/app.scss index 931b268..05b9885 100644 --- a/app/styles/app.scss +++ b/app/styles/app.scss @@ -56,11 +56,11 @@ md-progress-circular[md-mode=indeterminate] .md-spinner-wrapper { padding-right: 5px; text-align: right; z-index: 3; - font-size:16px + font-size: 16px; } .settingsItem { - margin-left: 15px; + margin-left: 10px; position: relative; display: inline-block; transition: 0.1s all ease-in-out; @@ -477,14 +477,14 @@ md-switch.md-default-theme.md-checked .md-thumb { width: 100%; color: white !important; z-index: 20; - background: linear-gradient(rgba(0, 0, 0, 0), rgba(0, 0, 0, 0.7)); + background: linear-gradient(rgba(0, 0, 0, 0), rgba(0, 0, 0, 1)); .tooltip.top { margin-top: -17px; } .tooltip-arrow { display: none; } - .play-arrow, .pause { + .play-arrow, .pause, .replay { font-size: 30px; } } @@ -966,6 +966,9 @@ div.ember-modal-dialog { md-input-container input { color: black !important; } + md-input-container label { + color: rgba(0, 0, 0, 0.26); + } } .addMusicButton { @@ -1005,10 +1008,6 @@ div.ember-modal-dialog { height: 100%; } -.credits { - border-top: 1px solid black; -} - .check { margin-left: 10px; position: relative; @@ -1016,9 +1015,13 @@ div.ember-modal-dialog { } .visualizersMenu { - left: -165px; + left: -135px; } .displayIcon { - background:url(assets/images/favicons/favicon-194x194.png) center center no-repeat; + background:url(images/favicons/favicon-90x90.png) center center no-repeat; +} + +.keyboard-arrow-down { + font-size: 20px; } diff --git a/bower.json b/bower.json index 86a3caa..6ebc520 100644 --- a/bower.json +++ b/bower.json @@ -19,8 +19,7 @@ "locallyjs": "~0.3.2", "matchMedia": "~0.2.0", "nouislider": "^8.0.1", - "qunit": "~1.18.0", - "three.js": "~0.72.0" + "qunit": "~1.18.0" }, "resolutions": { "ember": "~2.1.0", diff --git a/ember-cli-build.js b/ember-cli-build.js index 11d1234..bf066db 100644 --- a/ember-cli-build.js +++ b/ember-cli-build.js @@ -13,7 +13,6 @@ module.exports = function(defaults) { app.import('bower_components/bootstrap-sass/assets/javascripts/bootstrap/dropdown.js'); app.import('bower_components/JavaScript-ID3-Reader/dist/id3-minimized.js'); app.import('bower_components/jquery-mousewheel/jquery.mousewheel.js'); - app.import('bower_components/three.js/three.js'); app.import('bower_components/locallyjs/dist/locally.min.js'); app.import('bower_components/intro.js/intro.js'); app.import('bower_components/intro.js/introjs.css'); diff --git a/public/assets/images/favicons/favicon-90x90.png b/public/assets/images/favicons/favicon-90x90.png new file mode 100644 index 0000000000000000000000000000000000000000..4b40de416318377c673182bf2755de43727fd044 GIT binary patch literal 8295 zcmV-tAei5YP)S7g7A1 z+M`XgTp>3;Q%nve2nn)7h?C8*5Cg=Z3V5SLR~sf$jYrj2dWh#>35xe0L_yIW{7|+X zKLoa-79KP~I~9(?xd60;&haY7k5q-rE)f&s`stg=xk82&Vmg749tO!W&{uk3DxkJ- zfH>&)ivij@7er4X{eLB(ltKs}1~F7Z70W?sJS2AAi(|gUbAppTHfFv0qr&ypSR8de}e#PPU5ld|V=0F5CRfaAqLyQQ} zhb5}jBFsU9;0)VzRqs7L?b>uVYEsKd>wsLCpmX zv>ovnf){T~6mFbeWGZe|p+7+9Hi0{m1wVYMY_6_^d3QO4A1V>r=!R!cE#y#;o*JSO zp`vg(w&|#tV3KTTX^%r!b0Yc)DQF+bkP?H*MyCu%nE~_#NvTn!Cx^;vKO_skn}Sz; zZXCLxfHqJp?!desAR$wYJs9iRhb)~Qx15u7$~GX056p=7Y1-0 z&~;$TtZ#L6ZaQGN-*(>XG zH5Cv4JIFtaa*+R1qeYGCV;~zj$Tn>P#a^vcQgmIB*ZS}1*`d3xZG52x(M<*nyd;P& zEdxb=y$TPn_!#dVb3OIE0a~QW_9<3Ac&TpqbB{az2_OBtrT1p6kN&*(Q~Y^z5c>{u zEoESqa;c)?qT=TO*J-fI<@at_-~b&9x`~7Aq>@M_j=kzL(CPB|7&d6A)V}!rI2gPF zrrqVi%FpHZt{a8>=rLvd{OFkiT05YjQlHim&7~lGpB*w+klR!5Chu8ykays%&c%?= z>BsY^JWJ(aDmPH+OQkiHWGWU;1!t=1xP~Wcw*~a3GLp);%pRD(umY8z9I%iHQ&P#^ zA`9_(@LRJ~^x@|k8v^u6F>4H<2O&R=9=Ypd$0uY$>RqH%B4j4s*+xHFKxGb8t~N2s0La z;JA-mlYRv~!msp1_s{6t|Df^^m0?sexqo}EHa5f3n0Dv2!NbH2<+eYik$>HpK=#kT zPWnDGkV(Hc6PpC+`51azjqy>^E9)YnNSnz7j9o+DexAxS&c|tIiHrXTl`zkz_1F=3 zhHMwffbN-O&r}O}c^H<`_uFvV6Pg_8KCn{{7KRJjF);W$sxptKRH9 z0r^;eoM~>`Hy*~atqZNBf2&NQ`~@UG4i9Q98FN7!1hja%cl8FkJ^qn%OF}2*B6O=Y zd&gqNCi=FU%62L&TUL33NbX#2ga=GjuA;=Qvq3YkTBg;ajyAj>%an!+Q~EmIfa)qC?@c(u%emZH>g zgdHQe-*0O&pdUf_*9Hc12@j#q*Tzx<@}jj^7AT5t?bS-g z(qbnbPsgR4KH?ifiGLVq>I+$VLx1gi<^b;SadQRN>HsdB zMydkXT2O+Y1}28FA!5cTgBD3P<3LM|3Uo`L+eR9G3=A6aJ<2P%7FTesj$S}Ov(#*8 zO*u9UwFI$UkdPs0AZK%ZriJR8>PznHJZr>5&T&Xupg=Sf;a8i1piWbP-tBXh2gmqXr76NK}|0Nlr*Q99=ZM zAc1B)=`g~qs;u9H86v_#78?`jAO)I!rwW502?;RhIluxg(3W6;Rno&o6b72g43gZC z{{A7LscYd%mEjHvQ5-Ue)YUVYkGbBt1@=XhOItQ9FL9!lsz-b=4A!75AW@WA)lHBq zms+1${D*)pp#E}@pg2L5;n7Rzf%pXOxEoG4e{x1z=ePuXpZl0lmj08t+)|)lE$(ve z$J(@a@q{T|^M6^>H{_B-QjzPEB-mw^_EZ9UVkrg{#~1UQ@qoou2(qhFRK@q^2>K%> zokvM#obFnnNZnJx{>RUMq1Sc7=1Yq0HpdgT!-k$lvnkVPHD+4e_P$9SY>y2p77B81 z!Fb+xYkgnD|qH*lz1~^xL=u&95GD%wea_lr6q`s{Sv7mL^T#V`6TC-x=`*KlAML ztqAUor1_)1HF~(7N-|%%2(Kk|)XE(g(56#eHjWRGZLEAHphGE3ol#i8LBV zv-TFkYuf}2K0Q3BG22YHqJ16*x{WxwyEQ#+t)gaz}5e5a~3|;�iDf$yd6Lh&*yk}?9gaHi-o|JorHXQ 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 literal 0 HcmV?d00001