styling changes, WIP chrome extension
This commit is contained in:
parent
49e19df1d1
commit
e73518552a
31 changed files with 1372 additions and 1331 deletions
|
|
@ -10,7 +10,7 @@
|
|||
<meta name="author" content="Egor Philippov">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1"> {{content-for 'head'}}
|
||||
|
||||
<link href='//fonts.googleapis.com/css?family=Slabo+27px|Open+Sans' rel='stylesheet' type='text/css'>
|
||||
<link href='https://fonts.googleapis.com/css?family=Open+Sans|Raleway' rel='stylesheet' type='text/css'>
|
||||
|
||||
<link rel="stylesheet" integrity="" href="{{rootURL}}assets/vendor.css">
|
||||
<link rel="stylesheet" integrity="" href="{{rootURL}}assets/huegasm.css"> {{content-for 'head-footer'}}
|
||||
|
|
|
|||
|
|
@ -59,23 +59,25 @@ export default Component.extend({
|
|||
.done((result, status) => {
|
||||
let bridgeFindStatus = 'fail';
|
||||
|
||||
if (status === 'success' && result.length === 1) {
|
||||
this.set('bridgeIp', result[0].internalipaddress);
|
||||
chrome.storage.local.set({ 'bridgeIp': result[0].internalipaddress });
|
||||
bridgeFindStatus = 'success';
|
||||
} else if (result.length > 1) {
|
||||
let multipleBridgeIps = this.get('multipleBridgeIps');
|
||||
if (!this.isDestroyed) {
|
||||
if (status === 'success' && result.length === 1) {
|
||||
this.set('bridgeIp', result[0].internalipaddress);
|
||||
chrome.storage.local.set({ 'bridgeIp': result[0].internalipaddress });
|
||||
bridgeFindStatus = 'success';
|
||||
} else if (result.length > 1) {
|
||||
let multipleBridgeIps = this.get('multipleBridgeIps');
|
||||
|
||||
result.forEach(function (item) {
|
||||
multipleBridgeIps.pushObject(item.internalipaddress);
|
||||
});
|
||||
result.forEach(function (item) {
|
||||
multipleBridgeIps.pushObject(item.internalipaddress);
|
||||
});
|
||||
|
||||
bridgeFindStatus = 'multiple';
|
||||
} else {
|
||||
bridgeFindStatus = 'fail';
|
||||
bridgeFindStatus = 'multiple';
|
||||
} else {
|
||||
bridgeFindStatus = 'fail';
|
||||
}
|
||||
|
||||
this.set('bridgeFindStatus', bridgeFindStatus);
|
||||
}
|
||||
|
||||
this.set('bridgeFindStatus', bridgeFindStatus);
|
||||
})
|
||||
.fail(() => {
|
||||
this.set('bridgeFindStatus', 'fail');
|
||||
|
|
@ -99,7 +101,6 @@ export default Component.extend({
|
|||
|
||||
if (status === 'success' && !result[0].error) {
|
||||
this.clearBridgePingIntervalHandle();
|
||||
debugger;
|
||||
chrome.storage.local.set({ 'bridgeUsername': result[0].success.username });
|
||||
this.set('bridgeUsername', result[0].success.username);
|
||||
}
|
||||
|
|
@ -114,7 +115,9 @@ export default Component.extend({
|
|||
|
||||
clearBridgePingIntervalHandle() {
|
||||
clearInterval(this.get('bridgePingIntervalHandle'));
|
||||
this.set('bridgePingIntervalHandle', null);
|
||||
if (!this.isDestroyed) {
|
||||
this.set('bridgePingIntervalHandle', null);
|
||||
}
|
||||
},
|
||||
|
||||
actions: {
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
{{#if isAuthenticating}}
|
||||
<p>
|
||||
Your bridge IP is <b>{{bridgeIp}}</b>
|
||||
<br> Press the button on your bridge to authenticate this application.
|
||||
<br> Press the button on your bridge to authenticate Huegasm.
|
||||
</p>
|
||||
{{else}}
|
||||
<p>You failed to press the button in time. <a class="no-text-decoration" href="#" {{action 'retry'}}>RETRY</a></p>
|
||||
|
|
@ -18,7 +18,7 @@
|
|||
{{/unless}}
|
||||
|
||||
{{#if bridgeFindMultiple}}
|
||||
<p>Huegasm found multiple hue bridges. <br> Please select the one you want to use for this application.</p>
|
||||
<p>Huegasm found multiple hue bridges. <br> Please select the one you want to use for Huegasm.</p>
|
||||
|
||||
<div id="bridge-button-group">
|
||||
{{#each multipleBridgeIps as |bridge|}}
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ const {
|
|||
isNone,
|
||||
$,
|
||||
inject: { service },
|
||||
run: { later, next }
|
||||
run: { later, next, once }
|
||||
} = Ember;
|
||||
|
||||
export default Component.extend({
|
||||
|
|
@ -16,8 +16,6 @@ export default Component.extend({
|
|||
classNameBindings: ['active::hidden'],
|
||||
elementId: 'music-tab',
|
||||
|
||||
dancer: null,
|
||||
|
||||
notify: service(),
|
||||
|
||||
beatOptions: {
|
||||
|
|
@ -32,11 +30,11 @@ export default Component.extend({
|
|||
format: {
|
||||
to: function (value) {
|
||||
if (value === 0) {
|
||||
value = 'More';
|
||||
value = 'High';
|
||||
} else if (value === 0.25) {
|
||||
value = '';
|
||||
} else {
|
||||
value = 'Less';
|
||||
value = 'Low';
|
||||
}
|
||||
|
||||
return value;
|
||||
|
|
@ -75,10 +73,22 @@ export default Component.extend({
|
|||
defaultValue: 0,
|
||||
pips: {
|
||||
mode: 'values',
|
||||
values: [1, 50, 100, 150, 200, 254],
|
||||
values: [1, 63, 127, 190, 254],
|
||||
density: 10,
|
||||
format: {
|
||||
to: function (value) { return value; },
|
||||
to: function (value) {
|
||||
if (value === 63) {
|
||||
value = 25;
|
||||
} else if (value === 127) {
|
||||
value = 50;
|
||||
} else if (value === 190) {
|
||||
value = 75;
|
||||
} else if (value === 254) {
|
||||
value = 100;
|
||||
}
|
||||
|
||||
return value;
|
||||
},
|
||||
from: function (value) { return value; }
|
||||
}
|
||||
}
|
||||
|
|
@ -88,46 +98,48 @@ export default Component.extend({
|
|||
threshold: 0.3,
|
||||
hueRange: [0, 65535],
|
||||
brightnessRange: [1, 254],
|
||||
oldThreshold: null,
|
||||
|
||||
lastLightBopIndex: 0,
|
||||
|
||||
playerBottomDisplayed: true,
|
||||
audioStream: null,
|
||||
dimmerOn: false,
|
||||
|
||||
colorloopMode: false,
|
||||
flashingTransitions: false,
|
||||
|
||||
// 0 - no repeat, 1 - repeat all, 2 - repeat one
|
||||
repeat: 0,
|
||||
shuffle: false,
|
||||
volumeMuted: false,
|
||||
volume: 100,
|
||||
// beat detection related pausing
|
||||
paused: false,
|
||||
songBeatPreferences: {},
|
||||
usingBeatPreferences: false,
|
||||
oldBeatPrefCache: null,
|
||||
firstVisit: true,
|
||||
isListenining: false,
|
||||
|
||||
// noUiSlider connection specification
|
||||
filledConnect: [true, false],
|
||||
hueRangeConnect: [false, true, false],
|
||||
|
||||
changePlayerControl(name, value) {
|
||||
this.set(name, value);
|
||||
onConfigItemChanged: observer('threshold', 'flashingTransitions', 'colorloopMode', 'hueRange', 'brightnessRange', 'isListenining', function (wtf, name) {
|
||||
once(this, () => {
|
||||
let value = this.get(name),
|
||||
self = this;
|
||||
|
||||
if (name === 'threshold') {
|
||||
this.get('kick').set({ threshold: value });
|
||||
}
|
||||
this.set(name, value);
|
||||
|
||||
let toSave = {};
|
||||
toSave[name] = value;
|
||||
chrome.storage.local.set(toSave);
|
||||
},
|
||||
if (name === 'isListenining' && value) {
|
||||
chrome.runtime.sendMessage({ action: 'start-listening' }, function (response) {
|
||||
if (response && response.error) {
|
||||
self.get('notify').warning({ html: '<div class="alert alert-warning" role="alert">' + response.error + '</div>' });
|
||||
|
||||
self.set('isListenining', false);
|
||||
chrome.storage.local.set({ isListenining: false });
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
let toSave = {};
|
||||
toSave[name] = value;
|
||||
chrome.storage.local.set(toSave);
|
||||
});
|
||||
}),
|
||||
|
||||
simulateKick() {
|
||||
this.speakerBump();
|
||||
|
||||
simulateKick(/*mag, ratioKickMag*/) {
|
||||
let activeLights = this.get('activeLights'),
|
||||
lightsData = this.get('lightsData'),
|
||||
color = null,
|
||||
|
|
@ -194,8 +206,9 @@ export default Component.extend({
|
|||
later(this, function () {
|
||||
this.set('paused', false);
|
||||
}, 150);
|
||||
},
|
||||
|
||||
//work the music beat area - simulate the speaker vibration by running a CSS animation on it
|
||||
speakerBump() {
|
||||
$('#beat-speaker-center-outer').velocity({ blur: 3 }, 100).velocity({ blur: 0 }, 100);
|
||||
$('#beat-speaker-center-inner').velocity({ scale: 1.05 }, 100).velocity({ scale: 1 }, 100);
|
||||
},
|
||||
|
|
@ -203,76 +216,59 @@ export default Component.extend({
|
|||
init() {
|
||||
this._super(...arguments);
|
||||
|
||||
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;
|
||||
|
||||
let dancer = new Dancer(),
|
||||
kick = dancer.createKick({
|
||||
threshold: this.get('threshold'),
|
||||
onKick: (mag, ratioKickMag) => {
|
||||
if (this.get('paused') === false) {
|
||||
this.simulateKick(mag, ratioKickMag);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
kick.on();
|
||||
|
||||
this.setProperties({
|
||||
dancer: dancer,
|
||||
kick: kick
|
||||
chrome.storage.local.get('threshold', ({threshold}) => {
|
||||
if (!isNone(threshold)) {
|
||||
this.set('threshold', threshold);
|
||||
}
|
||||
});
|
||||
|
||||
['threshold', 'playerBottomDisplayed', 'flashingTransitions', 'colorloopMode', 'hueRange', 'brightnessRange'].forEach((item) => {
|
||||
chrome.storage.local.get(item, ({itemVal}) => {
|
||||
if (!isNone(itemVal)) {
|
||||
if (isNone(this.actions[item + 'Changed'])) {
|
||||
this.set(item, itemVal);
|
||||
} else {
|
||||
this.send(item + 'Changed', itemVal);
|
||||
}
|
||||
}
|
||||
});
|
||||
chrome.storage.local.get('flashingTransitions', ({flashingTransitions}) => {
|
||||
if (!isNone(flashingTransitions)) {
|
||||
this.set('flashingTransitions', flashingTransitions);
|
||||
}
|
||||
});
|
||||
|
||||
chrome.storage.local.get('colorloopMode', ({colorloopMode}) => {
|
||||
if (!isNone(colorloopMode)) {
|
||||
this.set('colorloopMode', colorloopMode);
|
||||
}
|
||||
});
|
||||
|
||||
chrome.storage.local.get('hueRange', ({hueRange}) => {
|
||||
if (!isNone(hueRange)) {
|
||||
this.set('hueRange', hueRange);
|
||||
}
|
||||
});
|
||||
|
||||
chrome.storage.local.get('brightnessRange', ({brightnessRange}) => {
|
||||
if (!isNone(brightnessRange)) {
|
||||
this.set('brightnessRange', brightnessRange);
|
||||
}
|
||||
});
|
||||
|
||||
chrome.storage.local.get('isListenining', ({isListenining}) => {
|
||||
if (!isNone(isListenining)) {
|
||||
this.set('isListenining', isListenining);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
didInsertElement() {
|
||||
this._super();
|
||||
|
||||
let self = this;
|
||||
|
||||
// prevent space/text selection when the user repeatedly clicks on the center
|
||||
$('#beat-container').on('mousedown', '#beat-speaker-center-inner', function (event) {
|
||||
event.preventDefault();
|
||||
});
|
||||
|
||||
if (!this.get('playerBottomDisplayed')) {
|
||||
$('#player-bottom').hide();
|
||||
}
|
||||
},
|
||||
|
||||
actions: {
|
||||
slideTogglePlayerBottom() {
|
||||
let elem = this.$('#player-bottom');
|
||||
|
||||
elem.velocity(elem.is(':visible') ? 'slideUp' : 'slideDown', { duration: 300 });
|
||||
this.changePlayerControl('playerBottomDisplayed', !this.get('playerBottomDisplayed'));
|
||||
},
|
||||
playerBottomDisplayedChanged(value) {
|
||||
this.changePlayerControl('playerBottomDisplayed', value);
|
||||
},
|
||||
thresholdChanged(value) {
|
||||
this.changePlayerControl('threshold', value, true);
|
||||
},
|
||||
brightnessRangeChanged(value) {
|
||||
this.changePlayerControl('brightnessRange', value);
|
||||
},
|
||||
hueRangeChanged(value) {
|
||||
this.changePlayerControl('hueRange', value);
|
||||
toggleListening() {
|
||||
this.toggleProperty('isListenining');
|
||||
},
|
||||
clickSpeaker() {
|
||||
this.simulateKick(1);
|
||||
this.simulateKick();
|
||||
},
|
||||
hideTooltip() {
|
||||
$('.bootstrap-tooltip').tooltip('hide');
|
||||
},
|
||||
toggleDimmer() {
|
||||
this.sendAction('toggleDimmer');
|
||||
|
|
|
|||
|
|
@ -1,10 +1,8 @@
|
|||
<div id="slide-toggle" class="text-center pointer row" {{action "slideTogglePlayerBottom"}}>
|
||||
<div class="col-xs-offset-5 col-xs-2">
|
||||
{{paper-icon beatDetectionAreaArrowIcon id="beat-detection-area-arrow-icon"}}
|
||||
</div>
|
||||
<div id="fancy-button-wrapper">
|
||||
<a href="#" class="fancy-button note {{if isListenining "active"}}" {{action "toggleListening"}}></a>
|
||||
</div>
|
||||
|
||||
<div id="player-bottom" class="row {{if dimmerOn "dimmerOn"}} {{if playerBottomDisplayed "display-flex"}}">
|
||||
<div class="row {{if dimmerOn "dimmerOn"}}">
|
||||
<div id="beat-area" class="col-sm-7 col-xs-12">
|
||||
<div class="row" id="beat-option-row">
|
||||
<div class="beat-option col-xs-4">
|
||||
|
|
@ -14,7 +12,7 @@
|
|||
</span>
|
||||
|
||||
{{range-slider start=hueRange orientation="vertical" step=beatOptions.hueRange.step range=beatOptions.hueRange.range connect=hueRangeConnect
|
||||
on-change="hueRangeChanged" pips=beatOptions.hueRange.pips}}
|
||||
on-change=(action (mut hueRange)) pips=beatOptions.hueRange.pips}}
|
||||
</div>
|
||||
|
||||
<div class="beat-option col-xs-4">
|
||||
|
|
@ -24,7 +22,7 @@
|
|||
</span>
|
||||
|
||||
{{range-slider start=brightnessRange orientation="vertical" step=beatOptions.brightnessRange.step range=beatOptions.brightnessRange.range
|
||||
on-change="brightnessRangeChanged" pips=beatOptions.brightnessRange.pips}}
|
||||
on-change=(action (mut brightnessRange)) pips=beatOptions.brightnessRange.pips}}
|
||||
</div>
|
||||
|
||||
<div id="sensitivity-settings" class="beat-option col-xs-4">
|
||||
|
|
@ -33,8 +31,8 @@
|
|||
Sensitivity
|
||||
</span>
|
||||
|
||||
{{range-slider start=threshold orientation="vertical" step=beatOptions.threshold.step range=beatOptions.threshold.range on-change="thresholdChanged"
|
||||
pips=beatOptions.threshold.pips}}
|
||||
{{range-slider start=threshold orientation="vertical" step=beatOptions.threshold.step range=beatOptions.threshold.range on-change=(action
|
||||
(mut threshold)) pips=beatOptions.threshold.pips}}
|
||||
</div>
|
||||
|
||||
<div id="light-option" class="col-xs-12">
|
||||
|
|
|
|||
|
|
@ -21,12 +21,11 @@ body {
|
|||
|
||||
body > .ember-view {
|
||||
display: flex;
|
||||
min-height: 100vh;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
body, button {
|
||||
font-family: 'Slabo 27px', serif;
|
||||
font-family: 'Raleway', sans-serif;
|
||||
}
|
||||
|
||||
#huegasm {
|
||||
|
|
|
|||
|
|
@ -31,7 +31,6 @@
|
|||
}
|
||||
|
||||
#bridge-finder {
|
||||
min-height: 500px;
|
||||
.md-bar {
|
||||
background-color: $secondaryThemeColor !important;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
#lights-tab {
|
||||
padding: 0;
|
||||
margin-top: 5vh;
|
||||
.paper-icon {
|
||||
line-height: 0.8 !important;
|
||||
}
|
||||
|
|
@ -19,7 +18,6 @@
|
|||
|
||||
#hue-controls {
|
||||
max-width: 1200px;
|
||||
height: 90vh;
|
||||
md-progress-circular {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
|
|
@ -35,7 +33,7 @@
|
|||
}
|
||||
|
||||
#navigation {
|
||||
padding: 15px 0 4vh;
|
||||
padding: 10px 0 2vh;
|
||||
text-align: center;
|
||||
margin: auto;
|
||||
position: relative;
|
||||
|
|
@ -44,13 +42,13 @@
|
|||
text-align: right;
|
||||
position: absolute;
|
||||
top: -10px;
|
||||
right: 10px;
|
||||
right: -10px;
|
||||
transform: scale(1.1);
|
||||
}
|
||||
}
|
||||
|
||||
.navigation-item {
|
||||
font-size: 18px;
|
||||
font-size: 20px;
|
||||
padding: 0 10px 0 10px;
|
||||
&.active {
|
||||
font-weight: bold;
|
||||
|
|
|
|||
|
|
@ -58,7 +58,7 @@
|
|||
.light-text {
|
||||
width: 60px;
|
||||
word-wrap: break-word;
|
||||
padding: 0 10px;
|
||||
padding: 0 7px;
|
||||
}
|
||||
|
||||
.light-text-content {
|
||||
|
|
|
|||
|
|
@ -8,87 +8,6 @@
|
|||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
#slide-toggle {
|
||||
font-size: 22px;
|
||||
color: $playerDefaultIconColor;
|
||||
background: #730B07;
|
||||
div .paper-icon {
|
||||
color: inherit !important;
|
||||
font-size: 24px;
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
|
||||
#slide-toggle:hover {
|
||||
color: lighten($playerDefaultIconColor, 30%) !important;
|
||||
}
|
||||
|
||||
|
||||
#player-area {
|
||||
height: $playerHeight;
|
||||
background-color: black;
|
||||
display: inline-block;
|
||||
padding: 0;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
#playlist {
|
||||
height: $playerHeight;
|
||||
background-color: #1E1E1E;
|
||||
padding: 0 5px 0 5px;
|
||||
}
|
||||
|
||||
#player-area * .noUi-origin {
|
||||
background-color: $blackish;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
#player-area * .noUi-base {
|
||||
background-color: $blackish;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
#volume-bar {
|
||||
width: 5em;
|
||||
height: 0.5em;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
#player-area * .noUi-handle::after,
|
||||
#player-area * .noUi-handle::before {
|
||||
content: none;
|
||||
}
|
||||
|
||||
#seek-slider {
|
||||
margin-bottom: 15px;
|
||||
transition-duration: 0.2s;
|
||||
height: 8px;
|
||||
.noUi-handle {
|
||||
opacity: 1 !important;
|
||||
}
|
||||
}
|
||||
|
||||
#seek-slider:hover {
|
||||
height: 8px;
|
||||
}
|
||||
|
||||
#seek-slider:hover * .noUi-handle {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
#seek-slider * .noUi-handle {
|
||||
border: none;
|
||||
height: 13px;
|
||||
width: 13px;
|
||||
border-radius: 50%;
|
||||
top: -4px;
|
||||
left: -6px;
|
||||
opacity: 0;
|
||||
transition-duration: 0.1s;
|
||||
background-color: $secondaryThemeColor !important;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
#beat-area {
|
||||
position: relative;
|
||||
padding: 0;
|
||||
|
|
@ -118,9 +37,10 @@
|
|||
}
|
||||
.option-description {
|
||||
display: inline-flex;
|
||||
font-size: 20px;
|
||||
font-size: 18px;
|
||||
justify-content: center;
|
||||
flex-direction: column;
|
||||
padding: 10px 0;
|
||||
}
|
||||
button {
|
||||
margin-top: 0;
|
||||
|
|
@ -155,65 +75,6 @@
|
|||
}
|
||||
}
|
||||
|
||||
#add-music-choices {
|
||||
min-width: initial;
|
||||
right: 0;
|
||||
left: initial;
|
||||
width: 100px;
|
||||
top: 25px;
|
||||
}
|
||||
|
||||
.add-new-music {
|
||||
padding: 0 5px 0 10px;
|
||||
font-size: 16px;
|
||||
border-radius: 5px;
|
||||
background: #f8f8f8;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.add-new-music:hover {
|
||||
background: darken(#f8f8f8, 5%);
|
||||
}
|
||||
|
||||
.sound-cloud-link {
|
||||
position: absolute;
|
||||
right: 55px;
|
||||
bottom: 22px;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#save-beat-preferences-star {
|
||||
position: absolute;
|
||||
top: 5px;
|
||||
left: 5px;
|
||||
z-index: 1000;
|
||||
md-icon {
|
||||
color: $secondaryThemeColor !important;
|
||||
font-size: 25px;
|
||||
cursor: default;
|
||||
}
|
||||
}
|
||||
|
||||
.visualizers-menu {
|
||||
left: -135px;
|
||||
}
|
||||
|
||||
.display-icon {
|
||||
background: url(images/huegasm.png) center center no-repeat;
|
||||
background-size: 80px 80px;
|
||||
}
|
||||
|
||||
.keyboard-arrow-down {
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
.visualizers-menu .paper-icon {
|
||||
margin-left: 10px;
|
||||
position: relative;
|
||||
top: -4px;
|
||||
}
|
||||
|
||||
.close {
|
||||
font-size: 18px !important;
|
||||
color: rgb(51, 51, 51);
|
||||
|
|
@ -224,36 +85,66 @@
|
|||
}
|
||||
}
|
||||
|
||||
.ember-notify-default.ember-notify-cn {
|
||||
top: 0;
|
||||
bottom: initial;
|
||||
#fancy-button-wrapper {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
#soundcloud-logo {
|
||||
display: block;
|
||||
}
|
||||
|
||||
#soundcloud-logo-small {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#soundcloud-tutorial {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
@media(max-width:1100px) {
|
||||
#soundcloud-logo {
|
||||
display: none;
|
||||
}
|
||||
#soundcloud-logo-small {
|
||||
.fancy-button {
|
||||
background-image: -webkit-linear-gradient(top, #f4f1ee, #fff);
|
||||
background-image: linear-gradient(top, #f4f1ee, #fff);
|
||||
border-radius: 50%;
|
||||
box-shadow: 0px 8px 10px 0px rgba(0, 0, 0, .3), inset 0px 4px 1px 1px white, inset 0px -3px 1px 1px rgba(204,198,197,.5);
|
||||
float:left;
|
||||
height: 90px;
|
||||
margin: 0 30px 30px 0;
|
||||
position: relative;
|
||||
width: 90px;
|
||||
-webkit-transition: all .1s linear;
|
||||
transition: all .1s linear;
|
||||
&:after {
|
||||
color:#e9e6e4;
|
||||
content: "";
|
||||
display: block;
|
||||
font-size: 50px;
|
||||
height: 30px;
|
||||
text-decoration: none;
|
||||
text-shadow: 0px -1px 1px #bdb5b4, 1px 1px 1px white;
|
||||
position: absolute;
|
||||
width: 30px;
|
||||
}
|
||||
&:hover {
|
||||
background-image: -webkit-linear-gradient(top, #fff, #f4f1ee);
|
||||
background-image: linear-gradient(top, #fff, #f4f1ee);
|
||||
color:#0088cc;
|
||||
}
|
||||
&:active {
|
||||
background-image: -webkit-linear-gradient(top, #efedec, #f7f4f4);
|
||||
background-image: linear-gradient(top, #efedec, #f7f4f4);
|
||||
box-shadow: 0 3px 5px 0 rgba(0,0,0,.4), inset 0px -3px 1px 1px rgba(204,198,197,.5);
|
||||
&:after{
|
||||
color:#dbd2d2;
|
||||
text-shadow: 0px -1px 1px #bdb5b4, 0px 1px 1px white;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.note {
|
||||
&.active:after {
|
||||
color: $secondaryThemeColor;
|
||||
}
|
||||
&:after{
|
||||
content: "♪";
|
||||
left: 32px;
|
||||
top: 14px;
|
||||
}
|
||||
&:hover:after {
|
||||
color: $secondaryThemeColor;
|
||||
text-shadow: 0px 0px 6px $secondaryThemeColor;
|
||||
}
|
||||
}
|
||||
|
||||
@media(min-width:767px) and (max-width:1200px) {
|
||||
#add-new-music-label {
|
||||
display: none;
|
||||
}
|
||||
#play-list-controls .paper-button {
|
||||
border: 1px solid $whitish;
|
||||
border-radius: 5px;
|
||||
|
|
@ -289,10 +180,6 @@
|
|||
.close {
|
||||
display: block;
|
||||
}
|
||||
#save-beat-preferences-star {
|
||||
right: 5px;
|
||||
left: initial;
|
||||
}
|
||||
md-checkbox {
|
||||
padding-right: 20px !important;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ md-checkbox .md-label {
|
|||
}
|
||||
|
||||
.md-button {
|
||||
font-size: 13px;
|
||||
flex-direction: unset;
|
||||
span {
|
||||
width: 100%;
|
||||
|
|
@ -62,7 +63,7 @@ md-switch.md-default-theme.md-checked .md-thumb {
|
|||
}
|
||||
|
||||
md-list-item {
|
||||
margin-bottom: 2vh;
|
||||
margin-bottom: 1vh;
|
||||
}
|
||||
|
||||
@media(max-width:500px) {
|
||||
|
|
|
|||
|
|
@ -14,8 +14,6 @@ module.exports = function (defaults) {
|
|||
destDir: '/fonts/bootstrap'
|
||||
});
|
||||
|
||||
app.import('vendor/dancer.js');
|
||||
|
||||
app.import('bower_components/bootstrap-sass/assets/javascripts/bootstrap/tooltip.js');
|
||||
app.import('bower_components/velocity/velocity.js');
|
||||
|
||||
|
|
|
|||
|
|
@ -1,11 +1,827 @@
|
|||
chrome.runtime.onMessage.addListener(function (request, sender, sendResponse) {
|
||||
if (request.action === 'start-listen') {
|
||||
chrome.tabCapture.capture({
|
||||
audio: true,
|
||||
video: false
|
||||
}, function (stream) {
|
||||
console.log('stream', stream);
|
||||
//I can attach all my filter here...
|
||||
});
|
||||
'use strict';
|
||||
|
||||
/*
|
||||
* dancer - v0.4.0 - 2014-02-01
|
||||
* https://github.com/jsantell/dancer.js
|
||||
* Copyright (c) 2014 Jordan Santell
|
||||
* Licensed MIT
|
||||
*/
|
||||
(function () {
|
||||
|
||||
var Dancer = function () {
|
||||
this.audioAdapter = Dancer._getAdapter(this);
|
||||
this.events = {};
|
||||
this.sections = [];
|
||||
this.bind('update', update);
|
||||
};
|
||||
|
||||
Dancer.version = 'X.X.X';
|
||||
Dancer.adapters = {};
|
||||
|
||||
Dancer.prototype = {
|
||||
|
||||
load: function (source, micBoost, useMic) {
|
||||
// Loading an Audio element
|
||||
if (source instanceof HTMLElement) {
|
||||
this.source = source;
|
||||
// Loading an object with src, [codecs]
|
||||
} else if (source instanceof EventTarget) {
|
||||
this.source = source;
|
||||
} else {
|
||||
this.source = window.Audio ? new Audio() : {};
|
||||
this.source.src = Dancer._makeSupportedPath(source.src, source.codecs);
|
||||
}
|
||||
|
||||
this.useMic = useMic === true;
|
||||
this.boost = micBoost ? micBoost : 1;
|
||||
this.audio = this.audioAdapter.load(this.source, this.useMic, this.boost);
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
/* Controls */
|
||||
play: function () {
|
||||
this.audioAdapter.play();
|
||||
return this;
|
||||
},
|
||||
|
||||
pause: function () {
|
||||
this.audioAdapter.pause();
|
||||
return this;
|
||||
},
|
||||
|
||||
setVolume: function (volume) {
|
||||
this.audioAdapter.setVolume(volume);
|
||||
return this;
|
||||
},
|
||||
|
||||
setBoost: function (boost) {
|
||||
this.audioAdapter.setBoost(boost);
|
||||
return this;
|
||||
},
|
||||
|
||||
/* Actions */
|
||||
createKick: function (options) {
|
||||
return new Dancer.Kick(this, options);
|
||||
},
|
||||
|
||||
bind: function (name, callback) {
|
||||
if (!this.events[name]) {
|
||||
this.events[name] = [];
|
||||
}
|
||||
this.events[name].push(callback);
|
||||
return this;
|
||||
},
|
||||
|
||||
unbind: function (name) {
|
||||
if (this.events[name]) {
|
||||
delete this.events[name];
|
||||
}
|
||||
return this;
|
||||
},
|
||||
|
||||
trigger: function (name) {
|
||||
var _this = this;
|
||||
if (this.events[name]) {
|
||||
this.events[name].forEach(function (callback) {
|
||||
callback.call(_this);
|
||||
});
|
||||
}
|
||||
return this;
|
||||
},
|
||||
|
||||
|
||||
/* Getters */
|
||||
|
||||
getVolume: function () {
|
||||
return this.audioAdapter.getVolume();
|
||||
},
|
||||
|
||||
getProgress: function () {
|
||||
return this.audioAdapter.getProgress();
|
||||
},
|
||||
|
||||
getTime: function () {
|
||||
return this.audioAdapter.getTime();
|
||||
},
|
||||
|
||||
// Returns the magnitude of a frequency or average over a range of frequencies
|
||||
getFrequency: function (freq, endFreq) {
|
||||
var sum = 0;
|
||||
if (endFreq !== undefined) {
|
||||
for (var i = freq; i <= endFreq; i++) {
|
||||
sum += this.getSpectrum()[i];
|
||||
}
|
||||
return sum / (endFreq - freq + 1);
|
||||
} else {
|
||||
return this.getSpectrum()[freq];
|
||||
}
|
||||
},
|
||||
|
||||
getWaveform: function () {
|
||||
return this.audioAdapter.getWaveform();
|
||||
},
|
||||
|
||||
getSpectrum: function () {
|
||||
return this.audioAdapter.getSpectrum();
|
||||
},
|
||||
|
||||
isLoaded: function () {
|
||||
return this.audioAdapter.isLoaded;
|
||||
},
|
||||
|
||||
isPlaying: function () {
|
||||
return this.audioAdapter.isPlaying;
|
||||
},
|
||||
|
||||
|
||||
/* Sections */
|
||||
|
||||
after: function (time, callback) {
|
||||
var _this = this;
|
||||
this.sections.push({
|
||||
condition: function () {
|
||||
return _this.getTime() > time;
|
||||
},
|
||||
callback: callback
|
||||
});
|
||||
return this;
|
||||
},
|
||||
|
||||
before: function (time, callback) {
|
||||
var _this = this;
|
||||
this.sections.push({
|
||||
condition: function () {
|
||||
return _this.getTime() < time;
|
||||
},
|
||||
callback: callback
|
||||
});
|
||||
return this;
|
||||
},
|
||||
|
||||
between: function (startTime, endTime, callback) {
|
||||
var _this = this;
|
||||
this.sections.push({
|
||||
condition: function () {
|
||||
return _this.getTime() > startTime && _this.getTime() < endTime;
|
||||
},
|
||||
callback: callback
|
||||
});
|
||||
return this;
|
||||
},
|
||||
|
||||
onceAt: function (time, callback) {
|
||||
var
|
||||
_this = this,
|
||||
thisSection = null;
|
||||
this.sections.push({
|
||||
condition: function () {
|
||||
return _this.getTime() > time && !this.called;
|
||||
},
|
||||
callback: function () {
|
||||
callback.call(this);
|
||||
thisSection.called = true;
|
||||
},
|
||||
called: false
|
||||
});
|
||||
// Baking the section in the closure due to callback's this being the dancer instance
|
||||
thisSection = this.sections[this.sections.length - 1];
|
||||
return this;
|
||||
}
|
||||
};
|
||||
|
||||
function update() {
|
||||
for (var i in this.sections) {
|
||||
if (this.sections[i].condition && this.sections[i].condition())
|
||||
this.sections[i].callback.call(this);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
window.Dancer = Dancer;
|
||||
})();
|
||||
|
||||
(function (Dancer) {
|
||||
|
||||
var CODECS = {
|
||||
'mp3': 'audio/mpeg;',
|
||||
'ogg': 'audio/ogg; codecs="vorbis"',
|
||||
'wav': 'audio/wav; codecs="1"',
|
||||
'aac': 'audio/mp4; codecs="mp4a.40.2"'
|
||||
},
|
||||
audioEl = document.createElement('audio');
|
||||
|
||||
Dancer.options = {};
|
||||
|
||||
Dancer.setOptions = function (o) {
|
||||
for (var option in o) {
|
||||
if (o.hasOwnProperty(option)) {
|
||||
Dancer.options[option] = o[option];
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Dancer.isSupported = function () {
|
||||
if (!window.Float32Array || !window.Uint32Array) {
|
||||
return null;
|
||||
} else if (!isUnsupportedSafari() && (window.AudioContext || window.webkitAudioContext)) {
|
||||
return 'webaudio';
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
};
|
||||
|
||||
Dancer.canPlay = function (type) {
|
||||
var canPlay = audioEl.canPlayType;
|
||||
return !!(
|
||||
type.toLowerCase() === 'mp3' ||
|
||||
audioEl.canPlayType &&
|
||||
audioEl.canPlayType(CODECS[type.toLowerCase()]).replace(/no/, ''));
|
||||
};
|
||||
|
||||
Dancer.addPlugin = function (name, fn) {
|
||||
if (Dancer.prototype[name] === undefined) {
|
||||
Dancer.prototype[name] = fn;
|
||||
}
|
||||
};
|
||||
|
||||
Dancer._makeSupportedPath = function (source, codecs) {
|
||||
if (!codecs) { return source; }
|
||||
|
||||
for (var i = 0; i < codecs.length; i++) {
|
||||
if (Dancer.canPlay(codecs[i])) {
|
||||
return source + '.' + codecs[i];
|
||||
}
|
||||
}
|
||||
return source;
|
||||
};
|
||||
|
||||
Dancer._getAdapter = function (instance) {
|
||||
switch (Dancer.isSupported()) {
|
||||
case 'webaudio':
|
||||
return new Dancer.adapters.webaudio(instance);
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
Dancer._getMP3SrcFromAudio = function (audioEl) {
|
||||
var sources = audioEl.children;
|
||||
if (audioEl.src) { return audioEl.src; }
|
||||
for (var i = sources.length; i--;) {
|
||||
if ((sources[i].type || '').match(/audio\/mpeg/)) return sources[i].src;
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
// Browser detection is lame, but Safari 6 has Web Audio API,
|
||||
// but does not support processing audio from a Media Element Source
|
||||
// https://gist.github.com/3265344
|
||||
function isUnsupportedSafari() {
|
||||
var
|
||||
isApple = !!(navigator.vendor || '').match(/Apple/),
|
||||
version = navigator.userAgent.match(/Version\/([^ ]*)/);
|
||||
version = version ? parseFloat(version[1]) : 0;
|
||||
return isApple && version <= 6;
|
||||
}
|
||||
|
||||
})(window.Dancer);
|
||||
|
||||
(function (undefined) {
|
||||
var Kick = function (dancer, o) {
|
||||
o = o || {};
|
||||
this.dancer = dancer;
|
||||
this.frequency = o.frequency !== undefined ? o.frequency : [0, 5];
|
||||
this.threshold = o.threshold !== undefined ? o.threshold : 0.3;
|
||||
this.decay = o.decay !== undefined ? o.decay : 0.02;
|
||||
this.onKick = o.onKick;
|
||||
this.offKick = o.offKick;
|
||||
this.isOn = false;
|
||||
this.currentThreshold = this.threshold;
|
||||
this.previousMag = 0;
|
||||
this.canUseRatio = true;
|
||||
this.canUseRatioHandle = null;
|
||||
|
||||
var _this = this;
|
||||
this.dancer.bind('update', function () {
|
||||
_this.onUpdate();
|
||||
});
|
||||
};
|
||||
|
||||
Kick.prototype = {
|
||||
on: function () {
|
||||
this.isOn = true;
|
||||
return this;
|
||||
},
|
||||
off: function () {
|
||||
this.isOn = false;
|
||||
return this;
|
||||
},
|
||||
|
||||
set: function (o) {
|
||||
o = o || {};
|
||||
this.frequency = o.frequency !== undefined ? o.frequency : this.frequency;
|
||||
this.threshold = o.threshold !== undefined ? o.threshold : this.threshold;
|
||||
this.decay = o.decay !== undefined ? o.decay : this.decay;
|
||||
this.onKick = o.onKick || this.onKick;
|
||||
this.offKick = o.offKick || this.offKick;
|
||||
},
|
||||
|
||||
onUpdate: function () {
|
||||
if (!this.isOn) { return; }
|
||||
|
||||
var magnitude = this.maxAmplitude(this.frequency);
|
||||
|
||||
if (magnitude >= this.currentThreshold && magnitude >= this.threshold) {
|
||||
this.currentThreshold = magnitude;
|
||||
this.onKick && this.onKick.call(this.dancer, magnitude);
|
||||
this.canUseRatio = false;
|
||||
|
||||
if (this.canUseRatioHandle) {
|
||||
clearTimeout(this.canUseRatioHandle);
|
||||
this.canUseRatioHandle = null;
|
||||
}
|
||||
|
||||
var self = this;
|
||||
this.canUseRatioHandle = setTimeout(function () {
|
||||
self.canUseRatio = true;
|
||||
}, 5000);
|
||||
} else {
|
||||
if (magnitude / this.previousMag > this.threshold * 5 && magnitude > 0.1 && this.canUseRatio) {
|
||||
this.onKick && this.onKick.call(this.dancer, magnitude, magnitude / this.previousMag);
|
||||
} else {
|
||||
this.offKick && this.offKick.call(this.dancer, magnitude);
|
||||
}
|
||||
|
||||
this.currentThreshold -= this.decay;
|
||||
this.previousMag = (magnitude > 0) ? magnitude : 0.0001;
|
||||
}
|
||||
},
|
||||
maxAmplitude: function (frequency) {
|
||||
var max = 0, fft = this.dancer.getSpectrum();
|
||||
|
||||
// Sloppy array check
|
||||
if (!frequency.length) {
|
||||
return frequency < fft.length ?
|
||||
fft[~~frequency] :
|
||||
null;
|
||||
}
|
||||
|
||||
for (var i = frequency[0], l = frequency[1]; i <= l; i++) {
|
||||
if (fft[i] > max) { max = fft[i]; }
|
||||
}
|
||||
return max;
|
||||
}
|
||||
};
|
||||
|
||||
window.Dancer.Kick = Kick;
|
||||
})();
|
||||
|
||||
(function () {
|
||||
var
|
||||
SAMPLE_SIZE = 2048,
|
||||
SAMPLE_RATE = 44100;
|
||||
|
||||
var adapter = function (dancer) {
|
||||
var context;
|
||||
|
||||
if ('AudioContext' in window) {
|
||||
context = new AudioContext();
|
||||
} else {
|
||||
context = new webkitAudioContext();
|
||||
}
|
||||
|
||||
this.dancer = dancer;
|
||||
this.audio = new Audio();
|
||||
this.context = context;
|
||||
};
|
||||
|
||||
adapter.prototype = {
|
||||
|
||||
load: function (_source, useMic, boost) {
|
||||
var _this = this;
|
||||
this.audio = _source;
|
||||
this.useMic = useMic;
|
||||
this.boost = boost;
|
||||
|
||||
this.isLoaded = false;
|
||||
this.progress = 0;
|
||||
|
||||
if (this.proc) {
|
||||
this.proc.onaudioprocess = null;
|
||||
delete this.proc;
|
||||
}
|
||||
|
||||
this.proc = this.context.createScriptProcessor(SAMPLE_SIZE / 2, 1, 1);
|
||||
|
||||
this.proc.onaudioprocess = function (e) {
|
||||
_this.update.call(_this, e);
|
||||
};
|
||||
|
||||
this.gain = this.context.createGain();
|
||||
|
||||
this.fft = new FFT(SAMPLE_SIZE / 2, SAMPLE_RATE, this.boost);
|
||||
this.signal = new Float32Array(SAMPLE_SIZE / 2);
|
||||
|
||||
if (this.audio.readyState < 3) {
|
||||
this.audio.addEventListener('canplay', function () {
|
||||
connectContext.call(_this);
|
||||
});
|
||||
} else {
|
||||
connectContext.call(_this);
|
||||
}
|
||||
|
||||
this.audio.addEventListener('progress', function (e) {
|
||||
if (e.currentTarget.duration && e.currentTarget.duration !== Infinity) {
|
||||
_this.progress = e.currentTarget.seekable.end(0) / e.currentTarget.duration;
|
||||
}
|
||||
});
|
||||
|
||||
return this.audio;
|
||||
},
|
||||
|
||||
play: function () {
|
||||
this.audio.play();
|
||||
this.isPlaying = true;
|
||||
},
|
||||
|
||||
pause: function () {
|
||||
this.audio.pause();
|
||||
this.isPlaying = false;
|
||||
},
|
||||
|
||||
setVolume: function (volume) {
|
||||
this.gain.gain.value = volume;
|
||||
},
|
||||
|
||||
setBoost: function (boost) {
|
||||
if (this.fft) {
|
||||
this.fft.setBoost(boost);
|
||||
}
|
||||
|
||||
this.boost = boost;
|
||||
},
|
||||
|
||||
getVolume: function () {
|
||||
return this.gain.gain.value;
|
||||
},
|
||||
|
||||
getProgress: function () {
|
||||
return this.progress;
|
||||
},
|
||||
|
||||
getWaveform: function () {
|
||||
return this.signal;
|
||||
},
|
||||
|
||||
getSpectrum: function () {
|
||||
return this.fft.spectrum;
|
||||
},
|
||||
|
||||
getTime: function () {
|
||||
return this.audio.currentTime;
|
||||
},
|
||||
|
||||
update: function (e) {
|
||||
if ((!this.isPlaying || !this.isLoaded) && this.useMic !== true) return;
|
||||
|
||||
var
|
||||
buffers = [],
|
||||
channels = e.inputBuffer.numberOfChannels,
|
||||
resolution = SAMPLE_SIZE / channels,
|
||||
sum = function (prev, curr) {
|
||||
return prev[i] + curr[i];
|
||||
}, i;
|
||||
|
||||
for (i = channels; i--;) {
|
||||
buffers.push(e.inputBuffer.getChannelData(i));
|
||||
}
|
||||
|
||||
for (i = 0; i < resolution; i++) {
|
||||
this.signal[i] = channels > 1 ?
|
||||
buffers.reduce(sum) / channels :
|
||||
buffers[0][i];
|
||||
}
|
||||
|
||||
this.fft.forward(this.signal);
|
||||
this.dancer.trigger('update');
|
||||
}
|
||||
};
|
||||
|
||||
function connectContext() {
|
||||
try {
|
||||
if (this.useMic) {
|
||||
this.source = this.context.createMediaStreamSource(this.audio);
|
||||
} else {
|
||||
this.source = this.context.createMediaElementSource(this.audio);
|
||||
}
|
||||
} catch (err) {
|
||||
console.info('Dancer: ' + err);
|
||||
return;
|
||||
}
|
||||
|
||||
this.source.connect(this.proc);
|
||||
this.source.connect(this.gain);
|
||||
this.gain.connect(this.context.destination);
|
||||
this.proc.connect(this.context.destination);
|
||||
|
||||
this.isLoaded = true;
|
||||
this.progress = 1;
|
||||
this.dancer.trigger('loaded');
|
||||
}
|
||||
|
||||
Dancer.adapters.webaudio = adapter;
|
||||
|
||||
})();
|
||||
|
||||
|
||||
/*
|
||||
* DSP.js - a comprehensive digital signal processing library for javascript
|
||||
*
|
||||
* Created by Corban Brook <corbanbrook@gmail.com> on 2010-01-01.
|
||||
* Copyright 2010 Corban Brook. All rights reserved.
|
||||
*
|
||||
*/
|
||||
|
||||
// Fourier Transform Module used by DFT, FFT, RFFT
|
||||
function FourierTransform(bufferSize, sampleRate, boost) {
|
||||
this.bufferSize = bufferSize;
|
||||
this.sampleRate = sampleRate;
|
||||
this.bandwidth = 2 / bufferSize * sampleRate / 2;
|
||||
this.boost = boost ? boost : 1;
|
||||
|
||||
this.spectrum = new Float32Array(bufferSize / 2);
|
||||
this.real = new Float32Array(bufferSize);
|
||||
this.imag = new Float32Array(bufferSize);
|
||||
|
||||
this.peakBand = 0;
|
||||
this.peak = 0;
|
||||
|
||||
/**
|
||||
* Calculates the *middle* frequency of an FFT band.
|
||||
*
|
||||
* @param {Number} index The index of the FFT band.
|
||||
*
|
||||
* @returns The middle frequency in Hz.
|
||||
*/
|
||||
this.getBandFrequency = function (index) {
|
||||
return this.bandwidth * index + this.bandwidth / 2;
|
||||
};
|
||||
|
||||
this.setBoost = function (boost) {
|
||||
this.boost = boost;
|
||||
};
|
||||
|
||||
this.calculateSpectrum = function () {
|
||||
var spectrum = this.spectrum,
|
||||
real = this.real,
|
||||
imag = this.imag,
|
||||
boost = this.boost,
|
||||
bSi = 2 / this.bufferSize,
|
||||
sqrt = Math.sqrt,
|
||||
rval,
|
||||
ival,
|
||||
mag;
|
||||
|
||||
for (var i = 0, N = bufferSize / 2; i < N; i++) {
|
||||
rval = real[i];
|
||||
ival = imag[i];
|
||||
mag = bSi * sqrt(rval * rval + ival * ival);
|
||||
|
||||
if (mag > this.peak) {
|
||||
this.peakBand = i;
|
||||
this.peak = mag;
|
||||
}
|
||||
|
||||
spectrum[i] = mag * boost;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* FFT is a class for calculating the Discrete Fourier Transform of a signal
|
||||
* with the Fast Fourier Transform algorithm.
|
||||
*
|
||||
* @param {Number} bufferSize The size of the sample buffer to be computed. Must be power of 2
|
||||
* @param {Number} sampleRate The sampleRate of the buffer (eg. 44100)
|
||||
* @param {Number} boost The coefficient
|
||||
*
|
||||
* @constructor
|
||||
*/
|
||||
function FFT(bufferSize, sampleRate, boost) {
|
||||
FourierTransform.call(this, bufferSize, sampleRate, boost);
|
||||
|
||||
this.reverseTable = new Uint32Array(bufferSize);
|
||||
|
||||
var limit = 1;
|
||||
var bit = bufferSize >> 1;
|
||||
|
||||
var i;
|
||||
|
||||
while (limit < bufferSize) {
|
||||
for (i = 0; i < limit; i++) {
|
||||
this.reverseTable[i + limit] = this.reverseTable[i] + bit;
|
||||
}
|
||||
|
||||
limit = limit << 1;
|
||||
bit = bit >> 1;
|
||||
}
|
||||
|
||||
this.sinTable = new Float32Array(bufferSize);
|
||||
this.cosTable = new Float32Array(bufferSize);
|
||||
|
||||
for (i = 0; i < bufferSize; i++) {
|
||||
this.sinTable[i] = Math.sin(-Math.PI / i);
|
||||
this.cosTable[i] = Math.cos(-Math.PI / i);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs a forward transform on the sample buffer.
|
||||
* Converts a time domain signal to frequency domain spectra.
|
||||
*
|
||||
* @param {Array} buffer The sample buffer. Buffer Length must be power of 2
|
||||
*
|
||||
* @returns The frequency spectrum array
|
||||
*/
|
||||
FFT.prototype.forward = function (buffer) {
|
||||
// Locally scope variables for speed up
|
||||
var bufferSize = this.bufferSize,
|
||||
cosTable = this.cosTable,
|
||||
sinTable = this.sinTable,
|
||||
reverseTable = this.reverseTable,
|
||||
real = this.real,
|
||||
imag = this.imag,
|
||||
spectrum = this.spectrum;
|
||||
|
||||
var k = Math.floor(Math.log(bufferSize) / Math.LN2);
|
||||
|
||||
if (Math.pow(2, k) !== bufferSize) { throw "Invalid buffer size, must be a power of 2."; }
|
||||
if (bufferSize !== buffer.length) { throw "Supplied buffer is not the same size as defined FFT. FFT Size: " + bufferSize + " Buffer Size: " + buffer.length; }
|
||||
|
||||
var halfSize = 1,
|
||||
phaseShiftStepReal,
|
||||
phaseShiftStepImag,
|
||||
currentPhaseShiftReal,
|
||||
currentPhaseShiftImag,
|
||||
off,
|
||||
tr,
|
||||
ti,
|
||||
tmpReal,
|
||||
i;
|
||||
|
||||
for (i = 0; i < bufferSize; i++) {
|
||||
real[i] = buffer[reverseTable[i]];
|
||||
imag[i] = 0;
|
||||
}
|
||||
|
||||
while (halfSize < bufferSize) {
|
||||
//phaseShiftStepReal = Math.cos(-Math.PI/halfSize);
|
||||
//phaseShiftStepImag = Math.sin(-Math.PI/halfSize);
|
||||
phaseShiftStepReal = cosTable[halfSize];
|
||||
phaseShiftStepImag = sinTable[halfSize];
|
||||
|
||||
currentPhaseShiftReal = 1;
|
||||
currentPhaseShiftImag = 0;
|
||||
|
||||
for (var fftStep = 0; fftStep < halfSize; fftStep++) {
|
||||
i = fftStep;
|
||||
|
||||
while (i < bufferSize) {
|
||||
off = i + halfSize;
|
||||
tr = (currentPhaseShiftReal * real[off]) - (currentPhaseShiftImag * imag[off]);
|
||||
ti = (currentPhaseShiftReal * imag[off]) + (currentPhaseShiftImag * real[off]);
|
||||
|
||||
real[off] = real[i] - tr;
|
||||
imag[off] = imag[i] - ti;
|
||||
real[i] += tr;
|
||||
imag[i] += ti;
|
||||
|
||||
i += halfSize << 1;
|
||||
}
|
||||
|
||||
tmpReal = currentPhaseShiftReal;
|
||||
currentPhaseShiftReal = (tmpReal * phaseShiftStepReal) - (currentPhaseShiftImag * phaseShiftStepImag);
|
||||
currentPhaseShiftImag = (tmpReal * phaseShiftStepImag) + (currentPhaseShiftImag * phaseShiftStepReal);
|
||||
}
|
||||
|
||||
halfSize = halfSize << 1;
|
||||
}
|
||||
|
||||
return this.calculateSpectrum();
|
||||
};
|
||||
|
||||
|
||||
chrome.storage.local.get('threshold', ({threshold}) => {
|
||||
threshold = threshold || 0.3;
|
||||
|
||||
let dancer = new window.Dancer(),
|
||||
paused = false,
|
||||
simulateKick = (mag, ratioKickMag) => {
|
||||
console.log('mag: ' + mag + ', ratioKickMag: ' + ratioKickMag);
|
||||
},
|
||||
kick = dancer.createKick({
|
||||
threshold,
|
||||
onKick: (mag, ratioKickMag) => {
|
||||
if (paused === false) {
|
||||
simulateKick(mag, ratioKickMag);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
kick.on();
|
||||
|
||||
chrome.runtime.onMessage.addListener(function (request, sender, sendResponse) {
|
||||
if (request.action === 'start-listening') {
|
||||
chrome.tabCapture.capture({
|
||||
audio: true,
|
||||
video: false
|
||||
}, function (stream) {
|
||||
let error = null;
|
||||
|
||||
if (!stream) {
|
||||
error = chrome.runtime.lastError.message;
|
||||
} else {
|
||||
// let audio = new Audio();
|
||||
// audio.src = URL.createObjectURL(stream);
|
||||
// audio.crossOrigin = "anonymous";
|
||||
//dancer.load(audio, 1);
|
||||
}
|
||||
|
||||
sendResponse({ error });
|
||||
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
});
|
||||
|
||||
// simulateKick(/*mag, ratioKickMag*/) {
|
||||
// let activeLights = this.get('activeLights'),
|
||||
// lightsData = this.get('lightsData'),
|
||||
// color = null,
|
||||
|
||||
// transitiontime = this.get('flashingTransitions'),
|
||||
// stimulateLight = (light, brightness, hue) => {
|
||||
// let options = { 'bri': brightness };
|
||||
|
||||
// if (transitiontime) {
|
||||
// options['transitiontime'] = 0;
|
||||
// } else {
|
||||
// options['transitiontime'] = 1;
|
||||
// }
|
||||
|
||||
// if (!isNone(hue)) {
|
||||
// options.hue = hue;
|
||||
// }
|
||||
|
||||
// if (lightsData[light].state.on === false) {
|
||||
// options.on = true;
|
||||
// }
|
||||
|
||||
// $.ajax(this.get('apiURL') + '/lights/' + light + '/state', {
|
||||
// data: JSON.stringify(options),
|
||||
// contentType: 'application/json',
|
||||
// type: 'PUT'
|
||||
// });
|
||||
// },
|
||||
// timeToBriOff = 100;
|
||||
|
||||
// if (activeLights.length > 0) {
|
||||
// let lastLightBopIndex = this.get('lastLightBopIndex'),
|
||||
// lightBopIndex,
|
||||
// brightnessRange = this.get('brightnessRange'),
|
||||
// light;
|
||||
|
||||
// lightBopIndex = Math.floor(Math.random() * activeLights.length);
|
||||
|
||||
// // let's try not to select the same light twice in a row
|
||||
// if (activeLights.length > 1) {
|
||||
// while (lightBopIndex === lastLightBopIndex) {
|
||||
// lightBopIndex = Math.floor(Math.random() * activeLights.length);
|
||||
// }
|
||||
// }
|
||||
|
||||
// light = activeLights[lightBopIndex];
|
||||
// this.set('lastLightBopIndex', lightBopIndex);
|
||||
|
||||
// if (!this.get('colorloopMode')) {
|
||||
// let hueRange = this.get('hueRange');
|
||||
|
||||
// color = Math.floor(Math.random() * (hueRange[1] - hueRange[0] + 1) + hueRange[0]);
|
||||
// }
|
||||
|
||||
// if (transitiontime) {
|
||||
// timeToBriOff = 80;
|
||||
// }
|
||||
|
||||
// stimulateLight(light, brightnessRange[1], color);
|
||||
// later(this, stimulateLight, light, brightnessRange[0], timeToBriOff);
|
||||
// }
|
||||
|
||||
// this.set('paused', true);
|
||||
// later(this, function () {
|
||||
// this.set('paused', false);
|
||||
// }, 150);
|
||||
// }
|
||||
709
chrome/vendor/dancer.js
vendored
709
chrome/vendor/dancer.js
vendored
|
|
@ -1,709 +0,0 @@
|
|||
/*
|
||||
* dancer - v0.4.0 - 2014-02-01
|
||||
* https://github.com/jsantell/dancer.js
|
||||
* Copyright (c) 2014 Jordan Santell
|
||||
* Licensed MIT
|
||||
*/
|
||||
(function() {
|
||||
|
||||
var Dancer = function () {
|
||||
this.audioAdapter = Dancer._getAdapter( this );
|
||||
this.events = {};
|
||||
this.sections = [];
|
||||
this.bind( 'update', update );
|
||||
};
|
||||
|
||||
Dancer.version = 'X.X.X';
|
||||
Dancer.adapters = {};
|
||||
|
||||
Dancer.prototype = {
|
||||
|
||||
load : function ( source, micBoost, useMic ) {
|
||||
// Loading an Audio element
|
||||
if ( source instanceof HTMLElement ) {
|
||||
this.source = source;
|
||||
// Loading an object with src, [codecs]
|
||||
} else if(source instanceof EventTarget){
|
||||
this.source = source;
|
||||
} else {
|
||||
this.source = window.Audio ? new Audio() : {};
|
||||
this.source.src = Dancer._makeSupportedPath( source.src, source.codecs );
|
||||
}
|
||||
|
||||
this.useMic = useMic === true;
|
||||
this.boost = micBoost ? micBoost : 1;
|
||||
this.audio = this.audioAdapter.load(this.source, this.useMic, this.boost);
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
/* Controls */
|
||||
play : function () {
|
||||
this.audioAdapter.play();
|
||||
return this;
|
||||
},
|
||||
|
||||
pause : function () {
|
||||
this.audioAdapter.pause();
|
||||
return this;
|
||||
},
|
||||
|
||||
setVolume : function ( volume ) {
|
||||
this.audioAdapter.setVolume( volume );
|
||||
return this;
|
||||
},
|
||||
|
||||
setBoost : function ( boost ) {
|
||||
this.audioAdapter.setBoost( boost );
|
||||
return this;
|
||||
},
|
||||
|
||||
/* Actions */
|
||||
createKick : function ( options ) {
|
||||
return new Dancer.Kick( this, options );
|
||||
},
|
||||
|
||||
bind : function ( name, callback ) {
|
||||
if ( !this.events[ name ] ) {
|
||||
this.events[ name ] = [];
|
||||
}
|
||||
this.events[ name ].push( callback );
|
||||
return this;
|
||||
},
|
||||
|
||||
unbind : function ( name ) {
|
||||
if ( this.events[ name ] ) {
|
||||
delete this.events[ name ];
|
||||
}
|
||||
return this;
|
||||
},
|
||||
|
||||
trigger : function ( name ) {
|
||||
var _this = this;
|
||||
if ( this.events[ name ] ) {
|
||||
this.events[ name ].forEach(function( callback ) {
|
||||
callback.call( _this );
|
||||
});
|
||||
}
|
||||
return this;
|
||||
},
|
||||
|
||||
|
||||
/* Getters */
|
||||
|
||||
getVolume : function () {
|
||||
return this.audioAdapter.getVolume();
|
||||
},
|
||||
|
||||
getProgress : function () {
|
||||
return this.audioAdapter.getProgress();
|
||||
},
|
||||
|
||||
getTime : function () {
|
||||
return this.audioAdapter.getTime();
|
||||
},
|
||||
|
||||
// Returns the magnitude of a frequency or average over a range of frequencies
|
||||
getFrequency : function ( freq, endFreq ) {
|
||||
var sum = 0;
|
||||
if ( endFreq !== undefined ) {
|
||||
for ( var i = freq; i <= endFreq; i++ ) {
|
||||
sum += this.getSpectrum()[ i ];
|
||||
}
|
||||
return sum / ( endFreq - freq + 1 );
|
||||
} else {
|
||||
return this.getSpectrum()[ freq ];
|
||||
}
|
||||
},
|
||||
|
||||
getWaveform : function () {
|
||||
return this.audioAdapter.getWaveform();
|
||||
},
|
||||
|
||||
getSpectrum : function () {
|
||||
return this.audioAdapter.getSpectrum();
|
||||
},
|
||||
|
||||
isLoaded : function () {
|
||||
return this.audioAdapter.isLoaded;
|
||||
},
|
||||
|
||||
isPlaying : function () {
|
||||
return this.audioAdapter.isPlaying;
|
||||
},
|
||||
|
||||
|
||||
/* Sections */
|
||||
|
||||
after : function ( time, callback ) {
|
||||
var _this = this;
|
||||
this.sections.push({
|
||||
condition : function () {
|
||||
return _this.getTime() > time;
|
||||
},
|
||||
callback : callback
|
||||
});
|
||||
return this;
|
||||
},
|
||||
|
||||
before : function ( time, callback ) {
|
||||
var _this = this;
|
||||
this.sections.push({
|
||||
condition : function () {
|
||||
return _this.getTime() < time;
|
||||
},
|
||||
callback : callback
|
||||
});
|
||||
return this;
|
||||
},
|
||||
|
||||
between : function ( startTime, endTime, callback ) {
|
||||
var _this = this;
|
||||
this.sections.push({
|
||||
condition : function () {
|
||||
return _this.getTime() > startTime && _this.getTime() < endTime;
|
||||
},
|
||||
callback : callback
|
||||
});
|
||||
return this;
|
||||
},
|
||||
|
||||
onceAt : function ( time, callback ) {
|
||||
var
|
||||
_this = this,
|
||||
thisSection = null;
|
||||
this.sections.push({
|
||||
condition : function () {
|
||||
return _this.getTime() > time && !this.called;
|
||||
},
|
||||
callback : function () {
|
||||
callback.call( this );
|
||||
thisSection.called = true;
|
||||
},
|
||||
called : false
|
||||
});
|
||||
// Baking the section in the closure due to callback's this being the dancer instance
|
||||
thisSection = this.sections[ this.sections.length - 1 ];
|
||||
return this;
|
||||
}
|
||||
};
|
||||
|
||||
function update () {
|
||||
for (var i in this.sections) {
|
||||
if (this.sections[i].condition && this.sections[i].condition() )
|
||||
this.sections[i].callback.call(this);
|
||||
}
|
||||
}
|
||||
|
||||
window.Dancer = Dancer;
|
||||
})();
|
||||
|
||||
(function ( Dancer ) {
|
||||
|
||||
var CODECS = {
|
||||
'mp3' : 'audio/mpeg;',
|
||||
'ogg' : 'audio/ogg; codecs="vorbis"',
|
||||
'wav' : 'audio/wav; codecs="1"',
|
||||
'aac' : 'audio/mp4; codecs="mp4a.40.2"'
|
||||
},
|
||||
audioEl = document.createElement( 'audio' );
|
||||
|
||||
Dancer.options = {};
|
||||
|
||||
Dancer.setOptions = function ( o ) {
|
||||
for ( var option in o ) {
|
||||
if ( o.hasOwnProperty( option ) ) {
|
||||
Dancer.options[ option ] = o[ option ];
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Dancer.isSupported = function () {
|
||||
if ( !window.Float32Array || !window.Uint32Array ) {
|
||||
return null;
|
||||
} else if ( !isUnsupportedSafari() && ( window.AudioContext || window.webkitAudioContext )) {
|
||||
return 'webaudio';
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
};
|
||||
|
||||
Dancer.canPlay = function ( type ) {
|
||||
var canPlay = audioEl.canPlayType;
|
||||
return !!(
|
||||
type.toLowerCase() === 'mp3' ||
|
||||
audioEl.canPlayType &&
|
||||
audioEl.canPlayType( CODECS[ type.toLowerCase() ] ).replace( /no/, ''));
|
||||
};
|
||||
|
||||
Dancer.addPlugin = function ( name, fn ) {
|
||||
if ( Dancer.prototype[ name ] === undefined ) {
|
||||
Dancer.prototype[ name ] = fn;
|
||||
}
|
||||
};
|
||||
|
||||
Dancer._makeSupportedPath = function ( source, codecs ) {
|
||||
if ( !codecs ) { return source; }
|
||||
|
||||
for ( var i = 0; i < codecs.length; i++ ) {
|
||||
if ( Dancer.canPlay( codecs[ i ] ) ) {
|
||||
return source + '.' + codecs[ i ];
|
||||
}
|
||||
}
|
||||
return source;
|
||||
};
|
||||
|
||||
Dancer._getAdapter = function ( instance ) {
|
||||
switch ( Dancer.isSupported() ) {
|
||||
case 'webaudio':
|
||||
return new Dancer.adapters.webaudio( instance );
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
Dancer._getMP3SrcFromAudio = function ( audioEl ) {
|
||||
var sources = audioEl.children;
|
||||
if ( audioEl.src ) { return audioEl.src; }
|
||||
for ( var i = sources.length; i--; ) {
|
||||
if (( sources[ i ].type || '' ).match( /audio\/mpeg/ )) return sources[ i ].src;
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
// Browser detection is lame, but Safari 6 has Web Audio API,
|
||||
// but does not support processing audio from a Media Element Source
|
||||
// https://gist.github.com/3265344
|
||||
function isUnsupportedSafari () {
|
||||
var
|
||||
isApple = !!( navigator.vendor || '' ).match( /Apple/ ),
|
||||
version = navigator.userAgent.match( /Version\/([^ ]*)/ );
|
||||
version = version ? parseFloat( version[ 1 ] ) : 0;
|
||||
return isApple && version <= 6;
|
||||
}
|
||||
|
||||
})( window.Dancer );
|
||||
|
||||
(function ( undefined ) {
|
||||
var Kick = function ( dancer, o ) {
|
||||
o = o || {};
|
||||
this.dancer = dancer;
|
||||
this.frequency = o.frequency !== undefined ? o.frequency : [ 0, 5 ];
|
||||
this.threshold = o.threshold !== undefined ? o.threshold : 0.3;
|
||||
this.decay = o.decay !== undefined ? o.decay : 0.02;
|
||||
this.onKick = o.onKick;
|
||||
this.offKick = o.offKick;
|
||||
this.isOn = false;
|
||||
this.currentThreshold = this.threshold;
|
||||
this.previousMag = 0;
|
||||
this.canUseRatio = true;
|
||||
this.canUseRatioHandle = null;
|
||||
|
||||
var _this = this;
|
||||
this.dancer.bind( 'update', function () {
|
||||
_this.onUpdate();
|
||||
});
|
||||
};
|
||||
|
||||
Kick.prototype = {
|
||||
on : function () {
|
||||
this.isOn = true;
|
||||
return this;
|
||||
},
|
||||
off : function () {
|
||||
this.isOn = false;
|
||||
return this;
|
||||
},
|
||||
|
||||
set : function ( o ) {
|
||||
o = o || {};
|
||||
this.frequency = o.frequency !== undefined ? o.frequency : this.frequency;
|
||||
this.threshold = o.threshold !== undefined ? o.threshold : this.threshold;
|
||||
this.decay = o.decay !== undefined ? o.decay : this.decay;
|
||||
this.onKick = o.onKick || this.onKick;
|
||||
this.offKick = o.offKick || this.offKick;
|
||||
},
|
||||
|
||||
onUpdate : function () {
|
||||
if ( !this.isOn ) { return; }
|
||||
|
||||
var magnitude = this.maxAmplitude(this.frequency);
|
||||
|
||||
if (magnitude >= this.currentThreshold && magnitude >= this.threshold) {
|
||||
this.currentThreshold = magnitude;
|
||||
this.onKick && this.onKick.call(this.dancer, magnitude);
|
||||
this.canUseRatio = false;
|
||||
|
||||
if(this.canUseRatioHandle) {
|
||||
clearTimeout(this.canUseRatioHandle);
|
||||
this.canUseRatioHandle = null;
|
||||
}
|
||||
|
||||
var self = this;
|
||||
this.canUseRatioHandle = setTimeout(function(){
|
||||
self.canUseRatio = true;
|
||||
}, 5000);
|
||||
} else {
|
||||
if(magnitude/this.previousMag > this.threshold*5 && magnitude>0.1 && this.canUseRatio) {
|
||||
this.onKick && this.onKick.call(this.dancer, magnitude, magnitude/this.previousMag);
|
||||
} else {
|
||||
this.offKick && this.offKick.call(this.dancer, magnitude);
|
||||
}
|
||||
|
||||
this.currentThreshold -= this.decay;
|
||||
this.previousMag = (magnitude > 0) ? magnitude : 0.0001;
|
||||
}
|
||||
},
|
||||
maxAmplitude : function ( frequency ) {
|
||||
var max = 0, fft = this.dancer.getSpectrum();
|
||||
|
||||
// Sloppy array check
|
||||
if ( !frequency.length ) {
|
||||
return frequency < fft.length ?
|
||||
fft[ ~~frequency ] :
|
||||
null;
|
||||
}
|
||||
|
||||
for ( var i = frequency[ 0 ], l = frequency[ 1 ]; i <= l; i++ ) {
|
||||
if ( fft[ i ] > max ) { max = fft[ i ]; }
|
||||
}
|
||||
return max;
|
||||
}
|
||||
};
|
||||
|
||||
window.Dancer.Kick = Kick;
|
||||
})();
|
||||
|
||||
(function() {
|
||||
var
|
||||
SAMPLE_SIZE = 2048,
|
||||
SAMPLE_RATE = 44100;
|
||||
|
||||
var adapter = function ( dancer ) {
|
||||
var context;
|
||||
|
||||
if('AudioContext' in window) {
|
||||
context = new AudioContext();
|
||||
} else {
|
||||
context = new webkitAudioContext();
|
||||
}
|
||||
|
||||
this.dancer = dancer;
|
||||
this.audio = new Audio();
|
||||
this.context = context;
|
||||
};
|
||||
|
||||
adapter.prototype = {
|
||||
|
||||
load : function (_source, useMic, boost) {
|
||||
var _this = this;
|
||||
this.audio = _source;
|
||||
this.useMic = useMic;
|
||||
this.boost = boost;
|
||||
|
||||
this.isLoaded = false;
|
||||
this.progress = 0;
|
||||
|
||||
if(this.proc){
|
||||
this.proc.onaudioprocess = null;
|
||||
delete this.proc;
|
||||
}
|
||||
|
||||
this.proc = this.context.createScriptProcessor( SAMPLE_SIZE / 2, 1, 1 );
|
||||
|
||||
this.proc.onaudioprocess = function ( e ) {
|
||||
_this.update.call( _this, e );
|
||||
};
|
||||
|
||||
this.gain = this.context.createGain();
|
||||
|
||||
this.fft = new FFT( SAMPLE_SIZE / 2, SAMPLE_RATE, this.boost );
|
||||
this.signal = new Float32Array( SAMPLE_SIZE / 2 );
|
||||
|
||||
if ( this.audio.readyState < 3 ) {
|
||||
this.audio.addEventListener( 'canplay', function () {
|
||||
connectContext.call( _this );
|
||||
});
|
||||
} else {
|
||||
connectContext.call( _this );
|
||||
}
|
||||
|
||||
this.audio.addEventListener( 'progress', function ( e ) {
|
||||
if ( e.currentTarget.duration && e.currentTarget.duration !== Infinity ) {
|
||||
_this.progress = e.currentTarget.seekable.end( 0 ) / e.currentTarget.duration;
|
||||
}
|
||||
});
|
||||
|
||||
return this.audio;
|
||||
},
|
||||
|
||||
play : function () {
|
||||
this.audio.play();
|
||||
this.isPlaying = true;
|
||||
},
|
||||
|
||||
pause : function () {
|
||||
this.audio.pause();
|
||||
this.isPlaying = false;
|
||||
},
|
||||
|
||||
setVolume : function ( volume ) {
|
||||
this.gain.gain.value = volume;
|
||||
},
|
||||
|
||||
setBoost : function( boost ){
|
||||
if(this.fft){
|
||||
this.fft.setBoost(boost);
|
||||
}
|
||||
|
||||
this.boost = boost;
|
||||
},
|
||||
|
||||
getVolume : function () {
|
||||
return this.gain.gain.value;
|
||||
},
|
||||
|
||||
getProgress : function() {
|
||||
return this.progress;
|
||||
},
|
||||
|
||||
getWaveform : function () {
|
||||
return this.signal;
|
||||
},
|
||||
|
||||
getSpectrum : function () {
|
||||
return this.fft.spectrum;
|
||||
},
|
||||
|
||||
getTime : function () {
|
||||
return this.audio.currentTime;
|
||||
},
|
||||
|
||||
update : function ( e ) {
|
||||
if ((!this.isPlaying || !this.isLoaded) && this.useMic !== true ) return;
|
||||
|
||||
var
|
||||
buffers = [],
|
||||
channels = e.inputBuffer.numberOfChannels,
|
||||
resolution = SAMPLE_SIZE / channels,
|
||||
sum = function ( prev, curr ) {
|
||||
return prev[ i ] + curr[ i ];
|
||||
}, i;
|
||||
|
||||
for ( i = channels; i--; ) {
|
||||
buffers.push( e.inputBuffer.getChannelData( i ) );
|
||||
}
|
||||
|
||||
for ( i = 0; i < resolution; i++ ) {
|
||||
this.signal[ i ] = channels > 1 ?
|
||||
buffers.reduce( sum ) / channels :
|
||||
buffers[ 0 ][ i ];
|
||||
}
|
||||
|
||||
this.fft.forward( this.signal );
|
||||
this.dancer.trigger( 'update' );
|
||||
}
|
||||
};
|
||||
|
||||
function connectContext () {
|
||||
try {
|
||||
if(this.useMic){
|
||||
this.source = this.context.createMediaStreamSource(this.audio);
|
||||
} else {
|
||||
this.source = this.context.createMediaElementSource(this.audio);
|
||||
}
|
||||
} catch (err) {
|
||||
console.info('Dancer: '+ err);
|
||||
return;
|
||||
}
|
||||
|
||||
this.source.connect(this.proc);
|
||||
this.source.connect(this.gain);
|
||||
this.gain.connect(this.context.destination);
|
||||
this.proc.connect(this.context.destination);
|
||||
|
||||
this.isLoaded = true;
|
||||
this.progress = 1;
|
||||
this.dancer.trigger( 'loaded' );
|
||||
}
|
||||
|
||||
Dancer.adapters.webaudio = adapter;
|
||||
|
||||
})();
|
||||
|
||||
|
||||
/*
|
||||
* DSP.js - a comprehensive digital signal processing library for javascript
|
||||
*
|
||||
* Created by Corban Brook <corbanbrook@gmail.com> on 2010-01-01.
|
||||
* Copyright 2010 Corban Brook. All rights reserved.
|
||||
*
|
||||
*/
|
||||
|
||||
// Fourier Transform Module used by DFT, FFT, RFFT
|
||||
function FourierTransform(bufferSize, sampleRate, boost) {
|
||||
this.bufferSize = bufferSize;
|
||||
this.sampleRate = sampleRate;
|
||||
this.bandwidth = 2 / bufferSize * sampleRate / 2;
|
||||
this.boost = boost ? boost : 1;
|
||||
|
||||
this.spectrum = new Float32Array(bufferSize/2);
|
||||
this.real = new Float32Array(bufferSize);
|
||||
this.imag = new Float32Array(bufferSize);
|
||||
|
||||
this.peakBand = 0;
|
||||
this.peak = 0;
|
||||
|
||||
/**
|
||||
* Calculates the *middle* frequency of an FFT band.
|
||||
*
|
||||
* @param {Number} index The index of the FFT band.
|
||||
*
|
||||
* @returns The middle frequency in Hz.
|
||||
*/
|
||||
this.getBandFrequency = function(index) {
|
||||
return this.bandwidth * index + this.bandwidth / 2;
|
||||
};
|
||||
|
||||
this.setBoost = function(boost){
|
||||
this.boost = boost;
|
||||
};
|
||||
|
||||
this.calculateSpectrum = function() {
|
||||
var spectrum = this.spectrum,
|
||||
real = this.real,
|
||||
imag = this.imag,
|
||||
boost = this.boost,
|
||||
bSi = 2 / this.bufferSize,
|
||||
sqrt = Math.sqrt,
|
||||
rval,
|
||||
ival,
|
||||
mag;
|
||||
|
||||
for (var i = 0, N = bufferSize/2; i < N; i++) {
|
||||
rval = real[i];
|
||||
ival = imag[i];
|
||||
mag = bSi * sqrt(rval * rval + ival * ival);
|
||||
|
||||
if (mag > this.peak) {
|
||||
this.peakBand = i;
|
||||
this.peak = mag;
|
||||
}
|
||||
|
||||
spectrum[i] = mag * boost;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* FFT is a class for calculating the Discrete Fourier Transform of a signal
|
||||
* with the Fast Fourier Transform algorithm.
|
||||
*
|
||||
* @param {Number} bufferSize The size of the sample buffer to be computed. Must be power of 2
|
||||
* @param {Number} sampleRate The sampleRate of the buffer (eg. 44100)
|
||||
* @param {Number} boost The coefficient
|
||||
*
|
||||
* @constructor
|
||||
*/
|
||||
function FFT(bufferSize, sampleRate, boost) {
|
||||
FourierTransform.call(this, bufferSize, sampleRate, boost);
|
||||
|
||||
this.reverseTable = new Uint32Array(bufferSize);
|
||||
|
||||
var limit = 1;
|
||||
var bit = bufferSize >> 1;
|
||||
|
||||
var i;
|
||||
|
||||
while (limit < bufferSize) {
|
||||
for (i = 0; i < limit; i++) {
|
||||
this.reverseTable[i + limit] = this.reverseTable[i] + bit;
|
||||
}
|
||||
|
||||
limit = limit << 1;
|
||||
bit = bit >> 1;
|
||||
}
|
||||
|
||||
this.sinTable = new Float32Array(bufferSize);
|
||||
this.cosTable = new Float32Array(bufferSize);
|
||||
|
||||
for (i = 0; i < bufferSize; i++) {
|
||||
this.sinTable[i] = Math.sin(-Math.PI/i);
|
||||
this.cosTable[i] = Math.cos(-Math.PI/i);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs a forward transform on the sample buffer.
|
||||
* Converts a time domain signal to frequency domain spectra.
|
||||
*
|
||||
* @param {Array} buffer The sample buffer. Buffer Length must be power of 2
|
||||
*
|
||||
* @returns The frequency spectrum array
|
||||
*/
|
||||
FFT.prototype.forward = function(buffer) {
|
||||
// Locally scope variables for speed up
|
||||
var bufferSize = this.bufferSize,
|
||||
cosTable = this.cosTable,
|
||||
sinTable = this.sinTable,
|
||||
reverseTable = this.reverseTable,
|
||||
real = this.real,
|
||||
imag = this.imag,
|
||||
spectrum = this.spectrum;
|
||||
|
||||
var k = Math.floor(Math.log(bufferSize) / Math.LN2);
|
||||
|
||||
if (Math.pow(2, k) !== bufferSize) { throw "Invalid buffer size, must be a power of 2."; }
|
||||
if (bufferSize !== buffer.length) { throw "Supplied buffer is not the same size as defined FFT. FFT Size: " + bufferSize + " Buffer Size: " + buffer.length; }
|
||||
|
||||
var halfSize = 1,
|
||||
phaseShiftStepReal,
|
||||
phaseShiftStepImag,
|
||||
currentPhaseShiftReal,
|
||||
currentPhaseShiftImag,
|
||||
off,
|
||||
tr,
|
||||
ti,
|
||||
tmpReal,
|
||||
i;
|
||||
|
||||
for (i = 0; i < bufferSize; i++) {
|
||||
real[i] = buffer[reverseTable[i]];
|
||||
imag[i] = 0;
|
||||
}
|
||||
|
||||
while (halfSize < bufferSize) {
|
||||
//phaseShiftStepReal = Math.cos(-Math.PI/halfSize);
|
||||
//phaseShiftStepImag = Math.sin(-Math.PI/halfSize);
|
||||
phaseShiftStepReal = cosTable[halfSize];
|
||||
phaseShiftStepImag = sinTable[halfSize];
|
||||
|
||||
currentPhaseShiftReal = 1;
|
||||
currentPhaseShiftImag = 0;
|
||||
|
||||
for (var fftStep = 0; fftStep < halfSize; fftStep++) {
|
||||
i = fftStep;
|
||||
|
||||
while (i < bufferSize) {
|
||||
off = i + halfSize;
|
||||
tr = (currentPhaseShiftReal * real[off]) - (currentPhaseShiftImag * imag[off]);
|
||||
ti = (currentPhaseShiftReal * imag[off]) + (currentPhaseShiftImag * real[off]);
|
||||
|
||||
real[off] = real[i] - tr;
|
||||
imag[off] = imag[i] - ti;
|
||||
real[i] += tr;
|
||||
imag[i] += ti;
|
||||
|
||||
i += halfSize << 1;
|
||||
}
|
||||
|
||||
tmpReal = currentPhaseShiftReal;
|
||||
currentPhaseShiftReal = (tmpReal * phaseShiftStepReal) - (currentPhaseShiftImag * phaseShiftStepImag);
|
||||
currentPhaseShiftImag = (tmpReal * phaseShiftStepImag) + (currentPhaseShiftImag * phaseShiftStepReal);
|
||||
}
|
||||
|
||||
halfSize = halfSize << 1;
|
||||
}
|
||||
|
||||
return this.calculateSpectrum();
|
||||
};
|
||||
|
|
@ -1,41 +1,42 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<title>Huegasm</title>
|
||||
<meta name="description" content="Huegasm is a free web application for managing and synchronizing your Philips Hue lights with the beat of your music.">
|
||||
<meta name="keywords" content="huegasm,hue,philips hue,music player">
|
||||
<meta name="author" content="Egor Philippov">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
|
||||
{{content-for 'head'}}
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<title>Huegasm</title>
|
||||
<meta name="description" content="Huegasm is a free web application for managing and synchronizing your Philips Hue lights with the beat of your music.">
|
||||
<meta name="keywords" content="huegasm,hue,philips hue,music player">
|
||||
<meta name="author" content="Egor Philippov">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1"> {{content-for 'head'}}
|
||||
|
||||
<link href='https://fonts.googleapis.com/css?family=Slabo+27px|Open+Sans' rel='stylesheet' type='text/css'>
|
||||
<link href='https://fonts.googleapis.com/css?family=Open+Sans|Raleway' rel='stylesheet' type='text/css'>
|
||||
|
||||
<link rel="stylesheet" integrity="" href="assets/vendor.css">
|
||||
<link rel="stylesheet" integrity="" href="assets/huegasm_mobile.css">
|
||||
<link rel="stylesheet" integrity="" href="assets/vendor.css">
|
||||
<link rel="stylesheet" integrity="" href="assets/huegasm_mobile.css"> {{content-for 'head-footer'}}
|
||||
|
||||
{{content-for 'head-footer'}}
|
||||
<script src="https://connect.soundcloud.com/sdk/sdk-3.1.2.js"></script>
|
||||
|
||||
<script src="https://connect.soundcloud.com/sdk/sdk-3.1.2.js"></script>
|
||||
<script>
|
||||
(function (i, s, o, g, r, a, m) {
|
||||
i['GoogleAnalyticsObject'] = r; i[r] = i[r] || function () {
|
||||
(i[r].q = i[r].q || []).push(arguments)
|
||||
}, i[r].l = 1 * new Date(); a = s.createElement(o),
|
||||
m = s.getElementsByTagName(o)[0]; a.async = 1; a.src = g; m.parentNode.insertBefore(a, m)
|
||||
})(window, document, 'script', 'https://www.google-analytics.com/analytics.js', 'ga');
|
||||
|
||||
<script>
|
||||
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
|
||||
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
|
||||
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
|
||||
})(window,document,'script','https://www.google-analytics.com/analytics.js','ga');
|
||||
ga('create', 'UA-69470561-1', 'auto');
|
||||
ga('send', 'pageview');
|
||||
</script>
|
||||
</head>
|
||||
|
||||
ga('create', 'UA-69470561-1', 'auto');
|
||||
ga('send', 'pageview');
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
{{content-for 'body'}}
|
||||
<body>
|
||||
{{content-for 'body'}}
|
||||
|
||||
<script src="assets/vendor.js"></script>
|
||||
<script src="assets/huegasm_mobile.js"></script>
|
||||
<script src="assets/vendor.js"></script>
|
||||
<script src="assets/huegasm_mobile.js"></script>
|
||||
|
||||
{{content-for 'body-footer'}}
|
||||
</body>
|
||||
</html>
|
||||
{{content-for 'body-footer'}}
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
|
@ -5,7 +5,7 @@
|
|||
<p class="bridge-finder-bottom">
|
||||
{{#if isAuthenticating}}
|
||||
Your bridge IP is <b>{{bridgeIp}}</b>
|
||||
<br> Press the button on your bridge to authenticate this application.
|
||||
<br> Press the button on your bridge to authenticate Huegasm.
|
||||
{{else}}
|
||||
You failed to press the button in time. <a class="no-text-decoration" href="#" {{action 'retry'}}>RETRY</a>
|
||||
{{/if}}
|
||||
|
|
@ -17,7 +17,7 @@
|
|||
{{/unless}}
|
||||
|
||||
{{#if bridgeFindMultiple}}
|
||||
<p>Huegasm found multiple hue bridges. <br> Please select the one you want to use for this application.</p>
|
||||
<p>Huegasm found multiple hue bridges. <br> Please select the one you want to use for Huegasm.</p>
|
||||
|
||||
<div id="bridge-button-group">
|
||||
{{#each multipleBridgeIps as |bridge|}}
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ export default Mixin.create({
|
|||
|
||||
beatOptions: {
|
||||
threshold: {
|
||||
range: {min: 0, max: 0.5},
|
||||
range: { min: 0, max: 0.5 },
|
||||
step: 0.01,
|
||||
defaultValue: 0.3,
|
||||
pips: {
|
||||
|
|
@ -30,23 +30,23 @@ export default Mixin.create({
|
|||
values: [0, 0.25, 0.5],
|
||||
density: 10,
|
||||
format: {
|
||||
to: function ( value ) {
|
||||
if(value === 0) {
|
||||
value = 'More';
|
||||
} else if(value === 0.25) {
|
||||
to: function (value) {
|
||||
if (value === 0) {
|
||||
value = 'High';
|
||||
} else if (value === 0.25) {
|
||||
value = '';
|
||||
} else {
|
||||
value = 'Less';
|
||||
value = 'Low';
|
||||
}
|
||||
|
||||
return value;
|
||||
},
|
||||
from: function ( value ) { return value; }
|
||||
from: function (value) { return value; }
|
||||
}
|
||||
}
|
||||
},
|
||||
hueRange: {
|
||||
range: {min: 0, max: 65535},
|
||||
range: { min: 0, max: 65535 },
|
||||
step: 1,
|
||||
defaultValue: 0.3,
|
||||
pips: {
|
||||
|
|
@ -54,10 +54,10 @@ export default Mixin.create({
|
|||
values: [0, 25500, 46920, 65535],
|
||||
density: 10,
|
||||
format: {
|
||||
to: function ( value ) {
|
||||
if(value === 0 || value === 65535) {
|
||||
to: function (value) {
|
||||
if (value === 0 || value === 65535) {
|
||||
value = 'Red';
|
||||
} else if(value === 25500 ) {
|
||||
} else if (value === 25500) {
|
||||
value = 'Green';
|
||||
} else {
|
||||
value = 'Blue';
|
||||
|
|
@ -65,12 +65,12 @@ export default Mixin.create({
|
|||
|
||||
return value;
|
||||
},
|
||||
from: function ( value ) { return value; }
|
||||
from: function (value) { return value; }
|
||||
}
|
||||
}
|
||||
},
|
||||
brightnessRange: {
|
||||
range: {min: 1, max: 254},
|
||||
range: { min: 1, max: 254 },
|
||||
step: 1,
|
||||
defaultValue: 0,
|
||||
pips: {
|
||||
|
|
@ -78,8 +78,16 @@ export default Mixin.create({
|
|||
values: [1, 50, 100, 150, 200, 254],
|
||||
density: 10,
|
||||
format: {
|
||||
to: function ( value ) { return value; },
|
||||
from: function ( value ) { return value; }
|
||||
to: function (value) {
|
||||
if (value === 50) {
|
||||
value = 20;
|
||||
} else if (value === 100) {
|
||||
value = 40;
|
||||
} else {
|
||||
value = 'Low';
|
||||
}
|
||||
},
|
||||
from: function (value) { return value; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -99,8 +107,6 @@ export default Mixin.create({
|
|||
playerBottomDisplayed: true,
|
||||
dragging: false,
|
||||
draggingOverPlayListArea: false,
|
||||
audioStream: null,
|
||||
dimmerOn: false,
|
||||
isShowingAddSoundCloudModal: false,
|
||||
|
||||
colorloopMode: false,
|
||||
|
|
@ -133,26 +139,26 @@ export default Mixin.create({
|
|||
SC_CLIENT_ID: 'aeec0034f58ecd85c2bd1deaecc41594',
|
||||
scUserNotSupportedHtml: '<div class="alert alert-danger" role="alert">SoundCloud user URLs are not supported.</div>',
|
||||
tooManySoundCloudFuckUps: '<div class="alert alert-danger" role="alert">The SoundCloud API is not seving the audio properly. More details <a href="https://www.soundcloudcommunity.com/soundcloud/topics/some-soundcloud-cdn-hosted-tracks-dont-have-access-control-allow-origin-header" target="_blank" rel="noopener noreferrer">HERE</a>.</div>',
|
||||
notStreamableHtml(fileNames){
|
||||
let html = '<div class="alert alert-danger" role="alert">The following file(s) could not be added because they are not allowed to be streamed:<br>' + fileNames.toString().replace(/,/g, '<br>') + '</div>';
|
||||
notStreamableHtml(fileNames) {
|
||||
let html = '<div class="alert alert-danger" role="alert">The following file(s) could not be added because they are not allowed to be streamed:<br>' + fileNames.toString().replace(/,/g, '<br>') + '</div>';
|
||||
|
||||
return html;
|
||||
},
|
||||
urlNotFoundHtml(url){
|
||||
urlNotFoundHtml(url) {
|
||||
return '<div class="alert alert-danger" role="alert">The URL ( ' + url + ' ) could not be resolved.</div>';
|
||||
},
|
||||
failedToPlayFileHtml(fileName){
|
||||
failedToPlayFileHtml(fileName) {
|
||||
return '<div class="alert alert-danger" role="alert">Failed to play file ( ' + fileName + ' ).</div>';
|
||||
},
|
||||
failedToDecodeFileHtml(fileName){
|
||||
failedToDecodeFileHtml(fileName) {
|
||||
return '<div class="alert alert-danger" role="alert">Failed to decode file ( ' + fileName + ' ).</div>';
|
||||
},
|
||||
|
||||
scUrl: computed('playQueuePointer', 'playQueue.[]', function(){
|
||||
scUrl: computed('playQueuePointer', 'playQueue.[]', function () {
|
||||
let rtn = null,
|
||||
currentSong = this.get('playQueue')[this.get('playQueuePointer')];
|
||||
|
||||
if(currentSong && currentSong.scUrl){
|
||||
if (currentSong && currentSong.scUrl) {
|
||||
rtn = currentSong.scUrl;
|
||||
}
|
||||
|
||||
|
|
@ -161,11 +167,11 @@ export default Mixin.create({
|
|||
|
||||
playQueueEmpty: computed.empty('playQueue'),
|
||||
playQueueNotEmpty: computed.notEmpty('playQueue'),
|
||||
playQueueMultiple: computed('playQueue.[]', function(){
|
||||
playQueueMultiple: computed('playQueue.[]', function () {
|
||||
return this.get('playQueue').length > 1;
|
||||
}),
|
||||
|
||||
seekPosition: computed('timeElapsed', 'timeTotal', function(){
|
||||
seekPosition: computed('timeElapsed', 'timeTotal', function () {
|
||||
let timeTotal = this.get('timeTotal'),
|
||||
timeElapsed = this.get('timeElapsed');
|
||||
|
||||
|
|
@ -173,21 +179,21 @@ export default Mixin.create({
|
|||
return 0;
|
||||
}
|
||||
|
||||
return timeElapsed/timeTotal*100;
|
||||
return timeElapsed / timeTotal * 100;
|
||||
}),
|
||||
|
||||
largeArtworkPic: computed('playQueuePointer', 'currentVisName', function(){
|
||||
largeArtworkPic: computed('playQueuePointer', 'currentVisName', function () {
|
||||
let pic = '',
|
||||
currentVisName = this.get('currentVisName'),
|
||||
playQueuePointer = this.get('playQueuePointer'),
|
||||
playQueue = this.get('playQueue');
|
||||
|
||||
if(playQueuePointer !== -1 && currentVisName === 'None'){
|
||||
if (playQueuePointer !== -1 && currentVisName === 'None') {
|
||||
let song = playQueue[playQueuePointer];
|
||||
if(!isNone(song.picture)){
|
||||
if (!isNone(song.picture)) {
|
||||
pic = song.picture;
|
||||
|
||||
if(song.scUrl){
|
||||
if (song.scUrl) {
|
||||
pic = pic.replace('67x67', '500x500');
|
||||
}
|
||||
}
|
||||
|
|
@ -196,91 +202,91 @@ export default Mixin.create({
|
|||
return pic;
|
||||
}),
|
||||
|
||||
repeatIcon: computed('repeat', function() {
|
||||
if(this.get('repeat') === 2) {
|
||||
repeatIcon: computed('repeat', function () {
|
||||
if (this.get('repeat') === 2) {
|
||||
return 'repeat-one';
|
||||
}
|
||||
|
||||
return 'repeat';
|
||||
}),
|
||||
|
||||
playingIcon: computed('playing', function() {
|
||||
if(this.get('playing')){
|
||||
playingIcon: computed('playing', function () {
|
||||
if (this.get('playing')) {
|
||||
return 'pause';
|
||||
} else if(this.get('timeElapsed') === this.get('timeTotal') && this.get('timeTotal') !== 0){
|
||||
} else if (this.get('timeElapsed') === this.get('timeTotal') && this.get('timeTotal') !== 0) {
|
||||
return 'replay';
|
||||
} else {
|
||||
return 'play-arrow';
|
||||
}
|
||||
}),
|
||||
|
||||
playerAreaClickIcon: computed('playing', function() {
|
||||
if(this.get('playing')){
|
||||
playerAreaClickIcon: computed('playing', function () {
|
||||
if (this.get('playing')) {
|
||||
return 'play-arrow';
|
||||
} else {
|
||||
return 'pause';
|
||||
}
|
||||
}),
|
||||
|
||||
playListAreaClass: computed('dragging', 'draggingOverPlayListArea', 'dimmerOn', function(){
|
||||
playListAreaClass: computed('dragging', 'draggingOverPlayListArea', 'dimmerOn', function () {
|
||||
let classes = 'pointer';
|
||||
|
||||
if(this.get('dragging')){
|
||||
if (this.get('dragging')) {
|
||||
classes += ' drag-here-highlight';
|
||||
}
|
||||
|
||||
if(this.get('draggingOverPlayListArea')){
|
||||
if (this.get('draggingOverPlayListArea')) {
|
||||
classes += ' dragging-over';
|
||||
}
|
||||
|
||||
if(this.get('dimmerOn')){
|
||||
if (this.get('dimmerOn')) {
|
||||
classes += ' dimmerOn';
|
||||
}
|
||||
|
||||
return classes;
|
||||
}),
|
||||
|
||||
dimmerOnClass: computed('dimmerOn', function(){
|
||||
dimmerOnClass: computed('dimmerOn', function () {
|
||||
return this.get('dimmerOn') ? 'dimmerOn' : null;
|
||||
}),
|
||||
|
||||
repeatClass: computed('repeat', function(){
|
||||
repeatClass: computed('repeat', function () {
|
||||
return this.get('repeat') !== 0 ? 'player-control-icon active' : 'player-control-icon';
|
||||
}),
|
||||
|
||||
shuffleClass: computed('shuffle', function(){
|
||||
shuffleClass: computed('shuffle', function () {
|
||||
return this.get('shuffle') ? 'player-control-icon active' : 'player-control-icon';
|
||||
}),
|
||||
|
||||
beatDetectionAreaArrowIcon: computed('playerBottomDisplayed', function(){
|
||||
if(!this.get('playerBottomDisplayed')){
|
||||
beatDetectionAreaArrowIcon: computed('playerBottomDisplayed', function () {
|
||||
if (!this.get('playerBottomDisplayed')) {
|
||||
return 'keyboard-arrow-down';
|
||||
} else {
|
||||
return 'keyboard-arrow-up';
|
||||
}
|
||||
}),
|
||||
|
||||
timeElapsedTxt: computed('timeElapsed', function(){
|
||||
timeElapsedTxt: computed('timeElapsed', function () {
|
||||
return this.formatTime(this.get('timeElapsed'));
|
||||
}),
|
||||
|
||||
timeTotalTxt: computed('timeTotal', function() {
|
||||
timeTotalTxt: computed('timeTotal', function () {
|
||||
return this.formatTime(this.get('timeTotal'));
|
||||
}),
|
||||
|
||||
onPlayQueueChange: observer('playQueue.length', function(){
|
||||
onPlayQueueChange: observer('playQueue.length', function () {
|
||||
let playQueueLength = this.get('playQueue.length');
|
||||
|
||||
if(playQueueLength > this.get('oldPlayQueueLength')){
|
||||
run.once(this, ()=>{
|
||||
run.next(this, function() {
|
||||
$(`.track${playQueueLength-1}`).velocity('scroll', { container: $('#play-list-area'), duration: 200 });
|
||||
if (playQueueLength > this.get('oldPlayQueueLength')) {
|
||||
run.once(this, () => {
|
||||
run.next(this, function () {
|
||||
$(`.track${playQueueLength - 1}`).velocity('scroll', { container: $('#play-list-area'), duration: 200 });
|
||||
Ps.update(document.getElementById('play-list-area'));
|
||||
});
|
||||
});
|
||||
} else {
|
||||
run.once(this, ()=>{
|
||||
run.next(this, function() {
|
||||
run.once(this, () => {
|
||||
run.next(this, function () {
|
||||
Ps.update(document.getElementById('play-list-area'));
|
||||
});
|
||||
});
|
||||
|
|
@ -289,17 +295,17 @@ export default Mixin.create({
|
|||
this.set('oldPlayQueueLength', playQueueLength);
|
||||
}),
|
||||
|
||||
onColorloopModeChange: observer('colorloopMode', 'playing', function(){
|
||||
onColorloopModeChange: observer('colorloopMode', 'playing', function () {
|
||||
this.set('colorLoopOn', this.get('playing') && this.get('colorloopMode'));
|
||||
}),
|
||||
|
||||
onOptionChange: observer('flashingTransitions', 'playQueue.[]', 'playQueuePointer', 'colorloopMode', function(self, option){
|
||||
onOptionChange: observer('flashingTransitions', 'playQueue.[]', 'playQueuePointer', 'colorloopMode', function (self, option) {
|
||||
option = option.replace('.[]', '');
|
||||
let value = this.get(option);
|
||||
|
||||
// can't really save local music
|
||||
if(option === 'playQueue'){
|
||||
value = value.filter((song)=>{
|
||||
if (option === 'playQueue') {
|
||||
value = value.filter((song) => {
|
||||
return !song.url.startsWith('blob:');
|
||||
});
|
||||
}
|
||||
|
|
@ -307,9 +313,9 @@ export default Mixin.create({
|
|||
this.get('storage').set('huegasm.' + option, value);
|
||||
}),
|
||||
|
||||
formatTime(time){
|
||||
return this.pad(Math.floor(time/60), 2) + ':' + this.pad(time%60, 2);
|
||||
formatTime(time) {
|
||||
return this.pad(Math.floor(time / 60), 2) + ':' + this.pad(time % 60, 2);
|
||||
},
|
||||
|
||||
pad(num, size){ return ('000000000' + num).substr(-size); }
|
||||
pad(num, size) { return ('000000000' + num).substr(-size); }
|
||||
});
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@
|
|||
}
|
||||
|
||||
body, button {
|
||||
font-family: 'Slabo 27px', serif;
|
||||
font-family: 'Raleway', sans-serif;
|
||||
}
|
||||
|
||||
.alert {
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@
|
|||
text-align: right;
|
||||
position: absolute;
|
||||
top: 5px;
|
||||
right: 10px;
|
||||
right: -10px;
|
||||
transform: scale(1.1);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@
|
|||
.light-text {
|
||||
width: 60px;
|
||||
word-wrap: break-word;
|
||||
padding: 0 10px;
|
||||
padding: 0 7px;
|
||||
&.light-inactive::before {
|
||||
left: 10px;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ md-checkbox .md-label {
|
|||
}
|
||||
|
||||
.md-button {
|
||||
font-size: 13px;
|
||||
flex-direction: unset;
|
||||
span {
|
||||
width: 100%;
|
||||
|
|
|
|||
|
|
@ -1,67 +1,67 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<title>Huegasm</title>
|
||||
<meta name="description" content="Huegasm is a free web application for managing and synchronizing your Philips Hue lights with the beat of your music.">
|
||||
<meta name="keywords" content="huegasm,hue,philips hue,lights,ambience,music player">
|
||||
<meta name="author" content="Egor Philippov">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
|
||||
<script type="application/ld+json">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<title>Huegasm</title>
|
||||
<meta name="description" content="Huegasm is a free web application for managing and synchronizing your Philips Hue lights with the beat of your music.">
|
||||
<meta name="keywords" content="huegasm,hue,philips hue,lights,ambience,music player">
|
||||
<meta name="author" content="Egor Philippov">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
|
||||
<script type="application/ld+json">
|
||||
{
|
||||
"@context": "http://schema.org",
|
||||
"@type": "WebSite",
|
||||
"name": "Huegasm",
|
||||
"url": "http://www.huegasm.com/"
|
||||
}
|
||||
</script>
|
||||
</script>
|
||||
|
||||
<!--Open graph meta tags -->
|
||||
<meta property="og:title" content="Huegasm" />
|
||||
<meta property="og:type" content="website" />
|
||||
<meta property="og:site_name" content="Huegasm" />
|
||||
<meta property="og:url" content="http://www.huegasm.com/" />
|
||||
<meta property="og:image" content="/mstile-144x144.png" />
|
||||
<!--Open graph meta tags -->
|
||||
<meta property="og:title" content="Huegasm" />
|
||||
<meta property="og:type" content="website" />
|
||||
<meta property="og:site_name" content="Huegasm" />
|
||||
<meta property="og:url" content="http://www.huegasm.com/" />
|
||||
<meta property="og:image" content="/mstile-144x144.png" />
|
||||
|
||||
<link type="text/plain" rel="author" href="http://www.huegasm.com/humans.txt" />
|
||||
<link type="text/plain" rel="author" href="http://www.huegasm.com/humans.txt" /> {{content-for 'head'}}
|
||||
|
||||
{{content-for 'head'}}
|
||||
<link href="https://fonts.googleapis.com/css?family=Open+Sans|Raleway" rel="stylesheet">
|
||||
|
||||
<link href='//fonts.googleapis.com/css?family=Slabo+27px|Open+Sans' rel='stylesheet' type='text/css'>
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png">
|
||||
<link rel="icon" type="image/png" href="/favicon-32x32.png" sizes="32x32">
|
||||
<link rel="icon" type="image/png" href="/favicon-16x16.png" sizes="16x16">
|
||||
<link rel="manifest" href="/manifest.json">
|
||||
<link rel="mask-icon" href="/safari-pinned-tab.svg" color="#5bbad5">
|
||||
<meta name="theme-color" content="#ffffff">
|
||||
|
||||
<link rel="stylesheet" integrity="" href="{{rootURL}}assets/vendor.css">
|
||||
<link rel="stylesheet" integrity="" href="{{rootURL}}assets/huegasm.css"> {{content-for 'head-footer'}}
|
||||
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png">
|
||||
<link rel="icon" type="image/png" href="/favicon-32x32.png" sizes="32x32">
|
||||
<link rel="icon" type="image/png" href="/favicon-16x16.png" sizes="16x16">
|
||||
<link rel="manifest" href="/manifest.json">
|
||||
<link rel="mask-icon" href="/safari-pinned-tab.svg" color="#5bbad5">
|
||||
<meta name="theme-color" content="#ffffff">
|
||||
<script src="https://connect.soundcloud.com/sdk/sdk-3.1.2.js"></script>
|
||||
|
||||
<link rel="stylesheet" integrity="" href="{{rootURL}}assets/vendor.css">
|
||||
<link rel="stylesheet" integrity="" href="{{rootURL}}assets/huegasm.css">
|
||||
<script>
|
||||
(function (i, s, o, g, r, a, m) {
|
||||
i['GoogleAnalyticsObject'] = r; i[r] = i[r] || function () {
|
||||
(i[r].q = i[r].q || []).push(arguments)
|
||||
}, i[r].l = 1 * new Date(); a = s.createElement(o),
|
||||
m = s.getElementsByTagName(o)[0]; a.async = 1; a.src = g; m.parentNode.insertBefore(a, m)
|
||||
})(window, document, 'script', '//www.google-analytics.com/analytics.js', 'ga');
|
||||
|
||||
{{content-for 'head-footer'}}
|
||||
ga('create', 'UA-69470561-1', 'auto');
|
||||
ga('send', 'pageview');
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<script src="https://connect.soundcloud.com/sdk/sdk-3.1.2.js"></script>
|
||||
<body>
|
||||
{{content-for 'body'}}
|
||||
|
||||
<script>
|
||||
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
|
||||
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
|
||||
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
|
||||
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
|
||||
<script src="{{rootURL}}assets/vendor.js"></script>
|
||||
<script src="{{rootURL}}assets/huegasm.js"></script>
|
||||
|
||||
ga('create', 'UA-69470561-1', 'auto');
|
||||
ga('send', 'pageview');
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
{{content-for 'body'}}
|
||||
{{content-for 'body-footer'}}
|
||||
</body>
|
||||
|
||||
<script src="{{rootURL}}assets/vendor.js"></script>
|
||||
<script src="{{rootURL}}assets/huegasm.js"></script>
|
||||
|
||||
{{content-for 'body-footer'}}
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
|
|
@ -6,7 +6,7 @@
|
|||
{{#if isAuthenticating}}
|
||||
<p>
|
||||
Your bridge IP is <b>{{bridgeIp}}</b>
|
||||
<br> Press the button on your bridge to authenticate this application.
|
||||
<br> Press the button on your bridge to authenticate Huegasm.
|
||||
</p>
|
||||
{{else}}
|
||||
<p>You failed to press the button in time. <a class="no-text-decoration" href="#" {{action 'retry'}}>RETRY</a></p>
|
||||
|
|
@ -18,7 +18,7 @@
|
|||
{{/unless}}
|
||||
|
||||
{{#if bridgeFindMultiple}}
|
||||
<p>Huegasm found multiple hue bridges. <br> Please select the one you want to use for this application.</p>
|
||||
<p>Huegasm found multiple hue bridges. <br> Please select the one you want to use for Huegasm.</p>
|
||||
|
||||
<div id="bridge-button-group">
|
||||
{{#each multipleBridgeIps as |bridge|}}
|
||||
|
|
|
|||
|
|
@ -9,12 +9,12 @@ export default Component.extend({
|
|||
tagName: 'footer',
|
||||
classNames: ['footer'],
|
||||
|
||||
year: computed(function(){
|
||||
year: computed(function () {
|
||||
return new Date().getFullYear();
|
||||
}),
|
||||
|
||||
actions: {
|
||||
toggleDimmer(){
|
||||
toggleDimmer() {
|
||||
this.sendAction();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ export default Mixin.create({
|
|||
|
||||
beatOptions: {
|
||||
threshold: {
|
||||
range: {min: 0, max: 0.5},
|
||||
range: { min: 0, max: 0.5 },
|
||||
step: 0.01,
|
||||
defaultValue: 0.3,
|
||||
pips: {
|
||||
|
|
@ -31,23 +31,23 @@ export default Mixin.create({
|
|||
values: [0, 0.25, 0.5],
|
||||
density: 10,
|
||||
format: {
|
||||
to: function ( value ) {
|
||||
if(value === 0) {
|
||||
value = 'More';
|
||||
} else if(value === 0.25) {
|
||||
to: function (value) {
|
||||
if (value === 0) {
|
||||
value = 'High';
|
||||
} else if (value === 0.25) {
|
||||
value = '';
|
||||
} else {
|
||||
value = 'Less';
|
||||
value = 'Low';
|
||||
}
|
||||
|
||||
return value;
|
||||
},
|
||||
from: function ( value ) { return value; }
|
||||
from: function (value) { return value; }
|
||||
}
|
||||
}
|
||||
},
|
||||
hueRange: {
|
||||
range: {min: 0, max: 65535},
|
||||
range: { min: 0, max: 65535 },
|
||||
step: 1,
|
||||
defaultValue: 0.3,
|
||||
pips: {
|
||||
|
|
@ -55,10 +55,10 @@ export default Mixin.create({
|
|||
values: [0, 25500, 46920, 65535],
|
||||
density: 10,
|
||||
format: {
|
||||
to: function ( value ) {
|
||||
if(value === 0 || value === 65535) {
|
||||
to: function (value) {
|
||||
if (value === 0 || value === 65535) {
|
||||
value = 'Red';
|
||||
} else if(value === 25500 ) {
|
||||
} else if (value === 25500) {
|
||||
value = 'Green';
|
||||
} else {
|
||||
value = 'Blue';
|
||||
|
|
@ -66,21 +66,33 @@ export default Mixin.create({
|
|||
|
||||
return value;
|
||||
},
|
||||
from: function ( value ) { return value; }
|
||||
from: function (value) { return value; }
|
||||
}
|
||||
}
|
||||
},
|
||||
brightnessRange: {
|
||||
range: {min: 1, max: 254},
|
||||
range: { min: 1, max: 254 },
|
||||
step: 1,
|
||||
defaultValue: 0,
|
||||
pips: {
|
||||
mode: 'values',
|
||||
values: [1, 50, 100, 150, 200, 254],
|
||||
values: [1, 63, 127, 190, 254],
|
||||
density: 10,
|
||||
format: {
|
||||
to: function ( value ) { return value; },
|
||||
from: function ( value ) { return value; }
|
||||
to: function (value) {
|
||||
if (value === 63) {
|
||||
value = 25;
|
||||
} else if (value === 127) {
|
||||
value = 50;
|
||||
} else if (value === 190) {
|
||||
value = 75;
|
||||
} else if (value === 254) {
|
||||
value = 100;
|
||||
}
|
||||
|
||||
return value;
|
||||
},
|
||||
from: function (value) { return value; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -101,8 +113,6 @@ export default Mixin.create({
|
|||
dragging: false,
|
||||
draggingOverPlayListArea: false,
|
||||
dragLeaveTimeoutHandle: null,
|
||||
audioStream: null,
|
||||
dimmerOn: false,
|
||||
isShowingAddSoundCloudModal: false,
|
||||
|
||||
colorloopMode: false,
|
||||
|
|
@ -136,26 +146,26 @@ export default Mixin.create({
|
|||
SC_CLIENT_ID: 'aeec0034f58ecd85c2bd1deaecc41594',
|
||||
scUserNotSupportedHtml: '<div class="alert alert-danger" role="alert">SoundCloud user URLs are not supported.</div>',
|
||||
tooManySoundCloudFuckUps: '<div class="alert alert-danger" role="alert">The SoundCloud API is not seving the audio properly. More details <a href="https://www.soundcloudcommunity.com/soundcloud/topics/some-soundcloud-cdn-hosted-tracks-dont-have-access-control-allow-origin-header" target="_blank" rel="noopener noreferrer">HERE</a>.</div>',
|
||||
notStreamableHtml(fileNames){
|
||||
let html = '<div class="alert alert-danger" role="alert">The following file(s) could not be added because they are not allowed to be streamed:<br>' + fileNames.toString().replace(/,/g, '<br>') + '</div>';
|
||||
notStreamableHtml(fileNames) {
|
||||
let html = '<div class="alert alert-danger" role="alert">The following file(s) could not be added because they are not allowed to be streamed:<br>' + fileNames.toString().replace(/,/g, '<br>') + '</div>';
|
||||
|
||||
return html;
|
||||
},
|
||||
urlNotFoundHtml(url){
|
||||
urlNotFoundHtml(url) {
|
||||
return '<div class="alert alert-danger" role="alert">The URL ( ' + url + ' ) could not be resolved.</div>';
|
||||
},
|
||||
failedToPlayFileHtml(fileName){
|
||||
failedToPlayFileHtml(fileName) {
|
||||
return '<div class="alert alert-danger" role="alert">Failed to play file ( ' + fileName + ' ).</div>';
|
||||
},
|
||||
failedToDecodeFileHtml(fileName){
|
||||
failedToDecodeFileHtml(fileName) {
|
||||
return '<div class="alert alert-danger" role="alert">Failed to decode file ( ' + fileName + ' ).</div>';
|
||||
},
|
||||
|
||||
scUrl: computed('playQueuePointer', 'playQueue.[]', function(){
|
||||
scUrl: computed('playQueuePointer', 'playQueue.[]', function () {
|
||||
let rtn = null,
|
||||
currentSong = this.get('playQueue')[this.get('playQueuePointer')];
|
||||
|
||||
if(currentSong && currentSong.scUrl){
|
||||
if (currentSong && currentSong.scUrl) {
|
||||
rtn = currentSong.scUrl;
|
||||
}
|
||||
|
||||
|
|
@ -164,11 +174,11 @@ export default Mixin.create({
|
|||
|
||||
playQueueEmpty: computed.empty('playQueue'),
|
||||
playQueueNotEmpty: computed.notEmpty('playQueue'),
|
||||
playQueueMultiple: computed('playQueue.[]', function(){
|
||||
playQueueMultiple: computed('playQueue.[]', function () {
|
||||
return this.get('playQueue').length > 1;
|
||||
}),
|
||||
|
||||
seekPosition: computed('timeElapsed', 'timeTotal', function(){
|
||||
seekPosition: computed('timeElapsed', 'timeTotal', function () {
|
||||
let timeTotal = this.get('timeTotal'),
|
||||
timeElapsed = this.get('timeElapsed');
|
||||
|
||||
|
|
@ -176,21 +186,21 @@ export default Mixin.create({
|
|||
return 0;
|
||||
}
|
||||
|
||||
return timeElapsed/timeTotal*100;
|
||||
return timeElapsed / timeTotal * 100;
|
||||
}),
|
||||
|
||||
largeArtworkPic: computed('playQueuePointer', 'currentVisName', function(){
|
||||
largeArtworkPic: computed('playQueuePointer', 'currentVisName', function () {
|
||||
let pic = '',
|
||||
currentVisName = this.get('currentVisName'),
|
||||
playQueuePointer = this.get('playQueuePointer'),
|
||||
playQueue = this.get('playQueue');
|
||||
|
||||
if(playQueuePointer !== -1 && currentVisName === 'None'){
|
||||
if (playQueuePointer !== -1 && currentVisName === 'None') {
|
||||
let song = playQueue[playQueuePointer];
|
||||
if(!isNone(song.picture)){
|
||||
if (!isNone(song.picture)) {
|
||||
pic = song.picture;
|
||||
|
||||
if(song.scUrl){
|
||||
if (song.scUrl) {
|
||||
pic = pic.replace('67x67', '500x500');
|
||||
}
|
||||
}
|
||||
|
|
@ -199,73 +209,73 @@ export default Mixin.create({
|
|||
return pic;
|
||||
}),
|
||||
|
||||
repeatIcon: computed('repeat', function() {
|
||||
if(this.get('repeat') === 2) {
|
||||
repeatIcon: computed('repeat', function () {
|
||||
if (this.get('repeat') === 2) {
|
||||
return 'repeat-one';
|
||||
}
|
||||
|
||||
return 'repeat';
|
||||
}),
|
||||
|
||||
playingIcon: computed('playing', function() {
|
||||
if(this.get('playing')){
|
||||
playingIcon: computed('playing', function () {
|
||||
if (this.get('playing')) {
|
||||
return 'pause';
|
||||
} else if(this.get('timeElapsed') === this.get('timeTotal') && this.get('timeTotal') !== 0){
|
||||
} else if (this.get('timeElapsed') === this.get('timeTotal') && this.get('timeTotal') !== 0) {
|
||||
return 'replay';
|
||||
} else {
|
||||
return 'play-arrow';
|
||||
}
|
||||
}),
|
||||
|
||||
playerAreaClickIcon: computed('playing', function() {
|
||||
if(this.get('playing')){
|
||||
playerAreaClickIcon: computed('playing', function () {
|
||||
if (this.get('playing')) {
|
||||
return 'play-arrow';
|
||||
} else {
|
||||
return 'pause';
|
||||
}
|
||||
}),
|
||||
|
||||
playListAreaClass: computed('dragging', 'draggingOverPlayListArea', 'dimmerOn', function(){
|
||||
playListAreaClass: computed('dragging', 'draggingOverPlayListArea', 'dimmerOn', function () {
|
||||
let classes = 'pointer';
|
||||
|
||||
if(this.get('dragging')){
|
||||
if (this.get('dragging')) {
|
||||
classes += ' drag-here-highlight';
|
||||
}
|
||||
|
||||
if(this.get('draggingOverPlayListArea')){
|
||||
if (this.get('draggingOverPlayListArea')) {
|
||||
classes += ' dragging-over';
|
||||
}
|
||||
|
||||
if(this.get('dimmerOn')){
|
||||
if (this.get('dimmerOn')) {
|
||||
classes += ' dimmerOn';
|
||||
}
|
||||
|
||||
return classes;
|
||||
}),
|
||||
|
||||
dimmerOnClass: computed('dimmerOn', function(){
|
||||
dimmerOnClass: computed('dimmerOn', function () {
|
||||
return this.get('dimmerOn') ? 'dimmerOn' : null;
|
||||
}),
|
||||
|
||||
volumeMutedClass: computed('volumeMuted', function(){
|
||||
volumeMutedClass: computed('volumeMuted', function () {
|
||||
let classes = 'player-control-icon volumeButton';
|
||||
|
||||
if(this.get('volumeMuted')){
|
||||
if (this.get('volumeMuted')) {
|
||||
classes += ' active';
|
||||
}
|
||||
|
||||
return classes;
|
||||
}),
|
||||
|
||||
repeatClass: computed('repeat', function(){
|
||||
repeatClass: computed('repeat', function () {
|
||||
return this.get('repeat') !== 0 ? 'player-control-icon active' : 'player-control-icon';
|
||||
}),
|
||||
|
||||
shuffleClass: computed('shuffle', function(){
|
||||
shuffleClass: computed('shuffle', function () {
|
||||
return this.get('shuffle') ? 'player-control-icon active' : 'player-control-icon';
|
||||
}),
|
||||
|
||||
volumeIcon: computed('volumeMuted', 'volume', function() {
|
||||
volumeIcon: computed('volumeMuted', 'volume', function () {
|
||||
let volume = this.get('volume');
|
||||
|
||||
if (this.get('volumeMuted')) {
|
||||
|
|
@ -279,29 +289,29 @@ export default Mixin.create({
|
|||
}
|
||||
}),
|
||||
|
||||
beatDetectionAreaArrowIcon: computed('playerBottomDisplayed', function(){
|
||||
if(!this.get('playerBottomDisplayed')){
|
||||
beatDetectionAreaArrowIcon: computed('playerBottomDisplayed', function () {
|
||||
if (!this.get('playerBottomDisplayed')) {
|
||||
return 'keyboard-arrow-down';
|
||||
} else {
|
||||
return 'keyboard-arrow-up';
|
||||
}
|
||||
}),
|
||||
|
||||
timeElapsedTxt: computed('timeElapsed', function(){
|
||||
timeElapsedTxt: computed('timeElapsed', function () {
|
||||
return this.formatTime(this.get('timeElapsed'));
|
||||
}),
|
||||
|
||||
timeTotalTxt: computed('timeTotal', function() {
|
||||
timeTotalTxt: computed('timeTotal', function () {
|
||||
return this.formatTime(this.get('timeTotal'));
|
||||
}),
|
||||
|
||||
onPlayQueueChange: observer('playQueue.length', function(){
|
||||
onPlayQueueChange: observer('playQueue.length', function () {
|
||||
let playQueueLength = this.get('playQueue.length');
|
||||
|
||||
if(playQueueLength > this.get('oldPlayQueueLength')){
|
||||
run.once(this, ()=>{
|
||||
run.next(this, function() {
|
||||
$(`.track${playQueueLength-1}`).velocity('scroll', { container: $('#play-list-area'), duration: 200 });
|
||||
if (playQueueLength > this.get('oldPlayQueueLength')) {
|
||||
run.once(this, () => {
|
||||
run.next(this, function () {
|
||||
$(`.track${playQueueLength - 1}`).velocity('scroll', { container: $('#play-list-area'), duration: 200 });
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
@ -309,17 +319,17 @@ export default Mixin.create({
|
|||
this.set('oldPlayQueueLength', playQueueLength);
|
||||
}),
|
||||
|
||||
onColorloopModeChange: observer('colorloopMode', 'playing', function(){
|
||||
onColorloopModeChange: observer('colorloopMode', 'playing', function () {
|
||||
this.set('colorLoopOn', this.get('playing') && this.get('colorloopMode'));
|
||||
}),
|
||||
|
||||
onOptionChange: observer('flashingTransitions', 'playQueue.[]', 'playQueuePointer', 'colorloopMode', function(self, option){
|
||||
onOptionChange: observer('flashingTransitions', 'playQueue.[]', 'playQueuePointer', 'colorloopMode', function (self, option) {
|
||||
option = option.replace('.[]', '');
|
||||
let value = this.get(option);
|
||||
|
||||
// can't really save local music
|
||||
if(option === 'playQueue'){
|
||||
value = value.filter((song)=>{
|
||||
if (option === 'playQueue') {
|
||||
value = value.filter((song) => {
|
||||
return !song.url.startsWith('blob:');
|
||||
});
|
||||
}
|
||||
|
|
@ -350,30 +360,30 @@ export default Mixin.create({
|
|||
this.changeTooltipText(type, tooltipTxt);
|
||||
})),
|
||||
|
||||
onVolumeMutedChange: on('init', observer('volumeMuted', function() {
|
||||
onVolumeMutedChange: on('init', observer('volumeMuted', function () {
|
||||
let tooltipTxt = 'Mute', type = 'volumeMuted',
|
||||
volumeMuted = this.get(type), dancer = this.get('dancer'),
|
||||
volume=0;
|
||||
volume = 0;
|
||||
|
||||
if (volumeMuted) {
|
||||
tooltipTxt = 'Unmute';
|
||||
volume = 0;
|
||||
} else {
|
||||
volume = this.get('volume')/100;
|
||||
volume = this.get('volume') / 100;
|
||||
}
|
||||
|
||||
if(this.get('playing')){
|
||||
if (this.get('playing')) {
|
||||
dancer.setVolume(volume);
|
||||
}
|
||||
|
||||
this.changeTooltipText(type, tooltipTxt);
|
||||
})),
|
||||
|
||||
onPrevChange: on('init', observer('timeElapsed', 'playQueueNotEmpty', 'playQueue.[]', function() {
|
||||
if(this.get('playQueueNotEmpty')){
|
||||
onPrevChange: on('init', observer('timeElapsed', 'playQueueNotEmpty', 'playQueue.[]', function () {
|
||||
if (this.get('playQueueNotEmpty')) {
|
||||
let tooltipTxt = 'Previous', type = 'prev';
|
||||
|
||||
if(this.get('timeElapsed') > 5 || this.get('playQueue').length === 1) {
|
||||
if (this.get('timeElapsed') > 5 || this.get('playQueue').length === 1) {
|
||||
tooltipTxt = 'Replay';
|
||||
}
|
||||
|
||||
|
|
@ -386,7 +396,7 @@ export default Mixin.create({
|
|||
|
||||
if (this.get(type)) {
|
||||
tooltipTxt = 'Pause';
|
||||
} else if(this.get('timeElapsed') === this.get('timeTotal') && this.get('timeTotal') !== 0){
|
||||
} else if (this.get('timeElapsed') === this.get('timeTotal') && this.get('timeTotal') !== 0) {
|
||||
tooltipTxt = 'Replay';
|
||||
}
|
||||
|
||||
|
|
@ -399,14 +409,14 @@ export default Mixin.create({
|
|||
//change the tooltip text for hover
|
||||
$('#' + type + 'Tooltip').attr('data-original-title', text);
|
||||
|
||||
if(isNone(this.get(type + 'TooltipTxt'))) {
|
||||
if (isNone(this.get(type + 'TooltipTxt'))) {
|
||||
this.set(type + 'TooltipTxt', text);
|
||||
}
|
||||
},
|
||||
|
||||
formatTime(time){
|
||||
return this.pad(Math.floor(time/60), 2) + ':' + this.pad(time%60, 2);
|
||||
formatTime(time) {
|
||||
return this.pad(Math.floor(time / 60), 2) + ':' + this.pad(time % 60, 2);
|
||||
},
|
||||
|
||||
pad(num, size){ return ('000000000' + num).substr(-size); }
|
||||
pad(num, size) { return ('000000000' + num).substr(-size); }
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,86 +1,100 @@
|
|||
<div class="row" id="step1">
|
||||
<div id="player-area" class="col-sm-8 col-xs-12 {{if (eq "None" currentVisName) "display-icon"}}" {{action "playerAreaPlay"}}>
|
||||
<canvas id="visualization"></canvas>
|
||||
<canvas id="visualization"></canvas>
|
||||
|
||||
<div id="artwork">
|
||||
<img src={{largeArtworkPic}}>
|
||||
</div>
|
||||
<div id="artwork">
|
||||
<img src= {{largeArtworkPic}}>
|
||||
</div>
|
||||
|
||||
{{paper-icon playerAreaClickIcon id="play-notification"}}
|
||||
{{paper-icon playerAreaClickIcon id="play-notification"}}
|
||||
|
||||
<div id="player-controls">
|
||||
{{range-slider start=seekPosition min=0 max=100 connect=filledConnect id="seek-slider" on-change="seekChanged"}}
|
||||
<div id="player-controls">
|
||||
{{range-slider start=seekPosition min=0 max=100 connect=filledConnect id="seek-slider" on-change="seekChanged"}}
|
||||
|
||||
{{#if playQueueNotEmpty}}
|
||||
<span data-toggle="tooltip" data-placement="top" class="bootstrap-tooltip" id="prevTooltip"
|
||||
data-title={{prevTooltipTxt}} {{action "previous"}}>{{paper-icon "skip-previous" class="player-control-icon"}}</span><!--
|
||||
-->{{/if}}<!--
|
||||
--><span data-toggle="tooltip" data-placement="top" id="playingTooltip" class="bootstrap-tooltip"
|
||||
data-title={{playingTooltipTxt}} {{action "play"}}>{{paper-icon playingIcon class="player-control-icon"}}</span><!--
|
||||
-->{{#if playQueueMultiple}}<!--
|
||||
--><span data-toggle="tooltip" data-placement="top" class="bootstrap-tooltip"
|
||||
data-title="Next" {{action "next" true}}>{{paper-icon "skip-next" action="" class="player-control-icon"}}</span><!--
|
||||
-->{{/if}}<!--
|
||||
--><span data-toggle="tooltip" data-placement="top" class="bootstrap-tooltip" id="volumeMutedTooltip"
|
||||
data-title={{volumeMutedTooltipTxt}} {{action "volumeMutedChanged"}}>{{paper-icon icon=volumeIcon class=volumeMutedClass}}</span><!--
|
||||
{{#if playQueueNotEmpty}}
|
||||
<span data-toggle="tooltip" data-placement="top" class="bootstrap-tooltip" id="prevTooltip" data-title= {{prevTooltipTxt}}
|
||||
{{action "previous"}}>{{paper-icon "skip-previous" class="player-control-icon"}}</span>
|
||||
<!--
|
||||
-->
|
||||
{{/if}}
|
||||
<!--
|
||||
-->
|
||||
<span data-toggle="tooltip" data-placement="top" id="playingTooltip" class="bootstrap-tooltip" data-title= {{playingTooltipTxt}}
|
||||
{{action "play"}}>{{paper-icon playingIcon class="player-control-icon"}}</span>
|
||||
<!--
|
||||
-->
|
||||
{{#if playQueueMultiple}}
|
||||
<!--
|
||||
--><span data-toggle="tooltip" data-placement="top" class="bootstrap-tooltip" data-title="Next" {{action "next" true}}>{{paper-icon "skip-next" action="" class="player-control-icon"}}</span>
|
||||
<!--
|
||||
-->
|
||||
{{/if}}
|
||||
<!--
|
||||
-->
|
||||
<span data-toggle="tooltip" data-placement="top" class="bootstrap-tooltip hidden-xs" id="volumeMutedTooltip" data-title= {{volumeMutedTooltipTxt}}
|
||||
{{action "volumeMutedChanged"}}>{{paper-icon icon=volumeIcon class=volumeMutedClass}}</span>
|
||||
<!--
|
||||
-->{{range-slider start=volume min=0 max=100 connect=filledConnect on-change="volumeChanged" id="volume-bar" class="hidden-xs"}}
|
||||
|
||||
<div id="player-time-controls">{{timeElapsedTxt}} / {{timeTotalTxt}}</div>
|
||||
<div id="player-time-controls">{{timeElapsedTxt}} / {{timeTotalTxt}}</div>
|
||||
|
||||
{{#paper-menu as |menu|}}
|
||||
{{#menu.trigger}}
|
||||
{{#paper-button iconButton=true}}
|
||||
{{paper-icon "remove-red-eye" class="player-control-icon"}}
|
||||
{{/paper-button}}
|
||||
{{/menu.trigger}}
|
||||
{{#menu.content width=2 as |content|}}
|
||||
{{#each visNames as |name|}}
|
||||
{{#content.menu-item onClick=(action "setVisName" name)}}
|
||||
{{name}}
|
||||
{{#paper-menu as |menu|}}
|
||||
{{#menu.trigger}}
|
||||
{{#paper-button iconButton=true}}
|
||||
{{paper-icon "remove-red-eye" class="player-control-icon"}}
|
||||
{{/paper-button}}
|
||||
{{/menu.trigger}}
|
||||
{{#menu.content width=2 as |content|}}
|
||||
{{#each visNames as |name|}}
|
||||
{{#content.menu-item onClick=(action "setVisName" name)}}
|
||||
{{name}}
|
||||
|
||||
{{#if (eq currentVisName name)}}
|
||||
{{paper-icon "check" classNames=dimmerOnClass}}
|
||||
{{/if}}
|
||||
{{/content.menu-item}}
|
||||
{{/each}}
|
||||
{{/menu.content}}
|
||||
{{/paper-menu}}
|
||||
{{#if (eq currentVisName name)}}
|
||||
{{paper-icon "check" classNames=dimmerOnClass}}
|
||||
{{/if}}
|
||||
{{/content.menu-item}}
|
||||
{{/each}}
|
||||
{{/menu.content}}
|
||||
{{/paper-menu}}
|
||||
|
||||
{{#if scUrl}}
|
||||
<a href={{scUrl}} class="sound-cloud-link"{{action "gotoSCURL" scUrl}}>
|
||||
<img src="assets/images/sc-white.png" id="soundcloud-logo" />
|
||||
<img src="assets/images/sc-white-sm.png" id="soundcloud-logo-small" />
|
||||
</a>
|
||||
{{/if}}
|
||||
{{#if scUrl}}
|
||||
<a href= {{scUrl}} class="sound-cloud-link" {{action "gotoSCURL" scUrl}}>
|
||||
<img src="assets/images/sc-white.png" id="soundcloud-logo" />
|
||||
<img src="assets/images/sc-white-sm.png" id="soundcloud-logo-small" />
|
||||
</a>
|
||||
{{/if}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="playlist" class="col-sm-4 col-xs-12">
|
||||
<input id="file-input" type="file" accept="audio/*" multiple="true"/>
|
||||
<div id="playlist" class="col-sm-4 col-xs-12">
|
||||
<input id="file-input" type="file" accept="audio/*" multiple="true" />
|
||||
|
||||
<div id="play-list-controls">
|
||||
{{#paper-menu as |menu|}}
|
||||
{{#menu.trigger}}
|
||||
{{#paper-button iconButton=false}}
|
||||
{{paper-icon "playlist add" class="player-control-icon"}} <span id="add-new-music-label">Add new music</span>
|
||||
{{/paper-button}}
|
||||
{{/menu.trigger}}
|
||||
{{#menu.content width=3 as |content|}}
|
||||
{{#content.menu-item onClick="addLocalAudio"}}
|
||||
{{paper-icon "attachment" class=shuffleClass}} Local file
|
||||
{{/content.menu-item}}
|
||||
{{#content.menu-item onClick="toggleIsShowingAddSoundCloudModal"}}
|
||||
{{paper-icon "cloud" class=shuffleClass}} SoundCloud
|
||||
{{/content.menu-item}}
|
||||
{{/menu.content}}
|
||||
{{/paper-menu}}
|
||||
<div id="play-list-controls">
|
||||
{{#paper-menu as |menu|}}
|
||||
{{#menu.trigger}}
|
||||
{{#paper-button iconButton=false}}
|
||||
{{paper-icon "playlist add" class="player-control-icon"}} <span id="add-new-music-label">Add new music</span>
|
||||
{{/paper-button}}
|
||||
{{/menu.trigger}}
|
||||
{{#menu.content width=3 as |content|}}
|
||||
{{#content.menu-item onClick="addLocalAudio" }}
|
||||
{{paper-icon "attachment" class=shuffleClass}} Local file
|
||||
{{/content.menu-item}}
|
||||
{{#content.menu-item onClick="toggleIsShowingAddSoundCloudModal" }}
|
||||
{{paper-icon "cloud" class=shuffleClass}} SoundCloud
|
||||
{{/content.menu-item}}
|
||||
{{/menu.content}}
|
||||
{{/paper-menu}}
|
||||
|
||||
<span data-toggle="tooltip" data-placement="top auto" class="bootstrap-tooltip" id="shuffleTooltip" data-title={{shuffleTooltipTxt}} {{action "shuffleChanged"}}>{{paper-icon "shuffle" class=shuffleClass}}</span>
|
||||
<span data-toggle="tooltip" data-placement="top auto" class="bootstrap-tooltip" id="repeatTooltip" data-title={{repeatTooltipTxt}} {{action "repeatChanged"}}>{{paper-icon repeatIcon class=repeatClass}}</span>
|
||||
<span data-toggle="tooltip" data-placement="top auto" class="bootstrap-tooltip hidden-xs" data-title="Clear playlist" {{action "clearPlaylist"}}>{{paper-icon "clear-all" class="player-control-icon"}}</span>
|
||||
</div>
|
||||
<span data-toggle="tooltip" data-placement="top auto" class="bootstrap-tooltip" id="shuffleTooltip" data-title= {{shuffleTooltipTxt}}
|
||||
{{action "shuffleChanged"}}>{{paper-icon "shuffle" class=shuffleClass}}</span>
|
||||
<span data-toggle="tooltip" data-placement="top auto" class="bootstrap-tooltip" id="repeatTooltip" data-title= {{repeatTooltipTxt}}
|
||||
{{action "repeatChanged"}}>{{paper-icon repeatIcon class=repeatClass}}</span>
|
||||
<span data-toggle="tooltip" data-placement="top auto" class="bootstrap-tooltip hidden-xs" data-title="Clear playlist" {{action "clearPlaylist"}}>{{paper-icon "clear-all" class="player-control-icon"}}</span>
|
||||
</div>
|
||||
|
||||
<div id="play-list-area" class={{playListAreaClass}} {{action "addLocalAudio"}} {{action "playerListAreaDragOver" on="dragOver"}} {{action "playerListAreaDragLeave" on="dragLeave"}} {{action "dropFiles" on="drop"}}>
|
||||
<div id="play-list-area" class= {{playListAreaClass}} {{action "addLocalAudio"}} {{action "playerListAreaDragOver" on="dragOver"}}
|
||||
{{action "playerListAreaDragLeave" on="dragLeave"}} {{action "dropFiles" on="drop"}}>
|
||||
{{#if (or playQueueEmpty dragging)}}
|
||||
<div id="dragHere">
|
||||
{{#if dragging}}
|
||||
|
|
@ -95,7 +109,7 @@
|
|||
{{#each playQueue as |item index|}}
|
||||
<div class="playlist-item pointer track{{index}} {{if (eq index playQueuePointer) "active"}} {{if dragging "hidden"}}" {{action "goToSong" index true bubbles=false}}>
|
||||
{{#if item.picture}}
|
||||
<img class="album-art" src={{item.picture}}>
|
||||
<img class="album-art" src= {{item.picture}}>
|
||||
{{else}}
|
||||
<img class="album-art" src="assets/images/missingArtwork.png">
|
||||
{{/if}}
|
||||
|
|
@ -105,9 +119,9 @@
|
|||
<div class="song-title">{{item.title}}</div>
|
||||
<div class="song-artist">
|
||||
{{#if item.artistUrl}}
|
||||
<a href="#" {{action "gotoURL" item.artistUrl bubbles=false}}>{{item.artist}}</a>
|
||||
<a href="#" {{action "gotoURL" item.artistUrl bubbles=false}}>{{item.artist}}</a>
|
||||
{{else}}
|
||||
{{item.artist}}
|
||||
{{item.artist}}
|
||||
{{/if}}
|
||||
</div>
|
||||
{{else}}
|
||||
|
|
@ -115,10 +129,11 @@
|
|||
{{/if}}
|
||||
</div>
|
||||
|
||||
<span data-toggle="tooltip" data-placement="top auto" data-title="Remove" data-container="body" class="audio-remove-button pointer bootstrap-tooltip" {{action "removeAudio" index bubbles=false}}>{{paper-icon "close" classNames="close"}}</span>
|
||||
<span data-toggle="tooltip" data-placement="top auto" data-title="Remove" data-container="body" class="audio-remove-button pointer bootstrap-tooltip"
|
||||
{{action "removeAudio" index bubbles=false}}>{{paper-icon "close" classNames="close"}}</span>
|
||||
</div>
|
||||
{{/each}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
@ -131,44 +146,53 @@
|
|||
<div id="player-bottom" class="row {{if dimmerOn "dimmerOn"}} {{if playerBottomDisplayed "display-flex"}}">
|
||||
<div id="beat-area" class="col-sm-7 col-xs-12">
|
||||
{{#if usingBeatPreferences}}
|
||||
<span data-toggle="tooltip" data-placement="top" data-title="Using the saved sensitivity preference from the last time you listened to this song" class="bootstrap-tooltip" id="save-beat-preferences-star">
|
||||
{{paper-icon "star" class=dimmerOnClass}}
|
||||
</span>
|
||||
<span data-toggle="tooltip" data-placement="top" data-title="Using the saved sensitivity preference from the last time you listened to this song"
|
||||
class="bootstrap-tooltip" id="save-beat-preferences-star">
|
||||
{{paper-icon "star" class=dimmerOnClass}}
|
||||
</span>
|
||||
{{/if}}
|
||||
|
||||
<div class="row" id="beat-option-row">
|
||||
<div class="beat-option col-xs-4">
|
||||
<span data-toggle="tooltip" data-placement="top" data-title="The range of hues ( colors ) that the lights may change to on beat." class="option-description bootstrap-tooltip">
|
||||
<span data-toggle="tooltip" data-placement="top" data-title="The range of hues ( colors ) that the lights may change to on beat."
|
||||
class="option-description bootstrap-tooltip">
|
||||
Hue Range
|
||||
</span>
|
||||
</span>
|
||||
|
||||
{{range-slider start=hueRange orientation="vertical" step=beatOptions.hueRange.step range=beatOptions.hueRange.range connect=hueRangeConnect on-change="hueRangeChanged" pips=beatOptions.hueRange.pips}}
|
||||
{{range-slider start=hueRange orientation="vertical" step=beatOptions.hueRange.step range=beatOptions.hueRange.range connect=hueRangeConnect
|
||||
on-change="hueRangeChanged" pips=beatOptions.hueRange.pips}}
|
||||
</div>
|
||||
|
||||
<div class="beat-option col-xs-4">
|
||||
<span data-toggle="tooltip" data-placement="top" data-title="The minimum ( off-beat ) and maximum ( on-beat ) brightness of the lights" class="option-description bootstrap-tooltip">
|
||||
<span data-toggle="tooltip" data-placement="top" data-title="The minimum ( off-beat ) and maximum ( on-beat ) brightness of the lights"
|
||||
class="option-description bootstrap-tooltip">
|
||||
Brightness Range
|
||||
</span>
|
||||
</span>
|
||||
|
||||
{{range-slider start=brightnessRange orientation="vertical" step=beatOptions.brightnessRange.step range=beatOptions.brightnessRange.range on-change="brightnessRangeChanged" pips=beatOptions.brightnessRange.pips}}
|
||||
{{range-slider start=brightnessRange orientation="vertical" step=beatOptions.brightnessRange.step range=beatOptions.brightnessRange.range
|
||||
on-change="brightnessRangeChanged" pips=beatOptions.brightnessRange.pips}}
|
||||
</div>
|
||||
|
||||
<div id="sensitivity-settings" class="beat-option col-xs-4">
|
||||
<span data-toggle="tooltip" data-placement="top" data-title="The sensitivity of the beat detector ( more sensitivity results in more registered beats )" class="option-description bootstrap-tooltip">
|
||||
<span data-toggle="tooltip" data-placement="top" data-title="The sensitivity of the beat detector ( more sensitivity results in more registered beats )"
|
||||
class="option-description bootstrap-tooltip">
|
||||
Sensitivity
|
||||
</span>
|
||||
</span>
|
||||
|
||||
{{range-slider start=threshold orientation="vertical" step=beatOptions.threshold.step range=beatOptions.threshold.range on-change="thresholdChanged" pips=beatOptions.threshold.pips}}
|
||||
{{range-slider start=threshold orientation="vertical" step=beatOptions.threshold.step range=beatOptions.threshold.range on-change="thresholdChanged"
|
||||
pips=beatOptions.threshold.pips}}
|
||||
</div>
|
||||
|
||||
<div id="light-option" class="col-xs-12">
|
||||
<span data-toggle="tooltip" data-placement="top auto" data-title="Quickly flash the lights on beat" class="bootstrap-tooltip" {{action "hideTooltip" on="mouseLeave"}}>
|
||||
<span data-toggle="tooltip" data-placement="top auto" data-title="Quickly flash the lights on beat" class="bootstrap-tooltip"
|
||||
{{action "hideTooltip" on="mouseLeave"}}>
|
||||
{{paper-checkbox value=flashingTransitions onChange=(action (mut flashingTransitions)) label="Flashing Transitions"}}
|
||||
</span>
|
||||
</span>
|
||||
|
||||
<span data-toggle="tooltip" data-placement="top auto" data-title="Slowly cycle the lights through all the colors" class="bootstrap-tooltip" {{action "hideTooltip" on="mouseLeave"}}>
|
||||
{{paper-checkbox value=colorloopMode onChange=(action (mut colorloopMode)) label="Colorloop"}}
|
||||
</span>
|
||||
<span data-toggle="tooltip" data-placement="top auto" data-title="Slowly cycle the lights through all the colors" class="bootstrap-tooltip"
|
||||
{{action "hideTooltip" on="mouseLeave"}}>
|
||||
{{paper-checkbox value=colorloopMode onChange=(action (mut colorloopMode)) label="Colorloop"}}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ body > .ember-view {
|
|||
}
|
||||
|
||||
body, button {
|
||||
font-family: 'Slabo 27px', serif;
|
||||
font-family: 'Raleway', sans-serif;
|
||||
}
|
||||
|
||||
#huegasm {
|
||||
|
|
@ -37,12 +37,17 @@ body, button {
|
|||
.footer {
|
||||
margin: 0 auto 10px auto;
|
||||
width: 100%;
|
||||
max-width: 800px;
|
||||
max-width: 1200px;
|
||||
text-align: center;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-around;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
@media(min-width:767px) {
|
||||
.footer {
|
||||
padding: 0 9%;
|
||||
}
|
||||
}
|
||||
|
||||
.footer-text {
|
||||
|
|
|
|||
|
|
@ -44,13 +44,13 @@
|
|||
text-align: right;
|
||||
position: absolute;
|
||||
top: -10px;
|
||||
right: 10px;
|
||||
right: -10px;
|
||||
transform: scale(1.1);
|
||||
}
|
||||
}
|
||||
|
||||
.navigation-item {
|
||||
font-size: 18px;
|
||||
font-size: 20px;
|
||||
padding: 0 10px 0 10px;
|
||||
&.active {
|
||||
font-weight: bold;
|
||||
|
|
|
|||
|
|
@ -58,7 +58,7 @@
|
|||
.light-text {
|
||||
width: 60px;
|
||||
word-wrap: break-word;
|
||||
padding: 0 10px;
|
||||
padding: 0 7px;
|
||||
}
|
||||
|
||||
.light-text-content {
|
||||
|
|
|
|||
|
|
@ -300,9 +300,10 @@
|
|||
}
|
||||
.option-description {
|
||||
display: inline-flex;
|
||||
font-size: 20px;
|
||||
font-size: 18px;
|
||||
justify-content: center;
|
||||
flex-direction: column;
|
||||
padding: 10px 0;
|
||||
}
|
||||
button {
|
||||
margin-top: 0;
|
||||
|
|
@ -466,6 +467,12 @@
|
|||
}
|
||||
}
|
||||
|
||||
@media(max-width: 950px) and (min-width:768px) {
|
||||
.option-description {
|
||||
height: 55px;
|
||||
}
|
||||
}
|
||||
|
||||
// mobile overrides
|
||||
@media(max-width:767px) {
|
||||
div#player-bottom {
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ md-checkbox .md-label {
|
|||
}
|
||||
|
||||
.md-button {
|
||||
font-size: 13px;
|
||||
flex-direction: unset;
|
||||
span {
|
||||
width: 100%;
|
||||
|
|
|
|||
Reference in a new issue