simplifying controls

This commit is contained in:
lone-cloud 2015-11-02 01:23:44 -08:00
parent 2c866db997
commit 272701813f
6 changed files with 107 additions and 633 deletions

View file

@ -66,15 +66,6 @@ export default Em.Component.extend({
'<i><b>TIP</b>: Beat settings are saved per song as indicated by the red star icon in the top left corner. These settings they will be restored if you ever listen to the same song again.</i>',
position: 'top'
},
{
element: '#beatOptionButtonGroup',
intro: 'Some additional settings:<br>' +
'<b>Default</b> - Revert to the default beat detection settings<br>' +
'<b>Random/Sequential</b> - The transition order of lights on beat<br>' +
'<b>Brightness/Brightness & Color</b> - The properties of the lights to change on beat<br><br>' +
'<i><b>TIP</b>: Turn the colorloop \'on\' in the <b>Lights</b> tab and set only the brightness to change on beat for a cool visual effect.</i>',
position: 'top'
},
{
element: '#beatContainer',
intro: 'An interactive speaker that will bump when a beat is registered. Switch over to the <b>Debug View</b> to see the intesity of all the registered and unregistered beats.<br><br>' +

View file

@ -198,13 +198,6 @@ export default Em.Component.extend(helperMixin, visualizerMixin, {
this.send('goToSong', index, true, true);
}
},
defaultControls(){
var beatOptions = this.get('beatOptions');
this.changePlayerControl('threshold', beatOptions.threshold.defaultValue);
this.changePlayerControl('interval', beatOptions.interval.defaultValue);
this.changePlayerControl('transitionTime', beatOptions.transitionTime.defaultValue);
},
playerAreaPlay(){
if(Em.isEmpty(Em.$('#playerControls:hover')) && this.get('playQueuePointer') !== -1 ){
this.send('play');
@ -260,8 +253,6 @@ export default Em.Component.extend(helperMixin, visualizerMixin, {
repeat = this.get('repeat'),
shuffle = this.get('shuffle');
this.get('beatHistory').clear();
if(repeat === 2){ // repeating one song takes precedence over shuffling
if(playQueuePointer === -1 && playQueue.length > 0) {
nextSong = 0;
@ -380,9 +371,6 @@ export default Em.Component.extend(helperMixin, visualizerMixin, {
this.get('storage').set('huegasm.micBoost', value);
this.get('dancer').setBoost(value);
},
intervalChanged(value){
this.changePlayerControl('interval', value, true);
},
audioModeChanged(value){
if(value === 1) {
this.startUsingMic();
@ -454,6 +442,11 @@ export default Em.Component.extend(helperMixin, visualizerMixin, {
changePlayerControl(name, value, saveBeatPrefs){
this.set(name, value);
if(name === 'threshold'){
this.get('kick').set({threshold: value});
}
if(saveBeatPrefs && this.get('usingLocalAudio') && this.get('playQueuePointer') !== -1){
this.saveSongBeatPreferences();
}
@ -466,7 +459,7 @@ export default Em.Component.extend(helperMixin, visualizerMixin, {
title = Em.isEmpty(song.artist) ? song.fileName : song.artist + '-' + song.title,
songBeatPreferences = this.get('songBeatPreferences');
songBeatPreferences[title] = {threshold: this.get('threshold'), interval: this.get('interval')};
songBeatPreferences[title] = {threshold: this.get('threshold')};
this.set('usingBeatPreferences', true);
this.get('storage').set('huegasm.songBeatPreferences', songBeatPreferences);
@ -481,14 +474,12 @@ export default Em.Component.extend(helperMixin, visualizerMixin, {
newOldBeatPrefCache = null;
if(!Em.isNone(preference)) { // load existing beat prefs
newOldBeatPrefCache = {threshold: this.get('threshold'), interval: this.get('interval')};
newOldBeatPrefCache = {threshold: this.get('threshold')};
this.changePlayerControl('threshold', preference.threshold);
this.changePlayerControl('interval', preference.interval);
this.set('usingBeatPreferences', true);
} else if(!Em.isNone(oldBeatPrefCache)) { // revert to using beat prefs before the remembered song
this.changePlayerControl('threshold', oldBeatPrefCache.threshold);
this.changePlayerControl('interval', oldBeatPrefCache.interval);
this.set('usingBeatPreferences', false);
}
@ -517,7 +508,7 @@ export default Em.Component.extend(helperMixin, visualizerMixin, {
dancer.load(stream, this.get('micBoost'), true);
this.set('usingBeatPreferences', false);
// much more sensitive beath preference settings are needed for mic mode
// much more sensitive beat preference settings are needed for mic mode
this.setProperties({
oldThreshold: this.get('threshold'),
threshold: 0.1
@ -589,97 +580,65 @@ export default Em.Component.extend(helperMixin, visualizerMixin, {
this.set('dragLeaveTimeoutHandle', setTimeout(function(){ self.set('dragging', false); }, 500));
},
simulateKick(mag) {
var validBeat = (this.get('threshold') < mag),
beatInterval = this.get('interval');
simulateKick() {
var activeLights = this.get('activeLights'),
transitionTime = this.get('transitionTime') * 10,
onBeatBriAndColor = this.get('onBeatBriAndColor'),
lightsData = this.get('lightsData'),
color = null,
beatInterval = 1,
stimulateLight = (light, brightness, hue) => {
var options = {'bri': brightness, 'transitiontime': transitionTime};
if(validBeat){
var activeLights = this.get('activeLights'),
transitionTime = this.get('transitionTime') * 10,
onBeatBriAndColor = this.get('onBeatBriAndColor'),
lightsData = this.get('lightsData'),
color = null,
stimulateLight = (light, brightness, hue) => {
var options = {'bri': brightness, 'transitiontime': transitionTime};
if(!Em.isNone(hue)) {
options.hue = hue;
}
if(!Em.isNone(hue)) {
options.hue = hue;
}
if(lightsData[light].state.on === false){
options.on = true;
}
if(lightsData[light].state.on === false){
options.on = true;
}
Em.$.ajax(this.get('apiURL') + '/lights/' + light + '/state', {
data: JSON.stringify(options),
contentType: 'application/json',
type: 'PUT'
});
};
Em.$.ajax(this.get('apiURL') + '/lights/' + light + '/state', {
data: JSON.stringify(options),
contentType: 'application/json',
type: 'PUT'
});
};
if(activeLights.length > 0){
var lastLightBopIndex = this.get('lastLightBopIndex'),
lightBopIndex,
light;
if(activeLights.length > 0){
var lastLightBopIndex = this.get('lastLightBopIndex'),
randomTransition = this.get('randomTransition'),
lightBopIndex,
light;
lightBopIndex = Math.floor(Math.random() * activeLights.length);
if(randomTransition) {
// 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);
// 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);
}
}
} else {
lightBopIndex = (lastLightBopIndex + 1) % activeLights.length;
}
light = activeLights[lightBopIndex];
this.set('lastLightBopIndex', lightBopIndex);
if(onBeatBriAndColor) {
color = Math.floor(Math.random() * 65535);
}
stimulateLight(light, 254, color);
setTimeout(stimulateLight, transitionTime + 50, light, 1);
}
light = activeLights[lightBopIndex];
this.set('lastLightBopIndex', lightBopIndex);
if(onBeatBriAndColor) {
color = Math.floor(Math.random() * 65535);
}
stimulateLight(light, 254, color);
setTimeout(stimulateLight, transitionTime + 50, light, 1);
}
if(beatInterval > 0 && validBeat){
this.set('paused', true);
setTimeout(() => {
this.set('paused', false);
}, beatInterval * 1000);
}
this.set('paused', true);
setTimeout(() => {
this.set('paused', false);
}, beatInterval * 100);
//work the music beat area
if(this.get('speakerViewed')){
if(validBeat){
// simulate the speaker vibration by running a CSS animation on it
Em.$('#beatSpeakerCenterOuter').removeClass('vibrateOuter').prop('offsetWidth', Em.$('#beatSpeakerCenterOuter').prop('offsetWidth')).addClass('vibrateOuter');
Em.$('#beatSpeakerCenterInner').removeClass('vibrateInner').prop('offsetWidth', Em.$('#beatSpeakerCenterInner').prop('offsetWidth')).addClass('vibrateInner');
}
} else {
var beatHistory = this.get('beatHistory'),
debugFiltered = this.get('debugFiltered'),
maxSize = this.get('maxBeatHistorySize'),
html = 'Beat intesity of <b>' + mag.toFixed(3) + '</b> at <b>' + this.get('timeElapsedTxt') + '</b>';
if(!validBeat){
if(!debugFiltered){
return;
}
html = '<span class="filterBeat">' + html + ' ( filtered ) </span>';
}
beatHistory.unshiftObjects(html);
if(beatHistory.length > maxSize){
beatHistory.popObject();
}
}
// simulate the speaker vibration by running a CSS animation on it
Em.$('#beatSpeakerCenterOuter').removeClass('vibrateOuter').prop('offsetWidth', Em.$('#beatSpeakerCenterOuter').prop('offsetWidth')).addClass('vibrateOuter');
Em.$('#beatSpeakerCenterInner').removeClass('vibrateInner').prop('offsetWidth', Em.$('#beatSpeakerCenterInner').prop('offsetWidth')).addClass('vibrateInner');
},
init() {
@ -690,13 +649,13 @@ export default Em.Component.extend(helperMixin, visualizerMixin, {
navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia;
var dancer = new Dancer(),
self = this,
storage = this.get('storage'),
kick = dancer.createKick({
threshold: this.beatOptions.threshold.range.min,
onKick: function (mag) {
if (self.get('paused') === false) {
self.simulateKick(mag);
frequency: [0,100],
threshold: this.get('threshold'),
onKick: (mag) => {
if (this.get('paused') === false) {
this.simulateKick(mag);
}
}
});
@ -712,14 +671,14 @@ export default Em.Component.extend(helperMixin, visualizerMixin, {
this.set('usingMicSupported', false);
}
['volume', 'shuffle', 'repeat', 'volumeMuted', 'threshold', 'interval', 'speakerViewed', 'transitionTime', 'randomTransition', 'playerBottomDisplayed', 'onBeatBriAndColor', 'audioMode', 'songBeatPreferences', 'debugFiltered', 'firstVisit', 'currentVisName', 'playQueue', 'playQueuePointer', 'micBoost'].forEach(function (item) {
['volume', 'shuffle', 'repeat', 'volumeMuted', 'threshold', 'transitionTime', 'playerBottomDisplayed', 'onBeatBriAndColor', 'audioMode', 'songBeatPreferences', 'firstVisit', 'currentVisName', 'playQueue', 'playQueuePointer', 'micBoost'].forEach((item)=>{
if (!Em.isNone(storage.get('huegasm.' + item))) {
var itemVal = storage.get('huegasm.' + item);
if(Em.isNone(self.actions[item+'Changed'])){
self.set(item, itemVal);
if(Em.isNone(this.actions[item+'Changed'])){
this.set(item, itemVal);
} else {
self.send(item + 'Changed', itemVal);
this.send(item + 'Changed', itemVal);
}
}
});

View file

@ -11,23 +11,9 @@ export default Em.Mixin.create({
beatOptions: {
threshold: {
range: {min: 0.1, max: 1.0},
range: {min: 0, max: 1.0},
step: 0.01,
defaultValue: 0.3,
pips: {
mode: 'positions',
values: [0,25,50,75,100],
density: 3,
format: {
to: function ( value ) {return value;},
from: function ( value ) { return value; }
}
}
},
interval: {
range: {min: 0, max: 0.5},
step: 0.01,
defaultValue: 0.1,
pips: {
mode: 'positions',
values: [0,20,40,60,80,100],
@ -70,14 +56,11 @@ export default Em.Mixin.create({
transitionTime: 0.1,
threshold: 0.3,
interval: 0.1,
micBoost: 5,
oldThreshold: null,
playQueuePointer: -1,
playQueue: Em.A(),
beatHistory: Em.A(),
maxBeatHistorySize: 200,
timeElapsed: 0,
timeTotal: 0,
lastLightBopIndex: 0,
@ -163,39 +146,6 @@ export default Em.Mixin.create({
return this.get('playing');
}.property('playing'),
speakerViewed: true,
debugFiltered: false,
speakerLabel: function() {
this.get('storage').set('huegasm.speakerViewed', this.get('speakerViewed'));
if(this.get('speakerViewed')){
this.get('beatHistory').clear();
return 'Speaker View';
} else {
return 'Debug View';
}
}.property('speakerViewed'),
debugFilteredText: function(){
var debugFiltered = this.get('debugFiltered');
this.get('storage').set('huegasm.debugFiltered', debugFiltered);
Em.$('#beatHistory .filterBeat').css('display', debugFiltered === true ? 'inline' : 'none');
if(debugFiltered){
return 'View Filtered';
} else {
return 'Hide Filtered';
}
}.property('debugFiltered'),
randomTransition: true,
randomTransitionLabel: function() {
if(this.get('randomTransition')){
return 'Random';
} else {
return 'Sequential';
}
}.property('randomTransition'),
onBeatBriAndColor: true,
onBeatBriAndColorLabel: function() {
if(this.get('onBeatBriAndColor')){
@ -296,7 +246,7 @@ export default Em.Mixin.create({
onOptionChange: function(self, option){
option = option.replace('.[]', '');
this.get('storage').set('huegasm.' + option, this.get(option));
}.observes('randomTransition', 'onBeatBriAndColor', 'playQueue.[]', 'playQueuePointer'),
}.observes('onBeatBriAndColor', 'playQueue.[]', 'playQueuePointer'),
onRepeatChange: function () {
var tooltipTxt = 'Repeat all', type = 'repeat';

View file

@ -146,79 +146,50 @@
<div id="playerBottom" class="row {{if dimmerOn "dimmerOn"}}">
<div id="beatArea" class="col-sm-7 col-xs-12">
{{#if usingBeatPreferences}}
<span data-toggle="tooltip" data-placement="bottom auto" data-title="Using your saved beat preferences from the last time you listened to this song" class="bootstrapTooltip savedStarTooltip">
<span data-toggle="tooltip" data-placement="bottom" data-title="Using your saved beat preferences from the last time you listened to this song" class="bootstrapTooltip savedStarTooltip">
{{paper-icon id="saveBeatPreferencesStar" icon="star"}}
</span>
{{/if}}
<div class="row" id="beatOptionRow">
<div class="beatOption col-xs-4">
<span data-toggle="tooltip" data-placement="bottom auto" data-title="The minimum sound intensity for the beat to register" class="optionDescription bootstrapTooltip">Beat Threshold</span>
{{range-slider start=threshold orientation="vertical" step=beatOptions.threshold.step range=beatOptions.threshold.range slide="thresholdChanged" pips=beatOptions.threshold.pips}}
<div class="text-center">{{threshold}}</div>
<div class="beatOption col-xs-4">
<span data-toggle="tooltip" data-placement="bottom auto" data-title="The minimum sound intensity for the beat to register" class="optionDescription bootstrapTooltip">Sensitivity</span>
{{range-slider start=threshold orientation="vertical" step=beatOptions.threshold.step range=beatOptions.threshold.range slide="thresholdChanged" pips=beatOptions.threshold.pips}}
</div>
<div class="beatOption col-xs-4">
<span data-toggle="tooltip" data-placement="bottom auto" data-title="The time it takes for a light to change color or brightness" class="optionDescription bootstrapTooltip">Transition Time</span>
{{range-slider start=transitionTime orientation="vertical" step=beatOptions.transitionTime.step range=beatOptions.transitionTime.range slide="transitionTimeChanged" pips=beatOptions.transitionTime.pips}}
</div>
<div class="beatOption col-xs-4">
{{#paper-switch checked=onBeatBriAndColor disabled=trial}}<span data-toggle="tooltip"
data-placement="bottom auto"
data-title="The properties of the lights to change on beat"
class="optionDescription bootstrapTooltip">
{{onBeatBriAndColorLabel}}</span>{{/paper-switch}}
</div>
</div>
<div class="beatOption col-xs-4">
<span data-toggle="tooltip" data-placement="bottom auto" data-title="The minimum amount of time between each registered beat" class="optionDescription bootstrapTooltip">Beat Interval</span>
{{range-slider start=interval orientation="vertical" step=beatOptions.interval.step range=beatOptions.interval.range slide="intervalChanged" pips=beatOptions.interval.pips}}
<div class="text-center">{{interval}} sec</div>
</div>
<div class="beatOption col-xs-4">
<span data-toggle="tooltip" data-placement="bottom auto" data-title="The time it takes for a light to change color or brightness" class="optionDescription bootstrapTooltip">Transition Time</span>
{{range-slider start=transitionTime orientation="vertical" step=beatOptions.transitionTime.step range=beatOptions.transitionTime.range slide="transitionTimeChanged" pips=beatOptions.transitionTime.pips}}
<div class="text-center">{{transitionTime}} sec</div>
</div>
</div>
<div id="beatOptionButtonGroup" class="row">
<div class="beatOption col-xs-3">
{{#paper-button raised=true warn=true action="defaultControls"}}Default{{/paper-button}}
</div>
<div class="beatOption col-xs-4">
{{#paper-switch checked=randomTransition disabled=trial}}<span data-toggle="tooltip"
data-placement="bottom auto"
data-title="The transition order of lights on beat"
class="optionDescription bootstrapTooltip">{{randomTransitionLabel}}</span>{{/paper-switch}}
</div>
<div class="beatOption col-xs-5">
{{#paper-switch checked=onBeatBriAndColor disabled=trial}}<span data-toggle="tooltip"
data-placement="bottom auto"
data-title="The properties of the lights to change on beat"
class="optionDescription bootstrapTooltip"> {{onBeatBriAndColorLabel}}</span>{{/paper-switch}}
</div>
</div>
</div>
<div id="beatContainer" class="col-sm-5 col-xs-12">
{{#if speakerViewed}}
<div id="beatContainer" class="col-sm-5 col-xs-12">
<div class="bezel">
<div class="rivet1"></div>
<div class="rivet2"></div>
<div class="rivet3"></div>
<div class="rivet4"></div>
<div class="rivet5"></div>
<div class="rivet6"></div>
<div class="rivet7"></div>
<div class="rivet8"></div>
<div class="rivet1"></div>
<div class="rivet2"></div>
<div class="rivet3"></div>
<div class="rivet4"></div>
<div class="rivet5"></div>
<div class="rivet6"></div>
<div class="rivet7"></div>
<div class="rivet8"></div>
<div id="beatSpeakerCenterOuter">
<div id="beatSpeakerCenterInner" class="cursorPointer" {{action "clickSpeaker"}}>
<div id="beatSpeakerCenterOuter">
<div id="beatSpeakerCenterInner" class="cursorPointer" {{action "clickSpeaker"}}>
</div>
</div>
</div>
</div>
</div>
{{else}}
<div id="beatHistory">
{{#each beatHistory as |item|}}
<p>{{{item}}}</p>
{{/each}}
</div>
{{#paper-switch checked=debugFiltered class="debugFilteredSwitch"}} {{debugFilteredText}} {{/paper-switch}}
{{/if}}
{{#paper-switch checked=speakerViewed class="speakerSwitch"}} {{speakerLabel}} {{/paper-switch}}
</div>
</div>
</div>
{{ember-notify closeAfter=5000}}

View file

@ -7,7 +7,7 @@
$playerHeight: 400px;
$playerDefaultIconColor: #BBBBBB;
$footerHeight: 40px;
$playerBottomHeight: 340px;
$playerBottomHeight: 300px;
$secondaryThemeColor: #F12B24;
$glowingText: 0 0 5px #fff, 0 0 10px #fff, 0 0 20px #228DFF;
$dimmerOnButtonColor: #404040;
@ -833,23 +833,8 @@ md-switch.md-default-theme.md-checked .md-thumb {
}
#beatContainer {
-webkit-transform: translate3d(0, 0, 0); // hack for chrome to force hardware acceleration and stop flickering
padding: 0;
height: $playerBottomHeight;
.speakerSwitch {
top: 0;
left: 0;
position: absolute;
margin-left: 0;
margin-bottom: 10px;
}
.debugFilteredSwitch {
top: 0;
right: 0;
position: absolute;
margin-left: 0;
margin-bottom: 10px;
}
}
#beatArea .lightGroup {
@ -865,31 +850,6 @@ md-switch.md-default-theme.md-checked .md-thumb {
margin-top: 10px;
}
#beatHistory {
border: 1px solid #C5C5C5;
color: black;
height: 85%;
background-color: white;
border-radius: 10px;
width: 290px;
margin: 40px auto 0 auto;
overflow: auto;
padding: 10px;
box-shadow: 5px 10px 15px 5px rgba(0, 0, 0, 0.1);
p {
margin-bottom: 5px;
}
.filterBeat {
font-style: italic;
}
}
#ytplayer{
display: block;
width: 100%;
height: 100%
}
.dimmerBulbOn {
fill: gold;
stroke: gold;

375
vendor/dancer.js vendored
View file

@ -13,7 +13,7 @@
this.bind( 'update', update );
};
Dancer.version = '0.4.0';
Dancer.version = 'X.X.X';
Dancer.adapters = {};
Dancer.prototype = {
@ -22,10 +22,6 @@
// Loading an Audio element
if ( source instanceof HTMLElement ) {
this.source = source;
if ( Dancer.isSupported() === 'flash' ) {
this.source = { src: Dancer._getMP3SrcFromAudio( source ) };
}
// Loading an object with src, [codecs]
} else if(source instanceof EventTarget){
this.source = source;
@ -227,8 +223,6 @@
return null;
} else if ( !isUnsupportedSafari() && ( window.AudioContext || window.webkitAudioContext )) {
return 'webaudio';
} else if ( FlashDetect.versionAtLeast( 9 ) ) {
return 'flash';
} else {
return '';
}
@ -237,8 +231,7 @@
Dancer.canPlay = function ( type ) {
var canPlay = audioEl.canPlayType;
return !!(
Dancer.isSupported() === 'flash' ?
type.toLowerCase() === 'mp3' :
type.toLowerCase() === 'mp3' ||
audioEl.canPlayType &&
audioEl.canPlayType( CODECS[ type.toLowerCase() ] ).replace( /no/, ''));
};
@ -264,8 +257,6 @@
switch ( Dancer.isSupported() ) {
case 'webaudio':
return new Dancer.adapters.webaudio( instance );
case 'flash':
return new Dancer.adapters.flash( instance );
default:
return null;
}
@ -333,10 +324,12 @@
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 );
console.log('xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxKICK:' + magnitude);
} else {
this.offKick && this.offKick.call( this.dancer, magnitude );
this.currentThreshold -= this.decay;
@ -368,15 +361,15 @@
SAMPLE_RATE = 44100;
var adapter = function ( dancer ) {
var context = new AudioContext(), filter = context.createBiquadFilter();
var context = new AudioContext();//, filter = context.createBiquadFilter();
filter.type = "lowpass";
filter.frequency.value = 440;
//filter.type = "lowpass";
//filter.frequency.value = 440;
this.dancer = dancer;
this.audio = new Audio();
this.context = context;
this.filter = filter;
//this.filter = filter;
};
adapter.prototype = {
@ -505,7 +498,7 @@
this.source.connect(this.proc);
this.source.connect(this.gain);
this.source.connect( this.filter );
//this.source.connect( this.filter );
this.gain.connect(this.context.destination);
this.proc.connect(this.context.destination);
//this.filter.connect( this.context.destination );
@ -519,154 +512,6 @@
})();
(function() {
var
SAMPLE_SIZE = 1024,
SAMPLE_RATE = 44100,
smLoaded = false,
smLoading = false,
CONVERSION_COEFFICIENT = 0.93;
var adapter = function ( dancer ) {
this.dancer = dancer;
this.wave_L = [];
this.wave_R = [];
this.spectrum = [];
window.SM2_DEFER = true;
};
adapter.prototype = {
// `source` can be either an Audio element, if supported, or an object
// either way, the path is stored in the `src` property
load : function ( source ) {
var _this = this;
this.path = source ? source.src : this.path;
this.isLoaded = false;
this.progress = 0;
!window.soundManager && !smLoading && loadSM.call( this );
if ( window.soundManager ) {
this.audio = soundManager.createSound({
id : 'dancer' + Math.random() + '',
url : this.path,
stream : true,
autoPlay : false,
autoLoad : true,
whileplaying : function () {
_this.update();
},
whileloading : function () {
_this.progress = this.bytesLoaded / this.bytesTotal;
},
onload : function () {
_this.fft = new FFT( SAMPLE_SIZE, SAMPLE_RATE );
_this.signal = new Float32Array( SAMPLE_SIZE );
_this.waveform = new Float32Array( SAMPLE_SIZE );
_this.isLoaded = true;
_this.progress = 1;
_this.dancer.trigger( 'loaded' );
}
});
this.dancer.audio = this.audio;
}
// Returns audio if SM already loaded -- otherwise,
// sets dancer instance's audio property after load
return this.audio;
},
play : function () {
this.audio.play();
this.isPlaying = true;
},
pause : function () {
this.audio.pause();
this.isPlaying = false;
},
setVolume : function ( volume ) {
this.audio.setVolume( volume * 100 );
},
getVolume : function () {
return this.audio.volume / 100;
},
getProgress : function () {
return this.progress;
},
getWaveform : function () {
return this.waveform;
},
getSpectrum : function () {
return this.fft.spectrum;
},
getTime : function () {
return this.audio.position / 1000;
},
update : function () {
if ( !this.isPlaying && !this.isLoaded ) return;
this.wave_L = this.audio.waveformData.left;
this.wave_R = this.audio.waveformData.right;
var avg;
for ( var i = 0, j = this.wave_L.length; i < j; i++ ) {
avg = parseFloat(this.wave_L[ i ]) + parseFloat(this.wave_R[ i ]);
this.waveform[ 2 * i ] = avg / 2;
this.waveform[ i * 2 + 1 ] = avg / 2;
this.signal[ 2 * i ] = avg * CONVERSION_COEFFICIENT;
this.signal[ i * 2 + 1 ] = avg * CONVERSION_COEFFICIENT;
}
this.fft.forward( this.signal );
this.dancer.trigger( 'update' );
}
};
function loadSM () {
var adapter = this;
smLoading = true;
loadScript( Dancer.options.flashJS, function () {
soundManager = new SoundManager();
soundManager.flashVersion = 9;
soundManager.flash9Options.useWaveformData = true;
soundManager.useWaveformData = true;
soundManager.useHighPerformance = true;
soundManager.useFastPolling = true;
soundManager.multiShot = false;
soundManager.debugMode = false;
soundManager.debugFlash = false;
soundManager.url = Dancer.options.flashSWF;
soundManager.onready(function () {
smLoaded = true;
adapter.load();
});
soundManager.ontimeout(function(){
console.error( 'Error loading SoundManager2.swf' );
});
soundManager.beginDelayedInit();
});
}
function loadScript ( url, callback ) {
var
script = document.createElement( 'script' ),
appender = document.getElementsByTagName( 'script' )[0];
script.type = 'text/javascript';
script.src = url;
script.onload = callback;
appender.parentNode.insertBefore( script, appender );
}
Dancer.adapters.flash = adapter;
})();
/*
* DSP.js - a comprehensive digital signal processing library for javascript
@ -843,205 +688,3 @@ FFT.prototype.forward = function(buffer) {
return this.calculateSpectrum();
};
/*
Copyright (c) Copyright (c) 2007, Carl S. Yestrau All rights reserved.
Code licensed under the BSD License: http://www.featureblend.com/license.txt
Version: 1.0.4
*/
var FlashDetect = new function(){
var self = this;
self.installed = false;
self.raw = "";
self.major = -1;
self.minor = -1;
self.revision = -1;
self.revisionStr = "";
var activeXDetectRules = [
{
"name":"ShockwaveFlash.ShockwaveFlash.7",
"version":function(obj){
return getActiveXVersion(obj);
}
},
{
"name":"ShockwaveFlash.ShockwaveFlash.6",
"version":function(obj){
var version = "6,0,21";
try{
obj.AllowScriptAccess = "always";
version = getActiveXVersion(obj);
}catch(err){}
return version;
}
},
{
"name":"ShockwaveFlash.ShockwaveFlash",
"version":function(obj){
return getActiveXVersion(obj);
}
}
];
/**
* Extract the ActiveX version of the plugin.
*
* @param {Object} The flash ActiveX object.
* @type String
*/
var getActiveXVersion = function(activeXObj){
var version = -1;
try{
version = activeXObj.GetVariable("$version");
}catch(err){}
return version;
};
/**
* Try and retrieve an ActiveX object having a specified name.
*
* @param {String} name The ActiveX object name lookup.
* @return One of ActiveX object or a simple object having an attribute of activeXError with a value of true.
* @type Object
*/
var getActiveXObject = function(name){
var obj = -1;
try{
obj = new ActiveXObject(name);
}catch(err){
obj = {activeXError:true};
}
return obj;
};
/**
* Parse an ActiveX $version string into an object.
*
* @param {String} str The ActiveX Object GetVariable($version) return value.
* @return An object having raw, major, minor, revision and revisionStr attributes.
* @type Object
*/
var parseActiveXVersion = function(str){
var versionArray = str.split(",");//replace with regex
return {
"raw":str,
"major":parseInt(versionArray[0].split(" ")[1], 10),
"minor":parseInt(versionArray[1], 10),
"revision":parseInt(versionArray[2], 10),
"revisionStr":versionArray[2]
};
};
/**
* Parse a standard enabledPlugin.description into an object.
*
* @param {String} str The enabledPlugin.description value.
* @return An object having raw, major, minor, revision and revisionStr attributes.
* @type Object
*/
var parseStandardVersion = function(str){
var descParts = str.split(/ +/);
var majorMinor = descParts[2].split(/\./);
var revisionStr = descParts[3];
return {
"raw":str,
"major":parseInt(majorMinor[0], 10),
"minor":parseInt(majorMinor[1], 10),
"revisionStr":revisionStr,
"revision":parseRevisionStrToInt(revisionStr)
};
};
/**
* Parse the plugin revision string into an integer.
*
* @param {String} The revision in string format.
* @type Number
*/
var parseRevisionStrToInt = function(str){
return parseInt(str.replace(/[a-zA-Z]/g, ""), 10) || self.revision;
};
/**
* Is the major version greater than or equal to a specified version.
*
* @param {Number} version The minimum required major version.
* @type Boolean
*/
self.majorAtLeast = function(version){
return self.major >= version;
};
/**
* Is the minor version greater than or equal to a specified version.
*
* @param {Number} version The minimum required minor version.
* @type Boolean
*/
self.minorAtLeast = function(version){
return self.minor >= version;
};
/**
* Is the revision version greater than or equal to a specified version.
*
* @param {Number} version The minimum required revision version.
* @type Boolean
*/
self.revisionAtLeast = function(version){
return self.revision >= version;
};
/**
* Is the version greater than or equal to a specified major, minor and revision.
*
* @param {Number} major The minimum required major version.
* @param {Number} (Optional) minor The minimum required minor version.
* @param {Number} (Optional) revision The minimum required revision version.
* @type Boolean
*/
self.versionAtLeast = function(major){
var properties = [self.major, self.minor, self.revision];
var len = Math.min(properties.length, arguments.length);
for(i=0; i<len; i++){
if(properties[i]>=arguments[i]){
if(i+1<len && properties[i]==arguments[i]){
continue;
}else{
return true;
}
}else{
return false;
}
}
};
/**
* Constructor, sets raw, major, minor, revisionStr, revision and installed public properties.
*/
self.FlashDetect = function(){
if(navigator.plugins && navigator.plugins.length>0){
var type = 'application/x-shockwave-flash';
var mimeTypes = navigator.mimeTypes;
if(mimeTypes && mimeTypes[type] && mimeTypes[type].enabledPlugin && mimeTypes[type].enabledPlugin.description){
var version = mimeTypes[type].enabledPlugin.description;
var versionObj = parseStandardVersion(version);
self.raw = versionObj.raw;
self.major = versionObj.major;
self.minor = versionObj.minor;
self.revisionStr = versionObj.revisionStr;
self.revision = versionObj.revision;
self.installed = true;
}
}else if(navigator.appVersion.indexOf("Mac")==-1 && window.execScript){
var version = -1;
for(var i=0; i<activeXDetectRules.length && version==-1; i++){
var obj = getActiveXObject(activeXDetectRules[i].name);
if(!obj.activeXError){
self.installed = true;
version = activeXDetectRules[i].version(obj);
if(version!=-1){
var versionObj = parseActiveXVersion(version);
self.raw = versionObj.raw;
self.major = versionObj.major;
self.minor = versionObj.minor;
self.revision = versionObj.revision;
self.revisionStr = versionObj.revisionStr;
}
}
}
}
}();
};
FlashDetect.JS_RELEASE = "1.0.4";