Better speaker design, starting on youtube integration

This commit is contained in:
lone-cloud 2015-10-04 01:06:10 -07:00
parent 29c023c343
commit 6c82d0f273
13 changed files with 540 additions and 272 deletions

View file

@ -6,7 +6,7 @@
{{/each}}
</div>
<div id="settings" class="col-lg-1 col-sm-2 col-xs-3">
<div id="settings" class="col-lg-2 col-sm-2 col-xs-3">
<span id="groupMenu" class="settingsItem groupMenu {{if groupControlDisplayed 'on'}}">
<span class="bootstrapTooltip" data-toggle="tooltip" data-placement="bottom auto" data-title="Light Groups" {{action "toggleGroupControl"}}>{{paper-icon icon="group"}}</span>

View file

@ -3,7 +3,6 @@ import Em from 'ember';
export default Em.Component.extend({
classNames: ['col-lg-4', 'col-lg-offset-4', 'col-sm-6', 'col-sm-offset-3', 'col-xs-12'],
classNameBindings: ['active::hidden'],
elementId: 'lightControl',
activeLights: [],
lightsData: null,

View file

@ -1,42 +1,57 @@
import Em from 'ember';
import musicControlMixin from './mixins/music-control';
import musicControlMixin from './mixins/music-tab';
import visualizerMixin from './mixins/visualizer';
export default Em.Component.extend(musicControlMixin, visualizerMixin, {
classNames: ['col-lg-6', 'col-lg-offset-3', 'col-sm-10', 'col-sm-offset-1', 'col-xs-12'],
classNames: ['col-lg-8', 'col-lg-offset-2', 'col-sm-10', 'col-sm-offset-1', 'col-xs-12'],
classNameBindings: ['active::hidden'],
onActiveChange: function(){
if(this.get('active')){
Em.$('#beatSpeakerCenter').removeClass('pop');
Em.$('#playNotification').removeClass('fadeOut');
Em.$('#beatSpeakerCenterOuter').removeClass('vibrateOuter');
Em.$('#beatSpeakerCenterInner').removeClass('vibrateInner');
}
}.observes('active'),
actions: {
useMic() {
var usingMic = this.get('usingMic');
useYoutubeAudio: function(){
var audioStream = this.get('audioStream');
if(!usingMic){
this.startUsingMic();
} else {
this.changePlayerControl('usingMic', !usingMic);
this.changePlayerControl('audioMode', 2);
this.get('audioStream').stop();
if(this.get('playQueuePointer') !== -1) {
this.send('goToSong',this.get('playQueuePointer'));
this.send('volumeChanged', this.get('volume'));
}
document.title = 'Huegasm';
if(!Em.isNone(audioStream)){
audioStream.stop();
this.set('audioStream', null);
}
document.title = 'Youtube - Huegasm';
},
useLocalAudio: function(){
var audioStream = this.get('audioStream');
this.changePlayerControl('audioMode', 0);
if(!Em.isNone(audioStream)){
audioStream.stop();
this.set('audioStream', null);
}
if(this.get('playQueuePointer') !== -1) {
this.send('goToSong', this.get('playQueuePointer'));
this.send('volumeChanged', this.get('volume'));
}
document.title = 'Huegasm';
},
useMicAudio() {
this.startUsingMic();
},
slideTogglePlayerBottom(){
this.changePlayerControl('playerBottomDisplayed', !this.get('playerBottomDisplayed'));
},
saveSongSettings() {
},
goToSong(index){
goToSong(index, playSong){
var dancer = this.get('dancer'), audio = new Audio();
audio.src = this.get('playQueue')[index].url;
@ -50,7 +65,9 @@ export default Em.Component.extend(musicControlMixin, visualizerMixin, {
timeElapsed: 0
});
this.send('play');
if(playSong){
this.send('play');
}
},
removeAudio(index){
if(index === this.get('playQueuePointer')) {
@ -74,15 +91,16 @@ export default Em.Component.extend(musicControlMixin, visualizerMixin, {
Em.$('#playNotification').removeClass('fadeOut').prop('offsetWidth', Em.$('#playNotification').prop('offsetWidth')).addClass('fadeOut');
}
},
play() {
var dancer = this.get('dancer');
play(replayPause) {
var dancer = this.get('dancer'), playQueuePointer = this.get('playQueuePointer');
if(this.get('playQueuePointer') !== -1 ) {
if(playQueuePointer !== -1 ) {
if (this.get('playing')) {
dancer.pause();
clearInterval(this.get('incrementElapseTimeHandle'));
this.toggleProperty('playing');
this.set('timeElapsed', Math.floor(dancer.getTime()));
if(!replayPause){
this.set('timeElapsed', Math.floor(dancer.getTime()));
}
} else {
if(this.get('volumeMuted')) {
dancer.setVolume(0);
@ -90,10 +108,15 @@ export default Em.Component.extend(musicControlMixin, visualizerMixin, {
dancer.setVolume(this.get('volume')/100);
}
// replay song
if(this.get('timeElapsed') === this.get('timeTotal')){
this.send('seekChanged', 0);
}
dancer.play();
this.set('incrementElapseTimeHandle', window.setInterval(this.incrementElapseTime.bind(this), 1000));
this.toggleProperty('playing');
}
this.toggleProperty('playing');
}
},
volumeChanged(value) {
@ -104,13 +127,22 @@ export default Em.Component.extend(musicControlMixin, visualizerMixin, {
},
next() {
var playQueuePointer = this.get('playQueuePointer'), playQueueLength = this.get('playQueue.length');
var nextSong = (playQueuePointer + 1);
var nextSong = (playQueuePointer + 1), repeat = this.get('repeat');
if(nextSong > playQueueLength-1 && this.get('repeat') === 1){
nextSong = nextSong % playQueueLength;
this.get('beatHistory').clear();
this.send('goToSong', nextSong);
if(repeat === 2){
this.send('goToSong', playQueuePointer, true);
} else if(nextSong > playQueueLength-1){
if(repeat === 1){
nextSong = nextSong % playQueueLength;
} else {
this.send('play', true);
return;
}
}
this.send('goToSong', nextSong, true);
},
previous() {
if(this.get('timeElapsed') > 5) {
@ -123,7 +155,7 @@ export default Em.Component.extend(musicControlMixin, visualizerMixin, {
nextSong = this.get('playQueue.length') - 1;
}
this.send('goToSong', nextSong);
this.send('goToSong', nextSong, true);
}
},
toggleVisualizations() {
@ -189,12 +221,12 @@ export default Em.Component.extend(musicControlMixin, visualizerMixin, {
onBeatBriAndColorChanged(value){
this.set('onBeatBriAndColor', value);
},
usingMicChanged(value){
if(value) {
audioModeChanged(value){
if(value === 1) {
this.startUsingMic();
} else {
this.set('usingMic', false);
}
this.set('audioMode', value);
},
clickSpeaker(){
this.simulateKick(1);
@ -224,7 +256,7 @@ export default Em.Component.extend(musicControlMixin, visualizerMixin, {
// make sure to init the first song
if(playQueue.length > 0 && self.get('playQueuePointer') === -1){
self.send('goToSong', 0);
self.send('goToSong', 0, true);
}
};
@ -246,7 +278,7 @@ export default Em.Component.extend(musicControlMixin, visualizerMixin, {
navigator.getUserMedia(
{audio: true},
(stream) => {
this.changePlayerControl('usingMic', true);
this.changePlayerControl('audioMode', 1);
var dancer = this.get('dancer');
if(dancer.audio && dancer.audio.pause) {
@ -264,7 +296,11 @@ export default Em.Component.extend(musicControlMixin, visualizerMixin, {
dancer.load(stream, true);
dancer.setVolume(0);
},
function(err) {
(err) => {
if(err.name == 'DevicesNotFoundError'){
this.get('notify').alert({html: this.get('notFoundHtml')});
}
console.log('Error during navigator.getUserMedia: ' + err.name + ', ' + err.message + ', ' + err.constraintName);
}
);
@ -311,17 +347,6 @@ export default Em.Component.extend(musicControlMixin, visualizerMixin, {
});
},
goToNextSong() {
this.get('beatHistory').clear();
if(this.get('repeat') === 2){
this.send('goToSong', this.get('playQueuePointer'));
} else {
this.get('timeElapsed');
this.send('next');
}
},
dragOver() {
var dragLeaveTimeoutHandle = this.get('dragLeaveTimeoutHandle');
this.set('dragging', true);
@ -386,7 +411,8 @@ export default Em.Component.extend(musicControlMixin, visualizerMixin, {
//work the music beat area
if(this.get('speakerViewed')){
// simulate the speaker vibration by running a CSS animation on it
Em.$('#beatSpeakerCenter').removeClass('pop').prop('offsetWidth', Em.$('#beatSpeakerCenter').prop('offsetWidth')).addClass('pop');
Em.$('#beatSpeakerCenterOuter').removeClass('vibrateOuter').prop('offsetWidth', Em.$('#beatSpeakerCenterOuter').prop('offsetWidth')).addClass('vibrateOuter');
Em.$('#beatSpeakerCenterInner').removeClass('vibrateInner').prop('offsetWidth', Em.$('#beatSpeakerCenterInner').prop('offsetWidth')).addClass('vibrateInner');
} else {
var beatHistory = self.get('beatHistory'),
maxSize = self.get('maxBeatHistorySize');
@ -415,14 +441,12 @@ export default Em.Component.extend(musicControlMixin, visualizerMixin, {
self.simulateKick(mag);
}
}
}),
Store = window.Locally.Store,
locally = new Store();
});
kick.on();
dancer.bind('loaded', () => {
if(!this.get('usingMic')){
if(this.get('usingLocalAudio')){
this.set('timeTotal', Math.round(dancer.audio.duration));
}
});
@ -442,8 +466,7 @@ export default Em.Component.extend(musicControlMixin, visualizerMixin, {
this.setProperties({
dancer: dancer,
kick: kick,
locally: locally
kick: kick
});
navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia;
@ -452,9 +475,18 @@ export default Em.Component.extend(musicControlMixin, visualizerMixin, {
this.set('usingMicSupported', false);
}
['volume', 'shuffle', 'repeat', 'volumeMuted', 'threshold', 'decay', 'frequency', 'speakerViewed', 'transitionTime', 'randomTransition', 'playerBottomDisplayed', 'onBeatBriAndColor', 'usingMic'].forEach(function (item) {
if (locally.get('huegasm.' + item)) {
self.send(item+'Changed', locally.get('huegasm.' + item));
['volume', 'shuffle', 'repeat', 'volumeMuted', 'threshold', 'decay', 'frequency', 'speakerViewed', 'transitionTime', 'randomTransition', 'playerBottomDisplayed', 'onBeatBriAndColor', 'audioMode'].forEach(function (item) {
if (localStorage.getItem('huegasm.' + item)) {
var itemVal = localStorage.getItem('huegasm.' + item);
if (item === 'repeat' || item === 'volume' || item === 'decay' || item === 'threshold' || item === 'transitionTime' || item === 'audioMode') {
itemVal = Number(itemVal);
} else if(item === 'frequency') {
itemVal = itemVal.split(',').map(function(val){return Number(val);});
} else {
itemVal = (itemVal === 'true');
}
self.send(item+'Changed', itemVal);
}
});
},
@ -465,6 +497,7 @@ export default Em.Component.extend(musicControlMixin, visualizerMixin, {
Em.$('#fileInput').on('change', function () {
var files = this.files;
self.send('handleNewFiles', files);
this.value = null;
});
// prevent space/text selection when the user repeatedly clicks on the center

View file

@ -3,6 +3,8 @@ import Em from 'ember';
export default Em.Mixin.create({
dancer: null,
notify: Em.inject.service('notify'),
beatOptions: {
threshold: {
range: {min: 0.1, max: 0.9},
@ -76,16 +78,21 @@ export default Em.Mixin.create({
lastLightBopIndex: 0,
usingMicSupported: true,
usingMic: false,
// 0 - local, 1 - mic, 2 - youtube
audioMode: 0,
usingLocalAudio: Em.computed.equal('audioMode', 0),
usingMicAudio: Em.computed.equal('audioMode', 1),
usingYoutubeAudio: Em.computed.equal('audioMode', 2),
playerBottomDisplayed: false,
dragging: false,
draggingOverPlayListArea: false,
dragLeaveTimeoutHandle: null,
visualizationsDisplayed: false,
audioStream: null,
locallly: null,
notUsingMic: Em.computed.not('usingMic'),
notFoundHtml: '<div class="alert alert-danger" role="alert">A microphone was not found.</div>',
playQueueEmpty: Em.computed.empty('playQueue'),
playQueueNotEmpty: Em.computed.notEmpty('playQueue'),
playQueueMultiple: function(){
@ -149,25 +156,17 @@ export default Em.Mixin.create({
}
this.set(name, value);
this.get('locally').set('huegasm.' + name, value);
localStorage.setItem('huegasm.' + name, value);
},
incrementElapseTimeHandle: null,
incrementElapseTime(){
this.incrementProperty('timeElapsed');
if(this.get('timeElapsed') > this.get('timeTotal')){
this.goToNextSong();
if(this.get('timeElapsed') === this.get('timeTotal')){
this.send('next');
}
},
micIcon: function() {
if (this.get('usingMic')) {
return 'mic';
}
return 'mic-off';
}.property('usingMic'),
repeatIcon: function () {
if (this.get('repeat') === 2) {
return 'repeat-one';
@ -177,7 +176,9 @@ export default Em.Mixin.create({
}.property('repeat'),
playingIcon: function () {
if (this.get('playing')) {
if(this.get('timeElapsed') === this.get('timeTotal') && this.get('timeTotal') !== 0){
return 'replay';
} else if (this.get('playing')) {
return 'pause';
} else {
return 'play-arrow';
@ -198,9 +199,17 @@ export default Em.Mixin.create({
return classes;
}.property('dragging', 'draggingOverPlayListArea'),
usingMicClass: function() {
return this.get('usingMic') ? 'playerControllIcon active' : 'playerControllIcon';
}.property('usingMic'),
usingLocalAudioClass: function() {
return this.get('usingLocalAudio') ? 'playerControllIcon active' : 'playerControllIcon';
}.property('usingLocalAudio'),
usingMicAudioClass: function() {
return this.get('usingMicAudio') ? 'playerControllIcon active' : 'playerControllIcon';
}.property('usingMicAudio'),
usingYoutubeAudioClass: function() {
return this.get('usingYoutubeAudio') ? 'playerControllIcon active' : 'playerControllIcon';
}.property('usingYoutubeAudio'),
repeatClass: function () {
return this.get('repeat') !== 0 ? 'playerControllIcon active' : 'playerControllIcon';
@ -225,12 +234,12 @@ export default Em.Mixin.create({
}.property('volumeMuted', 'volume'),
onSpeakerViewedChange: function(){
this.get('locally').set('huegasm.speakerViewed', this.get('speakerViewed'));
localStorage.setItem('huegasm.speakerViewed', this.get('speakerViewed'));
this.get('beatHistory').clear();
}.observes('speakerViewed'),
onOptionChange: function(self, option){
this.get('locally').set('huegasm.' + option, this.get(option));
localStorage.setItem('huegasm.' + option, this.get(option));
}.observes('randomTransition', 'onBeatBriAndColor'),
onRepeatChange: function () {
@ -255,16 +264,6 @@ export default Em.Mixin.create({
this.changeTooltipText(type, tooltipTxt);
}.observes('shuffle').on('init'),
onUsingMicChange: function () {
var tooltipTxt = 'Listen to Mic', type = 'usingMic';
if (this.get(type)) {
tooltipTxt = 'Don\'t Listen to Mic';
}
this.changeTooltipText(type, tooltipTxt);
}.observes('usingMic').on('init'),
onVolumeMutedChange: function () {
var tooltipTxt = 'Mute', type = 'volumeMuted',
volumeMuted = this.get(type), dancer = this.get('dancer'),
@ -301,6 +300,8 @@ export default Em.Mixin.create({
if (this.get(type)) {
tooltipTxt = 'Pause';
} else if(this.get('timeElapsed') === this.get('timeTotal')){
tooltipTxt = 'Replay';
}
this.changeTooltipText(type, tooltipTxt);
@ -319,9 +320,9 @@ export default Em.Mixin.create({
beatDetectionArrowIcon: function(){
if(!this.get('playerBottomDisplayed')){
return 'arrow-drop-down';
return 'angle-double-down';
} else {
return 'arrow-drop-up';
return 'angle-double-up';
}
}.property('playerBottomDisplayed'),

View file

@ -1,15 +1,15 @@
<div class="row">
<div id="playerArea" class="col-sm-8 col-xs-12" {{action "playerAreaPlay"}}>
<div id="playNotification"
class="material-icons {{if fadeOutNotification "fadeOut"}} {{if playing "play-arrow" "pause"}}"></div>
<div id="playerControls">
{{#if notUsingMic}}
{{range-slider start=seekPosition min=0 max=100 id="seekSlider" slide="seekChanged"}}
<div id="playerArea" class="col-sm-8 col-xs-12" {{action "playerAreaPlay"}}>
<div id="playNotification"
class="material-icons {{if fadeOutNotification "fadeOut"}} {{if playing "play-arrow" "pause"}}"></div>
<div id="playerControls">
{{#if usingLocalAudio}}
{{range-slider start=seekPosition min=0 max=100 id="seekSlider" slide="seekChanged"}}
{{#if playQueueMultiple}}
<span data-toggle="tooltip" data-placement="top" class="bootstrapTooltip" id="prevTooltip"
data-title={{prevTooltipTxt}} {{action "previous"}}>{{paper-icon icon="skip-previous" class="playerControllIcon"}}</span><!--
{{#if playQueueMultiple}}
<span data-toggle="tooltip" data-placement="top" class="bootstrapTooltip" id="prevTooltip"
data-title={{prevTooltipTxt}} {{action "previous"}}>{{paper-icon icon="skip-previous" class="playerControllIcon"}}</span><!--
-->{{/if}}<!--
--><span data-toggle="tooltip" data-placement="top" id="playingTooltip" class="bootstrapTooltip"
data-title={{playingTooltipTxt}} {{action "play"}}>{{paper-icon icon=playingIcon class="playerControllIcon"}}</span><!--
@ -21,153 +21,192 @@
data-title={{volumeMutedTooltipTxt}} {{action "volumeMutedChanged"}}>{{paper-icon icon=volumeClass class="playerControllIcon volumeButton"}}</span><!--
-->{{range-slider start=volume min=0 max=100 slide="volumeChanged" id="volumeBar"}}
<div id="playerTimeControls">{{timeElapsedTxt}} / {{timeTotalTxt}}</div>
{{/if}}
<div id="playerTimeControls">{{timeElapsedTxt}} / {{timeTotalTxt}}</div>
{{/if}}
<span class="pull-right">
<span data-toggle="tooltip" data-placement="top" class="bootstrapTooltip" data-title="Visualizations" {{action "toggleVisualizations"}}>{{paper-icon icon="remove-red-eye" class="playerControllIcon"}}
{{#if (or useLocalAudio useMicAudio)}}
<span class="pull-right">
<span data-toggle="tooltip" data-placement="top" class="bootstrapTooltip"
data-title="Visualizations" {{action "toggleVisualizations"}}>{{paper-icon icon="remove-red-eye" class="playerControllIcon"}}
</span>
<span data-toggle="tooltip" data-placement="top" class="bootstrapTooltip" data-title="Full screen" {{action "fullscreen"}}>{{paper-icon icon="fullscreen" class="playerControllIcon"}}
<span data-toggle="tooltip" data-placement="top" class="bootstrapTooltip"
data-title="Full screen" {{action "fullscreen"}}>{{paper-icon icon="fullscreen" class="playerControllIcon"}}
</span>
</span>
</div>
</div>
<div id="playlist" class="col-sm-4 col-xs-12">
<input id="fileInput" type="file" accept="audio/*" multiple="true" />
<div id="playListControls">
{{#if notUsingMic}}
<span data-toggle="tooltip" data-placement="bottom auto" class="bootstrapTooltip" id="shuffleTooltip" data-title={{shuffleTooltipTxt}} {{action "shuffleChanged"}}>{{paper-icon icon="shuffle" class=shuffleClass}}</span>
<span data-toggle="tooltip" data-placement="bottom auto" class="bootstrapTooltip" id="repeatTooltip" data-title={{repeatTooltipTxt}} {{action "repeatChanged"}}>{{paper-icon icon=repeatIcon class=repeatClass}}</span>
{{/if}}
{{#if usingMicSupported}}
<span data-toggle="tooltip" data-placement="bottom auto" class="pull-right bootstrapTooltip" id="usingMicTooltip" data-title={{usingMicTooltipTxt}} {{action "useMic"}}>{{paper-icon icon=micIcon class=usingMicClass}}</span>
{{/if}}
{{#if notUsingMic}}<span data-toggle="tooltip" data-placement="bottom auto" data-title="Add new music" class="pull-right bootstrapTooltip" {{action "addAudio"}}>{{paper-icon icon="add" class="playerControllIcon"}}</span>{{/if}}
{{/if}}
</div>
</div>
{{#if usingMic}}
<div id="playAreaMic">
{{paper-icon icon="mic"}}
</div>
{{else}}
<div id="playListArea"
class={{playListAreaClass}} {{action "playListAreaAddAudio"}} {{action "playListAreaDragOver" on="dragOver"}} {{action "playListAreaDragLeave" on="dragLeave"}} {{action "dropFiles" on="drop"}}>
{{#if (or playQueueEmpty dragging)}}
<div id="dragHere">
{{#if dragging}}
Drag your music files here
{{else}}
Add your music files here
{{/if}}
<div id="playlist" class="col-sm-4 col-xs-12">
<input id="fileInput" type="file" accept="audio/*" multiple="true"/>
<div id="playListControls">
<span data-toggle="tooltip" data-placement="bottom auto" class="bootstrapTooltip"
data-title="Play local audio files" {{action "useLocalAudio"}}>{{fa-icon "music" classNames=usingLocalAudioClass}}</span>
{{#if usingMicSupported}}
<span data-toggle="tooltip" data-placement="bottom auto" class="bootstrapTooltip"
data-title="Listen to audio through mic" {{action "useMicAudio"}}>{{fa-icon "microphone" classNames=usingMicAudioClass}}</span>
{{/if}}
<span data-toggle="tooltip" data-placement="bottom auto" class="bootstrapTooltip"
data-title="Play Youtube" {{action "useYoutubeAudio"}}>{{fa-icon 'youtubeWorkaround' classNames=usingYoutubeAudioClass}}</span>
{{#if usingLocalAudio}}
<span data-toggle="tooltip" data-placement="bottom auto" data-title="Add new music"
class="pull-right bootstrapTooltip" {{action "addAudio"}}>{{paper-icon icon="add" class="playerControllIcon"}}</span>
<span data-toggle="tooltip" data-placement="bottom auto" class="pull-right bootstrapTooltip"
id="shuffleTooltip"
data-title={{shuffleTooltipTxt}} {{action "shuffleChanged"}}>{{paper-icon icon="shuffle" class=shuffleClass}}</span>
<span data-toggle="tooltip" data-placement="bottom auto" class="pull-right bootstrapTooltip"
id="repeatTooltip"
data-title={{repeatTooltipTxt}} {{action "repeatChanged"}}>{{paper-icon icon=repeatIcon class=repeatClass}}</span>
{{/if}}
</div>
{{#if usingMicAudio}}
<div id="playAreaMic">
{{paper-icon icon="mic"}}
</div>
{{paper-icon icon="library-music"}}
{{else}}
{{#if usingLocalAudio}}
<div id="playListArea"
class={{playListAreaClass}} {{action "playListAreaAddAudio"}} {{action "playListAreaDragOver" on="dragOver"}} {{action "playListAreaDragLeave" on="dragLeave"}} {{action "dropFiles" on="drop"}}>
{{#if (or playQueueEmpty dragging)}}
<div id="dragHere">
{{#if dragging}}
Drag your music files here
{{else}}
Add your music files here
{{/if}}
</div>
{{paper-icon icon="library-music"}}
{{/if}}
{{#each playQueue as |item index|}}
<div class="playlistItem cursorPointer {{if (eq index playQueuePointer) "active"}} {{if dragging "hidden"}}" {{action "goToSong" index true bubbles=false}}>
{{#if item.title}}
{{item.title}}
<div class="songArtist">{{item.artist}}</div>
{{else}}
{{item.filename}}
{{/if}}
<div data-toggle="tooltip" data-placement="bottom auto" data-title="Remove from playlist"
class="audioRemoveButton cursorPointer bootstrapTooltip" {{action "removeAudio" index bubbles=false}}>{{paper-icon icon="close"}}</div>
</div>
{{/each}}
</div>
{{else}}
<div id="playAreaYoutube">
YOUTUBE
</div>
{{/if}}
{{#each playQueue as |item index|}}
<div class="playlistItem cursorPointer {{if (eq index playQueuePointer) "active"}} {{if dragging "hidden"}}" {{action "goToSong" index bubbles=false}}>
{{#if item.title}}
{{item.title}}
<div class="songArtist">{{item.artist}}</div>
{{else}}
{{item.filename}}
{{/if}}
<div data-toggle="tooltip" data-placement="bottom auto" data-title="Remove from playlist" class="audioRemoveButton cursorPointer bootstrapTooltip" {{action "removeAudio" index bubbles=false}}>{{paper-icon icon="close"}}</div>
</div>
{{/each}}
</div>
{{/if}}
</div>
{{/if}}
</div>
</div>
<div id="slideToggle" class="text-center cursorPointer row" {{action "slideTogglePlayerBottom"}}>
<div class="col-xs-offset-3 col-xs-3">
{{paper-icon icon=beatDetectionArrowIcon}}
</div>
<div class="col-xs-3">
{{paper-icon icon=beatDetectionArrowIcon}}
</div>
<div class="col-xs-offset-3 col-xs-3">
{{fa-icon beatDetectionArrowIcon}}
</div>
<div class="col-xs-3">
{{fa-icon beatDetectionArrowIcon}}
</div>
</div>
{{#if playerBottomDisplayed}}
<div id="playerBottom" class="row">
<div id="beatArea" class="col-sm-8 col-xs-12">
<div id="vertDivider" class="hidden-xs"></div>
<div id="playerBottom" class="row">
<div id="beatArea" class="col-sm-8 col-xs-12">
<div id="vertDivider" class="visible-lg visible-md"></div>
<div class="row">
<div class="beatOption col-xs-3">
<div class="text-center">{{threshold}}</div>
{{range-slider start=threshold orientation="vertical" step=beatOptions.threshold.step range=beatOptions.threshold.range slide="thresholdChanged" pips=beatOptions.threshold.pips}}
<span data-toggle="tooltip" data-placement="bottom auto"
data-title="Maximum intensity of the sound that may be registered as a beat"
class="optionDescription bootstrapTooltip">Max. Intensity</span>
<div class="row">
<div class="beatOption col-xs-3">
<div class="text-center">{{threshold}}</div>
{{range-slider start=threshold orientation="vertical" step=beatOptions.threshold.step range=beatOptions.threshold.range slide="thresholdChanged" pips=beatOptions.threshold.pips}}
<span data-toggle="tooltip" data-placement="bottom auto"
data-title="Maximum intensity of the sound that may be registered as a beat"
class="optionDescription bootstrapTooltip">Max. Intensity</span>
</div>
<div class="beatOption col-xs-3">
<div class="text-center">{{decay}}</div>
{{range-slider start=decay orientation="vertical" step=beatOptions.decay.step range=beatOptions.decay.range slide="decayChanged" pips=beatOptions.decay.pips}}
<span data-toggle="tooltip" data-placement="bottom auto"
data-title="The rate at which the previously registered beat's intensity is reduced to find the next beat"
class="optionDescription bootstrapTooltip">Decay Rate</span>
</div>
<div class="beatOption col-xs-3">
<div class="text-center">[{{#each frequency as |item index|}}{{item}}{{#unless index}}
,{{/unless}}{{/each}}
]
</div>
{{range-slider start=frequency orientation="vertical" step=beatOptions.frequency.step range=beatOptions.frequency.range connect=true slide="frequencyChanged" pips=beatOptions.frequency.pips}}
<span data-toggle="tooltip" data-placement="bottom auto"
data-title="The frequency range of sound to listen on for the beat"
class="optionDescription bootstrapTooltip">Frequency Range</span>
</div>
<div class="beatOption col-xs-3">
<div class="text-center">{{transitionTime}} sec</div>
{{range-slider start=transitionTime orientation="vertical" step=beatOptions.transitionTime.step range=beatOptions.transitionTime.range slide="transitionTimeChanged" pips=beatOptions.transitionTime.pips}}
<span data-toggle="tooltip" data-placement="bottom auto"
data-title="The time it takes for a light to change color or brightness"
class="optionDescription bootstrapTooltip">Transition Time</span>
</div>
</div>
<div id="beatOptionButtonGroup" class="row">
<div class="beatOption col-xs-6">
{{#paper-switch checked=randomTransition disabled=trial}}<span data-toggle="tooltip"
data-placement="bottom auto"
data-title="The transition order of lights on beat"
class="optionDescription bootstrapTooltip">{{randomTransitionLabel}}</span>{{/paper-switch}}
</div>
<div class="beatOption col-xs-6">
{{#paper-switch checked=onBeatBriAndColor disabled=trial}}<span data-toggle="tooltip"
data-placement="bottom auto"
data-title="The properties of the lights to change on beat"
class="optionDescription bootstrapTooltip"> {{onBeatBriAndColorLabel}}</span>{{/paper-switch}}
</div>
</div>
<div id="playerButtonGroup" class="row">
{{#paper-button raised=true warn=true action="defaultControls"}}Default{{/paper-button}}
{{#if usingLocalAudio}}
{{#paper-button raised=true action="saveSongSettings"}}Save Song Settings{{/paper-button}}
{{/if}}
</div>
</div>
<div class="beatOption col-xs-3">
<div class="text-center">{{decay}}</div>
{{range-slider start=decay orientation="vertical" step=beatOptions.decay.step range=beatOptions.decay.range slide="decayChanged" pips=beatOptions.decay.pips}}
<span data-toggle="tooltip" data-placement="bottom auto"
data-title="The rate at which the previously registered beat's intensity is reduced to find the next beat"
class="optionDescription bootstrapTooltip">Decay Rate</span>
</div>
<div id="beatContainer" class="col-sm-4 col-xs-12">
{{#if speakerViewed}}
<div class="bezel">
<div class="rivet1"></div>
<div class="rivet2"></div>
<div class="rivet3"></div>
<div class="rivet4"></div>
<div class="rivet5"></div>
<div class="rivet6"></div>
<div class="rivet7"></div>
<div class="rivet8"></div>
<div class="beatOption col-xs-3">
<div class="text-center">[{{#each frequency as |item index|}}{{item}}{{#unless index}} ,{{/unless}}{{/each}}
]
</div>
{{range-slider start=frequency orientation="vertical" step=beatOptions.frequency.step range=beatOptions.frequency.range connect=true slide="frequencyChanged" pips=beatOptions.frequency.pips}}
<span data-toggle="tooltip" data-placement="bottom auto"
data-title="The frequency range of sound to listen on for the beat"
class="optionDescription bootstrapTooltip">Frequency Range</span>
</div>
<div id="beatSpeakerCenterOuter">
<div id="beatSpeakerCenterInner" class="cursorPointer" {{action "clickSpeaker"}}>
</div>
</div>
</div>
{{else}}
<div id="beatHistory">
{{#each beatHistory as |item|}}
<p>{{{item}}}</p>
{{/each}}
</div>
{{/if}}
<div class="beatOption col-xs-3">
<div class="text-center">{{transitionTime}} sec</div>
{{range-slider start=transitionTime orientation="vertical" step=beatOptions.transitionTime.step range=beatOptions.transitionTime.range slide="transitionTimeChanged" pips=beatOptions.transitionTime.pips}}
<span data-toggle="tooltip" data-placement="bottom auto"
data-title="Transition time to change the lights on, on beat"
class="optionDescription bootstrapTooltip">Transition Time</span>
{{#paper-switch checked=speakerViewed}} {{speakerLabel}} {{/paper-switch}}
</div>
</div>
<div id="beatOptionButtonGroup" class="row">
<div class="beatOption col-xs-6">
{{#paper-switch checked=randomTransition disabled=trial}}<span data-toggle="tooltip" data-placement="bottom auto" data-title="The order in which the active lights are transitioned to on beat" class="optionDescription bootstrapTooltip">{{randomTransitionLabel}}</span>{{/paper-switch}}
</div>
<div class="beatOption col-xs-6">
{{#paper-switch checked=onBeatBriAndColor disabled=trial}}<span data-toggle="tooltip" data-placement="bottom auto" data-title="The properties of the lights to change on beat" class="optionDescription bootstrapTooltip"> {{onBeatBriAndColorLabel}}</span>{{/paper-switch}}
</div>
</div>
<div id="playerButtonGroup" class="row">
{{#paper-button raised=true warn=true action="defaultControls"}}Default{{/paper-button}}
{{#if notUsingMic}}
{{#paper-button raised=true action="saveSongSettings"}}Save Song Settings{{/paper-button}}
{{/if}}
</div>
</div>
{{/if}}
<div id="beatContainer" class="col-sm-4 col-xs-12">
{{#if speakerViewed}}
<div id="beatSpeaker">
<img src="assets/images/speaker-outer.png"/>
<div id="beatSpeakerCenter">
<img src="assets/images/speaker-inner.png" class="cursorPointer" {{action "clickSpeaker"}} />
</div>
</div>
{{else}}
<div id="beatHistory">
{{#each beatHistory as |item|}}
<p>{{{item}}}</p>
{{/each}}
</div>
{{/if}}
{{#paper-switch checked=speakerViewed}} {{speakerLabel}} {{/paper-switch}}
</div>
</div>
{{/if}}
{{ember-notify closeAfter=5000}}

View file

@ -1,5 +1,6 @@
@import 'ember-paper';
@import 'bower_components/bootstrap-sass/assets/stylesheets/_bootstrap';
@import "bower_components/font-awesome/scss/font-awesome";
@import 'ember-modal-dialog/ember-modal-structure';
@import 'ember-modal-dialog/ember-modal-appearance';
@ -136,7 +137,7 @@ md-progress-linear {
text-align: left;
}
// BRIDGE CONTROLS
// HUE CONTROLS
#appSettings {
position: absolute;
background: white;
@ -392,16 +393,21 @@ md-toolbar {
text-shadow: none;
}
// MUSIC CONTROL
// MUSIC TAB
.row {
margin: 0;
}
.#{$fa-css-prefix}-youtubeWorkaround:before {
content: $fa-var-youtube-play;
font-size: 22px;
}
#slideToggle {
color: $playerDefaultIconColor;
background-color: $playerBottomBackground;
div md-icon {
font-size: 40px;
div i {
font-size: 25px;
color: inherit !important;
}
}
@ -447,13 +453,19 @@ md-switch.md-default-theme.md-checked .md-thumb {
}
.playerControllIcon {
cursor: pointer;
color: $playerDefaultIconColor !important;
transition-duration: 0.1s;
margin-right: 0.208em;
margin-right: 10px;
}
i.playerControllIcon {
font-size: 20px;
margin-right: 12px;
}
.playerControllIcon.active {
color: lighten($playerDefaultIconColor, 30%) !important;
color: #F12B24 !important;
}
.playerControllIcon:hover {
@ -579,7 +591,7 @@ md-switch.md-default-theme.md-checked .md-thumb {
border-bottom: 1px solid #3a3a3a;
}
#playListArea, #playAreaMic {
#playListArea, #playAreaMic, #playAreaYoutube {
background-color: lighten($playListBackgroundColor, 20%);
width: 100%;
height: 333px;
@ -609,6 +621,11 @@ md-switch.md-default-theme.md-checked .md-thumb {
}
}
.ember-notify-cn {
top: 0;
bottom: auto;
}
.songArtist {
font-style: italic;
}
@ -705,38 +722,6 @@ md-switch.md-default-theme.md-checked .md-thumb {
}
}
#beatSpeaker {
position: relative;
padding: 0 5%;
img {
width: 100%;
}
}
#beatSpeakerCenter {
position: absolute;
width: 100%;
top: 14%;
right: 0;
padding: 0 20%;
img {
width: 100%;
}
}
.pop {
animation-name: pop;
animation-duration: 0.1s;
animation-timing-function: linear;
animation-iteration-count: 1;
}
@keyframes pop {
50% {
transform: scale(1.1);
}
}
#beatArea .lightGroup {
margin: 10px 20px 0 40px;
float: right;
@ -783,3 +768,209 @@ md-switch.md-default-theme.md-checked .md-thumb {
display: table-cell;
}
}
// FANCY SPEAKER
/* Variables */
$centersize: 100px;
$center1size: 250px;
$bezelsize: 285px;
$vibratesize: $centersize*1.06;
$vibratemargin:-$vibratesize/2;
$vibrateblur: 2px;
$vibrateblur1:1px;
/* Extenders */
%base {
border-radius: 100%;
}
%rivet {
position: absolute;
height: 8px;
width: 8px;
background-color: #555;
border-radius: 100%;
box-shadow: inset 0 0 3px #000, 0 0 2px #000;
}
/* Keyframes */
@keyframes vibrate {
0% {
-webkit-filter: blur($vibrateblur);
filter: blur($vibrateblur);
height: $vibratesize;
width: $vibratesize;
margin-left: $vibratemargin;
margin-top: $vibratemargin;
}
30% {
-webkit-filter: blur(0);
filter: blur(0);
height: $centersize;
width: $centersize;
}
50% {
-webkit-filter: blur($vibrateblur);
filter: blur($vibrateblur);
height: $vibratesize;
width: $vibratesize;
margin-left: $vibratemargin;
margin-top: $vibratemargin;
}
65% {
-webkit-filter: blur(0);
filter: blur(0);
height: $centersize;
width: $centersize;
}
70% {
-webkit-filter: blur($vibrateblur);
filter: blur($vibrateblur);
height: $vibratesize;
width: $vibratesize;
margin-left: $vibratemargin;
margin-top: $vibratemargin;
}
80% {
-webkit-filter: blur($vibrateblur);
filter: blur($vibrateblur);
height: $centersize;
width: $centersize;
}
100% {
-webkit-filter: blur($vibrateblur);
filter: blur($vibrateblur);
height: $vibratesize;
width: $vibratesize;
margin-left: $vibratemargin;
margin-top: $vibratemargin;
}
}
@keyframes vibrate1 {
0% {
-webkit-filter: blur($vibrateblur1);
filter: blur($vibrateblur1);
border: 15px solid #333;
}
30% {
-webkit-filter: blur(0);
filter: blur(0);
border: 17px solid #333;
}
50% {
-webkit-filter: blur($vibrateblur1);
filter: blur($vibrateblur1);
border: 15px solid #333;
}
65% {
-webkit-filter: blur(0);
filter: blur(0);
border: 17px solid #333;
}
70% {
-webkit-filter: blur($vibrateblur1);
filter: blur($vibrateblur1);
border: 15px solid #333;
}
80% {
-webkit-filter: blur($vibrateblur1);
filter: blur($vibrateblur1);
border: 17px solid #333;
}
100% {
-webkit-filter: blur($vibrateblur1);
filter: blur($vibrateblur1);
border: 15px solid #333;
}
}
#beatSpeakerCenterInner {
@extend %base;
height: $centersize;
width: $centersize;
position: absolute;
bottom: 60px;
right: 60px;
-webkit-filter: blur(1px);
filter: blur(1px);
background: rgb(0,0,0);
background: -moz-radial-gradient(center, ellipse cover, rgba(0,0,0,1) 0%, rgba(79,79,79,1) 0%, rgba(0,0,0,1) 100%);
background: -webkit-gradient(radial, center center, 0px, center center, 100%, color-stop(0%,rgba(0,0,0,1)), color-stop(0%,rgba(79,79,79,1)), color-stop(100%,rgba(0,0,0,1)));
background: -webkit-radial-gradient(center, ellipse cover, rgba(0,0,0,1) 0%,rgba(79,79,79,1) 0%,rgba(0,0,0,1) 100%);
background: -o-radial-gradient(center, ellipse cover, rgba(0,0,0,1) 0%,rgba(79,79,79,1) 0%,rgba(0,0,0,1) 100%);
background: -ms-radial-gradient(center, ellipse cover, rgba(0,0,0,1) 0%,rgba(79,79,79,1) 0%,rgba(0,0,0,1) 100%);
background: radial-gradient(ellipse at center, rgba(0,0,0,1) 0%,rgba(79,79,79,1) 0%,rgba(0,0,0,1) 100%);
box-shadow: 0 0 10px rgba(0, 0, 0, 1);
}
.vibrateInner{
-webkit-animation: vibrate 0.25s linear 1;
animation: vibrate 0.1s linear 1;
}
#beatSpeakerCenterOuter {
@extend %base;
position: absolute;
top: 16px;
left: 16px;
height: $center1size;
width: $center1size;
border: 15px solid #333;
box-shadow: -3px -3px 15px rgba(0, 0, 0, 0.4), inset -3px -3px 15px rgba(0, 0, 0, 0.5);
background: -moz-linear-gradient(130deg, rgba(117, 117, 117, 1) 55%, rgba(220, 220, 220, 1) 100%);
background: -webkit-linear-gradient(130deg, rgba(117, 117, 117, 1) 55%, rgba(220, 220, 220, 1) 100%);
background: -o-linear-gradient(130deg, rgba(117, 117, 117, 1) 55%, rgba(220, 220, 220, 1) 100%);
background: -ms-linear-gradient(130deg, rgba(117, 117, 117, 1) 55%, rgba(220, 220, 220, 1) 100%);
background: linear-gradient(130deg, rgba(117, 117, 117, 1) 55%, rgba(220, 220, 220, 1) 100%);
}
.vibrateOuter {
-webkit-animation: vibrate1 0.25s linear 1;
animation: vibrate1 0.1s linear 1;
}
.bezel {
@extend %base;
margin: 0 auto;
height: $bezelsize;
width: $bezelsize;
position: relative;
background-color: #A8A8A8;
box-shadow: 0 0 60px rgba(0, 0, 0, 0.8), inset 3px 3px 10px rgba(0, 0, 0, 0.8), 0 0 2px rgba(0, 0, 0, 0.8), inset 0 0 30px -5px rgba(0, 0, 0, 0.8);
}
.rivet1 {
@extend %rivet;
top: 6px;
left: 50%;
}
.rivet2 {
@extend %rivet;
bottom: 6px;
left: 50%;
}
.rivet3 {
@extend %rivet;
top: 50%;
left: 6px;
}
.rivet4 {
@extend %rivet;
top: 50%;
right: 6px;
}
.rivet5 {
@extend %rivet;
top: 18%;
left: 13.7%;
}
.rivet6 {
@extend %rivet;
top: 18%;
right: 13.5%;
}
.rivet7 {
@extend %rivet;
bottom: 17%;
left: 13.5%;
}
.rivet8 {
@extend %rivet;
bottom: 17%;
right: 13.5%;
}

Binary file not shown.

Binary file not shown.

View file

@ -15,14 +15,16 @@
"jquery": "~2.1.4",
"jquery-mousewheel": "~3.1.13",
"loader.js": "ember-cli/loader.js#3.2.0",
"locallyjs": "~0.3.1",
"matchMedia": "~0.2.0",
"nouislider": "^8.0.1",
"qunit": "~1.18.0",
"three.js": "~0.71.0"
"three.js": "~0.71.0",
"font-awesome": "~4.4.0"
},
"resolutions": {
"ember": "~2.0.2",
"jquery": "~2.1.4"
"jquery": "~2.1.4",
"ember-qunit": "0.4.9",
"qunit": "~1.18.0"
}
}

View file

@ -3,7 +3,9 @@ var EmberApp = require('ember-cli/lib/broccoli/ember-app');
module.exports = function(defaults) {
var app = new EmberApp(defaults, {
// Add options here
emberCliFontAwesome: {
useScss: true
}
});
app.import('vendor/dancer.js');
@ -11,7 +13,6 @@ module.exports = function(defaults) {
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');
// Use `app.import` to add additional libraries to the generated
// output files.

View file

@ -25,6 +25,7 @@
"ember-cli-babel": "^5.0.0",
"ember-cli-content-security-policy": "0.4.0",
"ember-cli-dependency-checker": "^1.0.0",
"ember-cli-font-awesome": "0.1.1",
"ember-cli-htmlbars": "1.0.0",
"ember-cli-htmlbars-inline-precompile": "^0.3.0",
"ember-cli-ic-ajax": "0.2.1",
@ -40,6 +41,7 @@
"ember-disable-proxy-controllers": "^1.0.0",
"ember-export-application-global": "^1.0.3",
"ember-modal-dialog": "0.8.1",
"ember-notify": "^4.0.1",
"ember-paper": "0.2.8",
"ember-truth-helpers": "1.1.0"
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 48 KiB