This commit is contained in:
Egor 2015-09-21 00:19:10 -07:00
parent 910c921e83
commit 1aa94094ab
15 changed files with 205 additions and 144 deletions

View file

@ -22,3 +22,4 @@ Music awesomeness for hue lights.
- integration with youtube, soundcloud, spotify ???
- auto beat detection mode
- lights on/off switch

View file

@ -29,7 +29,7 @@ export default Em.Component.extend({
// automatically close the group menu when the user clicks somewhere else
click: function() {
if(this.get('groupControlDisplayed') && !event.target.classList.contains('menu') && !$(event.target).closest('#groupControls').length) {
if(this.get('groupControlDisplayed') && !event.target.classList.contains('group') && !$(event.target).closest('#groupControls').length) {
this.toggleProperty('groupControlDisplayed');
}
},

View file

@ -3,23 +3,26 @@ import Em from 'ember';
export default Em.Component.extend({
classNames: ['innerControlFrame'],
classNameBindings: ['active::hidden'],
elementId: 'lightControl',
activeLights: [],
lightsData: null,
lightsDataIntervalHandle: null,
modalData: null,
isShowingLightsModal: false,
isShowingAddGroupsModal: false,
actions: {
clickLight: function(id, data){
if(this.get('isShowingLightsModal')){
this.set('modalData', {data:data, id:id});
}
this.toggleProperty('isShowingLightsModal');
}
didInsertElement: function(){
// handle color changes
var self = this;
Em.$('.color').colorPicker({
opacity: false,
renderCallback: function(elem){
console.log(elem[0].value);
}
});
},
// determines whether the lights are on/off for the lights switch
@ -35,6 +38,18 @@ export default Em.Component.extend({
});
}.property('lightsData', 'activeLights', 'strobeOn'),
// color of the lights in the group
color: function(){
var lightsData = this.get('lightsData'),
color = [0,0,0];
if(this.get('strobeOn') || this.get('activeLights').length === 0){
return color;
}
return [lightsData[0].state.hue, lightsData[0].state.sat, lightsData[0].state.bri];
}.property('lightsData', 'activeLights', 'strobeOn'),
// determines the average brightness of the hue system for the brightness slider
lightsBrightness: function(){
var lightsData = this.get('lightsData'), activeLights = this.get('activeLights'), lightsBrightness = 0;

View file

@ -12,7 +12,7 @@ export default Em.Component.extend(musicControlMixin, {
audio.src = this.get('playQueue')[index].url;
if(dancer.audio) {
this.send('clearCurrentAudio');
this.clearCurrentAudio(true);
}
dancer.load(audio);
@ -24,22 +24,9 @@ export default Em.Component.extend(musicControlMixin, {
this.send('play');
}
},
clearCurrentAudio: function() {
var dancer = this.get('dancer');
dancer.pause();
clearInterval(this.get('incrementElapseTimeHandle'));
this.setProperties({
playQueuePointer: -1,
timeElapsed: 0,
timeTotal: 0,
playing: false
});
},
removeAudio: function(index){
if(index === this.get('playQueuePointer')) {
this.send('clearCurrentAudio');
this.clearCurrentAudio(true);
}
this.get('playQueue').removeAt(index);
@ -94,9 +81,13 @@ export default Em.Component.extend(musicControlMixin, {
},
next: function () {
var playQueuePointer = this.get('playQueuePointer'), playQueueLength = this.get('playQueue.length');
var nextSong = (playQueuePointer + 1) % playQueueLength;
var nextSong = (playQueuePointer + 1);
this.send('goToSong', nextSong);
if(nextSong > playQueueLength-1 && this.get('repeat') === 1){
nextSong = nextSong % playQueueLength;
this.send('goToSong', nextSong);
}
},
previous: function () {
if(this.get('timeElapsed') > 5) {
@ -112,13 +103,15 @@ export default Em.Component.extend(musicControlMixin, {
this.send('goToSong', nextSong);
}
},
fullscreen: function () {
},
fullscreen: function () {},
seekChanged: function (position) {
var audioPosition = Math.floor(this.get('timeTotal') * position / 100);
this.get('dancer').source.currentTime = audioPosition;
this.set('timeElapsed', audioPosition);
var dancer = this.get('dancer');
if(dancer.audio){
var audioPosition = Math.floor(this.get('timeTotal') * position / 100);
dancer.audio.currentTime = audioPosition;
this.set('timeElapsed', audioPosition);
}
},
volumeMutedChanged: function (value) {
var dancer = this.get('dancer'),
@ -205,7 +198,33 @@ export default Em.Component.extend(musicControlMixin, {
}
},
dragLeaveTimeoutHandle: null,
clearCurrentAudio: function(resetPointer) {
var dancer = this.get('dancer');
dancer.pause();
clearInterval(this.get('incrementElapseTimeHandle'));
if(resetPointer){
this.set('playQueuePointer', -1);
}
this.setProperties({
timeElapsed: 0,
timeTotal: 0,
playing: false
});
},
goToNextSong: function() {
this.get('beatHistory').clear();
if(this.get('repeat') === 2){
this.send('goToSong', this.get('playQueuePointer'));
} else {
this.get('timeElapsed')
this.send('next');
}
},
dragOver: function() {
var dragLeaveTimeoutHandle = this.get('dragLeaveTimeoutHandle');
@ -222,17 +241,6 @@ export default Em.Component.extend(musicControlMixin, {
this.set('dragLeaveTimeoutHandle', setTimeout(function(){ self.set('dragging', false); }, 500));
},
changePlayerControl: function(name, value, isOption){
if(isOption){
var options = {};
options[name] = value;
this.get('kick').set(options);
}
this.set(name, value);
localStorage.setItem('huegasm.' + name, value);
},
init: function () {
this._super();

View file

@ -5,11 +5,11 @@ export default Em.Mixin.create({
beatOptions: {
threshold: {
range: {min: 0.1, max: 0.6},
range: {min: 0.1, max: 0.9},
defaultValue: 0.3,
pips: {
mode: 'positions',
values: [0,20,40,60,80,100],
values: [0,25,50,75,100],
density: 3,
format: {
to: function ( value ) {return value;},
@ -34,7 +34,7 @@ export default Em.Mixin.create({
frequency: {
range: {min: 0, max: 10},
step: 1,
defaultValue: [0,5],
defaultValue: [0,10],
pips: {
mode: 'values',
values: [0,2,4,6,8,10],
@ -61,6 +61,7 @@ export default Em.Mixin.create({
dragging: false,
draggingOverPlayListArea: false,
dragLeaveTimeoutHandle: null,
playQueueEmpty: Em.computed.empty('playQueue'),
playQueueNotEmpty: Em.computed.notEmpty('playQueue'),
@ -97,9 +98,23 @@ export default Em.Mixin.create({
}
}.property('speakerViewed'),
changePlayerControl: function(name, value, isOption){
if(isOption){
var options = {};
options[name] = value;
this.get('kick').set(options);
}
this.set(name, value);
localStorage.setItem('huegasm.' + name, value);
},
incrementElapseTimeHandle: null,
incrementElapseTime: function(){
this.incrementProperty('timeElapsed');
if(this.get('timeElapsed') > this.get('timeTotal')){
this.goToNextSong();
}
},
repeatIcon: function () {

View file

@ -1,9 +0,0 @@
import Em from 'ember';
export default Em.Component.extend({
actions: {
close: function(){
this.sendAction();
}
}
});

View file

@ -11,6 +11,12 @@ $playerDefaultIconColor: #BBBBBB;
$footerHeight: 40px;
// BRIDGE FINDER
* {
text-rendering: optimizeLegibility;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
html {
min-height: 100%;
height: auto;
@ -122,21 +128,40 @@ md-progress-linear {
padding: 0 10px 0 10px;
}
.navigationItem:hover{
text-decoration: underline;
}
.navigationItem.active {
font-weight: bold;
cursor: default;
}
.navigationItem.active:hover {
color: #000;
text-decoration: none;
.navigationItem:hover {
font-weight: bold;
}
.cp-color-picker{
z-index: 100;
}
#lightControl{
min-height: 500px;
}
.color {
width: 50px;
padding: 22px;
cursor: pointer;
font-size: 0;
margin-right: 20px;
}
// LIGHT GROUP
md-slider {
cursor: pointer;
}
md-slider.md-default-theme .md-thumb:after {
border-color: #F12B24;
background-color: #F12B24;
}
// LIGHT GROUP
.paper-sidenav {
overflow: visible;
}
@ -165,7 +190,7 @@ md-progress-linear {
.lightGroup {
margin: 0 auto 0 auto;
.tooltip.top {
margin-top: -10px;
margin-top: 8px;
}
}
@ -176,28 +201,35 @@ md-progress-linear {
}
.lightInactive {
cursor: pointer;
position: relative;
}
.lightInactive::before {
font-weight: bold;
position: absolute;
content: "X";
top: -20px;
left: 6px;
top: 0;
left: 15px;
font-size: 40px;
color: rgba(255, 0, 0, 0.37);
font-family: cursive;
}
.horizontalLightGroup {
.lightInactive::before {
top: -21px;
left: 6px;
}
.tooltip.top {
margin-top: -10px;
}
}
.lightUnreachable {
background-color: rgba(255, 0, 0, 0.7);
}
.lightActive img {
cursor: pointer;
transition-duration: 0.3s;
transition-property: transform;
box-shadow: 0 0 1px rgba(0, 0, 0, 0);
@ -215,7 +247,7 @@ md-icon {
color: rgba(0, 0, 0, 0.54) !important;
}
md-icon.menu {
md-icon.group {
margin: 30px 0 0 16px;
}
@ -240,10 +272,6 @@ md-toolbar {
background-color: inherit !important;
}
//.innerControlFrame {
// height: 100vh;
//}
// GROUP CONTROL
.groupRow.selectedRow {
background-color: #7F7F7F !important;
@ -296,6 +324,13 @@ md-toolbar {
}
// MUSIC CONTROL
md-switch.md-default-theme.md-checked .md-bar {
background-color: rgba(241, 43, 36, 0.5);
}
md-switch.md-default-theme.md-checked .md-thumb{
background-color: #F12B24;
}
#playerControls {
opacity: 0;
transition: all 0.2s ease-in-out;
@ -500,7 +535,6 @@ md-toolbar {
}
.playlistItem {
border-bottom: 1px solid #9E9E9E;
height: 45px;
font-family: 'Open Sans', sans-serif;
padding: 5px;
@ -541,16 +575,20 @@ md-toolbar {
#beatArea * .noUi-vertical {
height: 170px;
margin-top: 20px;
margin-bottom: 5px;
margin-bottom: 15px;
}
.beatOption {
display: inline-block;
margin-right: 2em;
#beatOptionGroup {
margin-top: 20px;
.beatOption {
display: inline-block;
margin-right: 2em;
}
}
#playerBottom {
background-color: grey;
color: white;
background-color: #5D5D5D;
}
#beatSpeakerContainer {
@ -567,27 +605,35 @@ md-toolbar {
#beatSpeaker {
position: relative;
margin: 20px auto 0 auto;
margin: 10px auto 0 auto;
border-radius: 50%;
width: 280px;
height: 280px;
background-image: url('images/speaker-outer.png');
width: 284px;
height: 283px;
//border: 1px solid white;
//background: black;
#beatSpeakerCenter {
width: 188px;
height: 186px;
position: absolute;
top: 17%;
left: 17%;
border-radius: 50%;
//border: 3px solid brown;
//background: orange;
background-image: url('images/speaker-inner.png');
position: absolute;
top: 16%;
left: 18%;
}
#beatSpeakerCenterBackground {
width: 188px;
height: 186px;
background-color: black;
position: absolute;
top: 16%;
left: 18%;
z-index: -1;
}
//#beatSpeakerCenter::before {
// position: absolute;
// top: 28%;
// left: 28%;
// width: 80px;
// height: 80px;
// content: '';
// background-color: black;
// border: 1px solid white;
// border-radius: 50%;
//}
}
.pop {
@ -603,7 +649,12 @@ md-toolbar {
}
}
#beatArea .lightGroup {
margin: 10px 0 0 40px;
margin: 10px 50px 0 40px;
float: right;
span {
display: block;
padding: 10px;
}
}
#playerButtonGroup {
@ -621,7 +672,7 @@ md-toolbar {
#beatHistory {
height: 250px;
background-color: #CFCFCF;
background-color: white;
border-radius: 10px;
width: 80%;
margin: 20px auto;

View file

@ -1,6 +1,6 @@
{{#if ready}}
<span {{action "toggleGroupControl"}} id="groupControlToggle" class={{if groupControlDisplayed 'on'}}>
{{paper-icon icon="menu"}}
{{paper-icon icon="group"}}
</span>
{{controls/group-control lightsData=lightsData groupsData=groupsData activeLights=activeLights apiURL=apiURL updateGroupsData=updateGroupsData groupControlDisplayed=groupControlDisplayed}}

View file

@ -1,6 +1,6 @@
{{#paper-list}}
{{#paper-item class="item"}}
{{light-group lightsData=lightsData activeLights=activeLights action='clickLight' apiURL=apiURL}}
{{light-group lightsData=lightsData activeLights=activeLights action='clickLight' apiURL=apiURL classNames="horizontalLightGroup"}}
{{/paper-item}}
{{#paper-item class="item"}}
@ -15,11 +15,15 @@
{{paper-slider flex=true min='1' max='254' value=lightsBrightness disabled=brightnessControlDisabled}}
{{/paper-item}}
{{#paper-item class="item"}}
{{paper-icon icon="color-lens"}}
<p>Color</p>
<input class="color" value="rgb(0, 0, 0)" />
{{/paper-item}}
{{#paper-item class="item"}}
{{paper-icon icon="flare"}}
<p>Strobe</p>
{{#paper-switch checked=strobeOn disabled=trial}} {{strobeOnTxt}} {{/paper-switch}}
{{/paper-item}}
{{modals/light-control-modal modalData=modalData apiURL=apiURL action="clickLight" isShowingLightsModal=isShowingLightsModal}}
{{/paper-list}}

View file

@ -58,13 +58,12 @@
</div>
</div>
<div id="playerBottom" class="row">
<span id="beatArea" class="col-xs-7">
<span id="beatArea" class="col-xs-8">
<div id="vertDivider"></div>
{{light-group lightsData=lightsData activeLights=activeLights action='clickLight' apiURL=apiURL noHover=true}}
<span id="beatOptionGroup">
<div id="beatOptionGroup">
<span class="beatOption">
{{range-slider start=threshold orientation="vertical" range=beatOptions.threshold.range slide="thresholdChanged" pips=beatOptions.threshold.pips}}
Max. Beat Intensity
@ -79,14 +78,14 @@
{{range-slider start=frequency orientation="vertical" step=beatOptions.frequency.step range=beatOptions.frequency.range connect=true slide="frequencyChanged" pips=beatOptions.frequency.pips}}
Beat Frequency Range
</span>
</span>
</div>
<div id="playerButtonGroup">
{{#paper-button raised=true warn=true action="defaultControls"}}Default{{/paper-button}}
</div>
</span>
<span id="beatSpeakerContainer" class="col-xs-5">
<span id="beatSpeakerContainer" class="col-xs-4">
{{#paper-switch checked=speakerViewed noink=true}} {{speakerLabel}} {{/paper-switch}}
{{#liquid-if speakerViewed}}
<div id="beatSpeaker">

View file

@ -1,8 +0,0 @@
{{#if isShowingLightsModal}}
{{#modal-dialog close="close"
alignment="center"
translucentOverlay=true}}
TODO
<button {{action 'close'}}>Close</button>
{{/modal-dialog}}
{{/if}}

View file

@ -2,6 +2,7 @@
"name": "huegasm",
"dependencies": {
"bootstrap-sass": "~3.3.5",
"colorspaces.js": "https://github.com/boronine/colorspaces.js.git#~0.1.4",
"ember": "~2.0.2",
"ember-cli-shims": "ember-cli/ember-cli-shims#0.0.3",
"ember-cli-test-loader": "ember-cli-test-loader#0.1.3",
@ -11,12 +12,14 @@
"ember-qunit-notifications": "0.0.7",
"ember-resolver": "~0.1.18",
"hammerjs": "~2.0.4",
"hue-color-converter": "https://github.com/Q42/hue-color-converter",
"JavaScript-ID3-Reader": "https://github.com/aadsm/JavaScript-ID3-Reader.git",
"jquery": "~2.1.4",
"jquery-mousewheel": "~3.1.13",
"loader.js": "ember-cli/loader.js#3.2.0",
"nouislider": "^8.0.1",
"qunit": "~1.18.0"
"qunit": "~1.18.0",
"tinyColorPicker": "https://github.com/PitPik/tinyColorPicker.git"
},
"resolutions": {
"ember": "~2.0.2",

View file

@ -10,6 +10,9 @@ module.exports = function(defaults) {
app.import('bower_components/bootstrap-sass/assets/javascripts/bootstrap/tooltip.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/tinyColorPicker/colors.js');
app.import('bower_components/tinyColorPicker/jqColorPicker.js');
app.import('bower_components/colorspaces.js/colorspaces.js');
// Use `app.import` to add additional libraries to the generated
// output files.

View file

@ -1,26 +0,0 @@
import { moduleForComponent, test } from 'ember-qunit';
import hbs from 'htmlbars-inline-precompile';
moduleForComponent('modals/light-control-modal', 'Integration | Component | modals/light control modal', {
integration: true
});
test('it renders', function(assert) {
assert.expect(2);
// Set any properties with this.set('myProperty', 'value');
// Handle any actions with this.on('myAction', function(val) { ... });
this.render(hbs`{{modals/light-control-modal}}`);
assert.equal(this.$().text().trim(), '');
// Template block usage:
this.render(hbs`
{{#modals/light-control-modal}}
template block text
{{/modals/light-control-modal}}
`);
assert.equal(this.$().text().trim(), 'template block text');
});

7
vendor/dancer.js vendored
View file

@ -476,7 +476,12 @@
};
function connectContext () {
this.source = this.context.createMediaElementSource( this.audio );
try{
this.source = this.context.createMediaElementSource( this.audio );
} catch(err){
return;
}
this.source.connect( this.proc );
this.source.connect( this.gain );
//this.source.connect( this.filter );