\r
//console.log( 'updatePosition x:' + x + ' gpu:' + !!useGPU );\r
if( obj.transform ){\r
- if( ( x === x || y === y ) && ( x !== 0 && y !== 0 ) ) str += ' translate(' + ( x | 0 ) + 'px,' + ( y | 0 ) + 'px)';\r
+ if( ( x === x || y === y ) && ( x !== 0 && y !== 0 ) ){\r
+ if( X_UA[ 'Safari' ] && X_UA[ 'Windows' ] ){\r
+ // http://shinimae.hatenablog.com/entry/2016/01/13/151748\r
+ str = ' -webkit-translate(' + ( x | 0 ) + 'px,' + ( y | 0 ) + 'px)';\r
+ } else {\r
+ str = ' translate(' + ( x | 0 ) + 'px,' + ( y | 0 ) + 'px)';\r
+ };\r
+ };\r
if( rotate < 0 || 0 < rotate ) str += ' rotate(' + rotate + 'deg)'; // opera は rad?\r
if( skewX < 0 || 0 < skewX ) str += ' skewX(' + skewX + 'deg)';\r
if( skewY < 0 || 0 < skewY ) str += ' skewY(' + skewY + 'deg)';\r
this[ 'listenOnce' ]( X_EVENT_COMPLETE, X_NET_proxyDispatch )\r
[ 'asyncDispatch' ]( 32, { type : X_EVENT_COMPLETE, 'lastEventType' : e.type } );\r
\r
+ // target を上書き X_NET_currentWrapper -> X_NET_currentQueue\r
+ e[ 'target' ] = e[ 'currentTarget' ] = this;\r
this[ 'asyncDispatch' ]( e );\r
break;\r
\r
postdata = obj[ 'postdata' ] || '',\r
timeout = obj[ 'timeout' ] || 20000,\r
noCache = obj[ 'cache' ] !== true,\r
- dataType = X_XHR._dataType = obj[ 'dataType' ],\r
+ dataType = X_XHR._dataType = obj[ 'dataType' ], // ext が入っている\r
xDomain = !X_URL_isSameDomain( url ),\r
isFile = X_URL_isLocal( url ),\r
init,\r
if( raw.responseType !== undefined ){\r
switch( dataType ){\r
case '' :\r
+ case 'txt' :\r
case 'text' :\r
// js, css\r
- raw.responseType = 'text';\r
+ raw.responseType = X_XHR._dataType = 'text';\r
break;\r
case 'json' : // firefox9- は moz-json\r
- raw.responseType = X_UA[ 'Gecko' ] < 10 ? 'moz-json' : X_UA[ 'Gecko' ] ? dataType : ''; // Iron 37 でエラー\r
+ raw.responseType = X_XHR._dataType = X_UA[ 'Gecko' ] < 10 ? 'moz-json' : X_UA[ 'Gecko' ] ? dataType : ''; // Iron 37 でエラー\r
break;\r
case 'document' :\r
case 'xml' :\r
case 'html' :\r
case 'htm' :\r
// svg\r
- raw.responseType = 'document';\r
+ raw.responseType = X_XHR._dataType = 'document';\r
break;\r
case 'blob' :\r
case 'arraybuffer' :\r
// jpeg,jpg,png,gif,mp3,ogg...\r
- raw.responseType = dataType;\r
+ raw.responseType = X_XHR._dataType = dataType;\r
break;\r
};\r
};\r
\r
// parse json, html, xml, text, script, css\r
switch( X_XHR._dataType ){\r
- case '' :\r
case 'text' :\r
data = X_Script_try( X_Object_find, [ raw, 'responseText' ] );\r
break;\r
if( X_Type_isString( data ) ) data = X_JSON_parseTrustableString( data );\r
break;\r
case 'document' :\r
- case 'xml' :\r
- case 'html' :\r
- case 'htm' :\r
- // svg, vml, xaml, xul, mxml ??\r
data = raw[ 'responseXML' ] || raw[ 'response' ] || raw[ 'responseText' ]; // とりあえず\r
break;\r
case 'blob' :\r
var action = cmd === '+' ? 'setItem' : cmd === '-' ? 'removeItem' : 'getItem',
pair;
- if( window.localStorage ){
+ if( window.localStorage ){ // TODO http://qiita.com/narikei/items/f55fb9cb398beac52ea9
return window.localStorage[ action ]( X_Pair_get( that )[ 'clientID' ] + name, value );
};
X_Type_isArray( sourceList ) ? X_Array_copy( sourceList ) : [ sourceList ],\r
opt_option || {} );\r
this[ 'listenOnce' ]( [ X_EVENT_BACKEND_READY, X_EVENT_BACKEND_NONE, X_EVENT_KILL_INSTANCE ], X_Audio_handleEvent );\r
- X_ViewPort[ 'listenOnce' ]( X_EVENT_UNLOAD, this, X_AudioSprite_handleEvent );\r
+ X_ViewPort[ 'listenOnce' ]( X_EVENT_UNLOAD, this, X_Audio_handleEvent );\r
},\r
\r
/**\r
this[ 'listenOnce' ]( X_EVENT_READY, X_Audio_handleEvent );\r
break;\r
\r
- case X_EVENT_READY :\r
+ case X_EVENT_READY : // TODO AudioBase 側へ行かない?\r
pair = X_Pair_get( this );\r
( pair.autoplay || pair._playReserved ) && pair.actualPlay();\r
delete pair._playReserved;\r
break;\r
\r
case X_EVENT_KILL_INSTANCE :\r
- X_ViewPort[ 'unlisten' ]( X_EVENT_UNLOAD, this, X_AudioSprite_handleEvent );\r
+ X_ViewPort[ 'unlisten' ]( X_EVENT_UNLOAD, this, X_Audio_handleEvent );\r
if( backend = X_Pair_get( this ) ){\r
backend[ 'kill' ]();\r
X_Pair_release( this, backend );\r
'backendID' : i\r
};\r
// WebAudio\r
- if( this.backendID === 1 ) _e[ 'needTouchForPlay' ] = X_WebAudio_need1stTouch;\r
+ if( this.backendID === 1 ) _e[ 'needTouchForPlay' ] = /* X_WebAudio_need1stTouch && */ X_WebAudio_isNoTouch;\r
// HTMLAudio\r
if( this.backendID === 2 ) _e[ 'needTouchForLoad' ] = X_HTMLAudio_need1stTouch;\r
\r
'X.AudioBase',\r
X_Class.ABSTRACT,\r
{\r
- disatcher : null,\r
+ dispatcher : null,\r
\r
startTime : 0, // state_startTime\r
endTime : -1, // state_startTime\r
X_Audio_codecs;
+// WebAudioAPIを使っているはずなのに、マナーモードで音が出る!?
+// http://qiita.com/gonshi_com/items/e41dbb80f5eb4c176108
+// HTML Audio、もしくはHTML Videoをページ内で1つでも使用していた場合、そのページでは WebAudioAPI の音がマナーモード時にも鳴ってしまう
+
if( X_Audio_constructor ){
//http://himaxoff.blog111.fc2.com/blog-entry-97.html
//引数なしで new Audio() とすると、Operaでエラーになるそうなので注意。
};
-var X_WebAudio_context = // 4s 以下ではない iPad 2G または iPad mini 1G 以下ではない, iPod touch 4G 以下ではない
+var X_WebAudio_Context = // 4s 以下ではない iPad 2G または iPad mini 1G 以下ではない, iPod touch 4G 以下ではない
!X_UA[ 'iPhone_4s' ] && !X_UA[ 'iPad_2Mini1' ] && !X_UA[ 'iPod_4' ] &&
// iOS7 以上で HTML Audio が鳴らない問題を見ていくよ
// !X_UA[ 'iOS' ] &&
//!X_UA[ 'Blink' ] &&
// Firefox40.0.5 + Windows8 で音声が途中から鳴らなくなる
// Firefox41.0.1 + Windows8 で音声が途中から鳴らなくなる
- !( 40 <= X_UA[ 'Gecko' ] && X_UA[ 'Gecko' ] < 46 && X_UA[ 'Windows' ] ) &&
- ( window[ 'AudioContext' ] || window[ 'webkitAudioContext' ] ),
+ !( 40 <= X_UA[ 'Gecko' ] && /* X_UA[ 'Gecko' ] < 48 && */ X_UA[ 'Windows' ] ) &&
+ ( window[ 'AudioContext' ] || window[ 'webkitAudioContext' ] || window[ 'mozAudioContext' ] ),
+ X_WebAudio_context,
X_WebAudio_BUFFER_LIST = [],
X_WebAudio_need1stTouch = X_UA[ 'iOS' ],
- X_WebAudio_touchState = X_WebAudio_need1stTouch,
+ X_WebAudio_isNoTouch = X_WebAudio_need1stTouch,
+ X_WebAudio_needRateFix = X_WebAudio_need1stTouch,
X_WebAudio,
X_WebAudio_BufferLoader,
X_WebAudio_fpsFix;
/*
* iPhone 4s 以下、iPad2以下、iPad mini 1以下, iPod touch 4G 以下は不可
*/
-if( X_WebAudio_context ){
+if( X_WebAudio_Context ){
+
+ X_WebAudio_context = new X_WebAudio_Context;
- X_WebAudio_context = new X_WebAudio_context;
+ // http://lilting.ch/3323.html
+ // 【間に合わせ】iOS9系でのWebAudioの音割れ対処について
+ /*
+ if( X_WebAudio_needRateFix ){
+ X_WebAudio_context.close();
+ X_WebAudio_context = new X_WebAudio_Context;
+ }; */
+
+ /*
+ * TODO X_TEMP へ
+ * http://qiita.com/simiraaaa/items/79a9ac972cc76fb58d93
+ * [WebAudio API] iOS9で音が歪む、遅い、低い、割れる等の回避方法
+ */
+ if( X_WebAudio_needRateFix ){
+ X_TEMP.webAudioSampleRateFix = function( sampleRate ){
+ X_TEMP.webAudioDummyPlay( sampleRate );
+
+ if( true || X_WebAudio_context[ 'sampleRate' ] !== sampleRate ){
+ // alert( '[debug]iOSで音割れを検知、修復コードを実施 ctxSR:' + X_WebAudio_context[ 'sampleRate' ] + ' abfSR:' + sampleRate );
+
+ X_WebAudio_context.close && X_WebAudio_context.close();
+ X_WebAudio_context = new X_WebAudio_Context;
+
+ X_TEMP.webAudioDummyPlay( sampleRate );
+ };
+
+ delete X_TEMP.webAudioSampleRateFix;
+ delete X_TEMP.webAudioDummyPlay;
+ };
+ X_TEMP.webAudioDummyPlay = function( sampleRate, source ){
+ source = X_WebAudio_context[ 'createBufferSource' ]();
+ source.buffer = X_WebAudio_context[ 'createBuffer' ]( 1, 1, sampleRate );
+ source[ 'connect' ]( X_WebAudio_context[ 'destination' ] );
+ source.start ? source.start( 0 ) : source[ 'noteOn' ] ? source[ 'noteOn' ]( 0 ) : source[ 'noteGrainOn' ]( 0 );
+ };
+ };
X_WebAudio_BufferLoader = X_EventDispatcher[ 'inherits' ](
'X.WebAudio.BufferLoader',
}
);
-
-
+
X_WebAudio = X_AudioBase[ 'inherits' ](
'X.WebAudio',
X_Class.POOL_OBJECT,
audioBuffer : null,
bufferSource : null,
gainNode : null,
+
+ bufferPlay : '',
+ bufferStop : '',
//_onended : null,
- 'Constructor' : function( disatcher, url, option ){
+ 'Constructor' : function( dispatcher, url, option ){
var i = 0,
l = X_WebAudio_BUFFER_LIST.length,
loader;
this.loader = loader = X_WebAudio_BufferLoader( this, url );
};
- this.disatcher = disatcher || this;
+ this.dispatcher = dispatcher || this;
this.setState( option );
this[ 'listenOnce' ]( X_EVENT_KILL_INSTANCE, this.onKill );
} else {
loader[ 'listenOnce' ]( X_EVENT_COMPLETE, this, this._onLoadBufferComplete );
};
+
+ if( X_WebAudio_isNoTouch ){
+ X_TEMP.xWebAudioInstances = X_TEMP.xWebAudioInstances || [];
+ X_TEMP.xWebAudioInstances.push( this );
+ };
},
onKill : function(){
//this._onended && X_Closure_correct( this._onended );
this.gainNode && this.gainNode.disconnect();
+
+ if( X_WebAudio_isNoTouch ){
+ X_TEMP.xWebAudioInstances.splice( X_TEMP.xWebAudioInstances.indexOf( this ), 1 );
+ };
},
_onLoadBufferComplete : function( e ){
var loader = this.loader,
if ( !buffer ) {
this.error = loader.errorState;
- this.disatcher[ 'dispatch' ]({
+ this.dispatcher[ 'dispatch' ]({
type : X_EVENT_ERROR,
error : loader.errorState,
message : loader.errorState === 1 ?
this.audioBuffer = buffer;
this.duration = buffer.duration * 1000;
- this.disatcher[ 'asyncDispatch' ]( X_WebAudio_touchState ? X_EVENT_MEDIA_WAIT_FOR_TOUCH : X_EVENT_READY );
+ this.dispatcher[ 'asyncDispatch' ]( X_WebAudio_isNoTouch ? X_EVENT_MEDIA_WAIT_FOR_TOUCH : X_EVENT_READY );
},
actualPlay : function(){
- var e, begin, end;
+ var xWebAudio, begin, end;
console.log( '[WebAudio] play abuf:' + !!this.audioBuffer );
this._playReserved = true;
return;
};
-
- if( X_WebAudio_touchState ){
- e = X_EventDispatcher_CURRENT_EVENTS[ X_EventDispatcher_CURRENT_EVENTS.length - 1 ];
+
+ if( X_WebAudio_isNoTouch ){
+ //@dev{
+ var e = X_EventDispatcher_CURRENT_EVENTS[ X_EventDispatcher_CURRENT_EVENTS.length - 1 ];
if( !e || !e[ 'pointerType' ] ){
// alert( 'タッチイベント以外での play! ' + ( e ? e.type : '' ) );
return;
};
+ //@}
+
// http://qiita.com/uupaa/items/e5856e3cb2a9fc8c5507
// iOS9 + touchstart で呼んでいた場合、 X_ViewPort['listenOnce']('pointerup',this,this.actualPlay())
- this.disatcher[ 'asyncDispatch' ]( X_EVENT_READY );
+ this.dispatcher[ 'asyncDispatch' ]( X_EVENT_READY );
+
+ // Web Audio インスタンスが複数生成された場合、一つの Web Audio に対してタッチによる play が開始されたら、
+ // 1. 同時に生成された他の X.Audio インスタンスに対して READY イベントを発する
+ // 2. 以降の X.Audio インスタンス生成時に needTouchForPlay フラグは false
+ // ちなみに HTML Audio インスタンスは各々にタッチが必要
+ //X_WebAudio_isNoTouch = false;
+
+ while( xWebAudio = X_TEMP.xWebAudioInstances.pop() ){
+ xWebAudio !== this && xWebAudio[ 'asyncDispatch' ]( X_EVENT_READY );
+ };
+ delete X_TEMP.xWebAudioInstances;
+
+ X_WebAudio_isNoTouch = false;
+
+ X_TEMP.webAudioSampleRateFix && X_TEMP.webAudioSampleRateFix( this.audioBuffer[ 'sampleRate' ] );
};
- X_WebAudio_touchState = false;
end = X_Audio_getEndTime( this );
begin = X_Audio_getStartTime( this, end, true );
console.log( '[WebAudio] play ' + begin + ' -> ' + end + ' loop: ' + this.autoLoop + ' :' + this.loopStartTime + ' -> ' + this.loopEndTime );
-
- if( this.bufferSource ) this._sourceDispose();
- if( !this.gainNode ){
- this.gainNode = X_WebAudio_context[ 'createGain' ] ? X_WebAudio_context[ 'createGain' ]() : X_WebAudio_context[ 'createGainNode' ]();
- this.gainNode[ 'connect' ]( X_WebAudio_context[ 'destination' ] );
- };
-
- this.bufferSource = X_WebAudio_context[ 'createBufferSource' ]();
- this.bufferSource.buffer = this.audioBuffer;
+ this._createTree( begin, end );
/* win8.1 Firefox45, win8.1 Chrome48 で動かなくなる...
if( this.bufferSource[ 'loop' ] = this.autoLoop ){
this.bufferSource[ 'loopStart' ] = 0 <= this.loopStartTime ? this.loopStartTime / 1000 : begin / 1000;
this.bufferSource[ 'loopEnd' ] = 0 <= this.loopEndTime ? this.loopEndTime / 1000 : end / 1000;
}; */
-
- this.bufferSource[ 'connect' ]( this.gainNode );
- this.gainNode[ 'gain' ].value = this.gain;
-
+
// おかしい、stop 前に外していても呼ばれる、、、@Firefox33.1
// 破棄された X.Callback が呼ばれて、obj.proxy() でエラーになる。Firefox では、onended は使わない
// 多くのブラウザで onended は timer を使ったカウントより遅いので使わない
//this._timerID && X_Timer_remove( this._timerID );
//this._timerID = X_Timer_once( end - begin, this, this._onEnded );
//};
-
- if( this.bufferSource.start ){
- this.bufferSource.start( 0, begin / 1000, ( end - begin ) / 1000 );
- } else
- if( this.bufferSource[ 'noteOn' ] ){
- this.bufferSource[ 'noteOn' ]( 0, begin / 1000, ( end - begin ) / 1000 );
- } else {
- this.bufferSource[ 'noteGrainOn' ]( 0, begin / 1000, ( end - begin ) / 1000 );
- };
-
+
this.playing = true;
this._startPos = begin;
this._endPosition = end;
this._interval = this._interval || X_Timer_add( 100, 0, this, this._onInterval );
},
+ _createTree : function( begin, end ){
+ if( this.bufferSource ) this._sourceDispose();
+
+ if( !this.gainNode ){
+ this.gainNode = X_WebAudio_context[ 'createGain' ] ? X_WebAudio_context[ 'createGain' ]() : X_WebAudio_context[ 'createGainNode' ]();
+ this.gainNode[ 'connect' ]( X_WebAudio_context[ 'destination' ] );
+ };
+
+ this.bufferSource = X_WebAudio_context[ 'createBufferSource' ]();
+ this.bufferSource.buffer = this.audioBuffer;
+ this.bufferSource[ 'connect' ]( this.gainNode );
+
+ this.gainNode[ 'gain' ].value = this.gain;
+
+ if( !this.bufferPlay ){
+ this.bufferPlay = this.bufferSource.start ? 'start' : this.bufferSource[ 'noteOn' ] ? 'noteOn' : 'noteGrainOn';
+ this.bufferStop = this.bufferSource.stop ? 'stop' : 'noteOff';
+ };
+ // https://developer.mozilla.org/ja/docs/Web/API/AudioBufferSourceNode
+ // AudioBufferSourceNode.start()の呼び出しは一度しかできません。
+ this.bufferSource[ this.bufferPlay ]( 0, begin / 1000, ( end - begin ) / 1000 );
+ },
+
_sourceDispose : function(){
this.bufferSource.disconnect();
//delete this.bufferSource.onended;
delete this.bufferSource;
},
-
- /*
- _onInterval : function(){
- if( !this.playing ){
- delete this._interval;
- return X_CALLBACK_UN_LISTEN;
- };
- this.disatcher[ 'dispatch' ]( X_EVENT_MEDIA_PLAYING );
- }, */
_onInterval : function(){
var time;
//console.log( '> onEnd ' + ( this.playing && ( X_WebAudio_context.currentTime * 1000 - this._startTime ) ) + ' < ' + ( this._endPosition - this._startPos ) );
if( time < 0 ){
- this.disatcher[ 'dispatch' ]( X_EVENT_MEDIA_PLAYING );
+ this.dispatcher[ 'dispatch' ]( X_EVENT_MEDIA_PLAYING );
return;
};
if( this.autoLoop ){
- if( !( this.disatcher[ 'dispatch' ]( X_EVENT_MEDIA_BEFORE_LOOP ) & X_CALLBACK_PREVENT_DEFAULT ) ){
+ if( !( this.dispatcher[ 'dispatch' ]( X_EVENT_MEDIA_BEFORE_LOOP ) & X_CALLBACK_PREVENT_DEFAULT ) ){
this.looped = true;
- this.disatcher[ 'dispatch' ]( X_EVENT_MEDIA_LOOPED );
+ this.dispatcher[ 'dispatch' ]( X_EVENT_MEDIA_LOOPED );
this.actualPlay();
} else {
delete this._interval;
};
} else {
this.actualPause();
- this.disatcher[ 'dispatch' ]( X_EVENT_MEDIA_ENDED );
+ this.dispatcher[ 'dispatch' ]( X_EVENT_MEDIA_ENDED );
};
};
},
delete this.playing;
if( this.bufferSource ){
- this.bufferSource.stop ?
- this.bufferSource.stop( 0 ) : this.bufferSource[ 'noteOff' ]( 0 );
+ this.bufferSource[ this.bufferStop ]( 0 );
};
},
\r
// Opera Mobile 12 は 2回目以降の currentTime へのセットで currentTime が更新されなくなるため、タイマーを使用する\r
X_HTMLAudio_currentTimeFix = !!X_UA[ 'OperaMobile' ] || !!X_UA[ 'OperaTablet' ],\r
- // Firefox44.0.2 で音声の再生開始に難あり...\r
- X_HTMLAudio_playStartFix = X_UA[ 'Windows' ] && X_UA[ 'Gecko' ] === 44,\r
+ // Firefox44.0.2 で音声の再生開始に難あり... 49 でも確認, あるいはCGIで動的に生成しているmp3自体に問題があるのかも\r
+ X_HTMLAudio_playStartFix = X_UA[ 'Windows' ] && 44 <= X_UA[ 'Gecko' ],\r
\r
X_HTMLAudio_volumeFix = X_UA[ 'Chrome' ],\r
/*\r
\r
_seekingFixON : false,\r
\r
- 'Constructor' : function( disatcher, source, option ){\r
+ 'Constructor' : function( dispatcher, source, option ){\r
var raw;\r
\r
- this.disatcher = disatcher || this;\r
+ this.dispatcher = dispatcher || this;\r
this._src = source;\r
\r
if( X_HTMLAudio_shortPlayFix ){\r
},\r
\r
onDebug : function( e ){\r
- this.disatcher[ 'dispatch' ]( {\r
+ this.dispatcher[ 'dispatch' ]( {\r
type : X_EVENT_DEBUG,\r
'rawEvent' : e.type,\r
'current' : this[ '_rawObject' ].currentTime,\r
for( i = time = 0, l = buf && buf.length; i < l; ++i ){\r
time += buf[ 'end' ]( i ) - buf[ 'start' ]( i );\r
};\r
- this.disatcher[ 'dispatch' ]( { type : X_EVENT_PROGRESS, 'percent' : time * 1000 / this.duration * 100 } );\r
+ this.dispatcher[ 'dispatch' ]( { type : X_EVENT_PROGRESS, 'percent' : time * 1000 / this.duration * 100 } );\r
};\r
break;\r
\r
if( this._touchState === 1 ){\r
if( e.type === X_HTMLAudio_playTrigger ){\r
this._touchState = 2;\r
- this.disatcher[ 'asyncDispatch' ]( X_EVENT_MEDIA_WAIT_FOR_TOUCH );\r
+ this.dispatcher[ 'asyncDispatch' ]( X_EVENT_MEDIA_WAIT_FOR_TOUCH );\r
};\r
} else\r
if( ended ){\r
if( this.autoLoop ){\r
- if( !( this.disatcher[ 'dispatch' ]( X_EVENT_MEDIA_BEFORE_LOOP ) & X_CALLBACK_PREVENT_DEFAULT ) ){\r
+ if( !( this.dispatcher[ 'dispatch' ]( X_EVENT_MEDIA_BEFORE_LOOP ) & X_CALLBACK_PREVENT_DEFAULT ) ){\r
this.looped = true;\r
- this.disatcher[ 'dispatch' ]( X_EVENT_MEDIA_LOOPED );\r
+ this.dispatcher[ 'dispatch' ]( X_EVENT_MEDIA_LOOPED );\r
this.actualPlay( X_HTMLAudio_endedFixCWV && actualEnded, X_HTMLAudio_endedFixAOSP3 && actualEnded );\r
};\r
} else {\r
this.seekTime = 0;\r
delete this.playing;\r
- this.disatcher[ 'dispatch' ]( X_EVENT_MEDIA_ENDED );\r
+ this.dispatcher[ 'dispatch' ]( X_EVENT_MEDIA_ENDED );\r
};\r
} else\r
if( this._readyState === 1 && this.duration ){\r
this._readyState |= 2;\r
- this.disatcher[ 'asyncDispatch' ]( X_EVENT_READY );\r
+ this.dispatcher[ 'asyncDispatch' ]( X_EVENT_READY );\r
+ \r
+ // TODO 勝手に play する環境があるので pause() を実施\r
+ /*\r
+ if( !this.playing && !this.autoplay && !this._playReserved && !X_HTMLAudio_pauseFix ){\r
+ this.actualPause();\r
+ }; */\r
+ \r
console.log( '> Audio Loaded!! ' + e.type + ' d:' + ( this.duration | 0 ) );\r
} else\r
if( eventType ){\r
- this.disatcher[ 'dispatch' ]( eventType );\r
+ this.dispatcher[ 'dispatch' ]( eventType );\r
};\r
},\r
\r
this._endedFixON = true;\r
raw.src = this._src;\r
console.log( '△ onEndedFix の開始' );\r
- this.disatcher[ 'dispatch' ]( X_EVENT_MEDIA_WAITING );\r
+ this.dispatcher[ 'dispatch' ]( X_EVENT_MEDIA_WAITING );\r
};\r
};\r
\r
_lastState : '',\r
_interval : 0, // setInterval timer id\r
\r
- 'Constructor' : function( disatcher, source, option ){\r
+ 'Constructor' : function( dispatcher, source, option ){\r
!X_SLAudio_uid && X_TEMP.slaudioInit();\r
\r
/*\r
* http://www.atmarkit.co.jp/fdotnet/dotnettips/902slobjcallfromjs/slobjcallfromjs.html\r
* このページのサンプルは sl5+firefox32 環境で動いている。xaml を js から利用する形ではなく、.xap を sl4 以下で作るのがよさそう.\r
*/\r
- this.disatcher = disatcher || this;\r
+ this.dispatcher = dispatcher || this;\r
this._source = source;\r
// X.Audio._slOnload_ は不可\r
this._onload = 'XAudioSilverlightOnLoad' + ( ++X_SLAudio_uid );\r
if( this.playing ){\r
//X_Timer_once( 16, this, this.actualPlay );\r
} else {\r
- this.disatcher[ 'dispatch' ]( X_EVENT_ERROR ); // open failed\r
+ this.dispatcher[ 'dispatch' ]( X_EVENT_ERROR ); // open failed\r
this[ 'kill' ](); \r
};\r
break;\r
case 'MediaOpened' :\r
// http://msdn.microsoft.com/ja-jp/library/bb979710(VS.95).aspx\r
this.duration = this[ '_rawObject' ][ 'NaturalDuration' ][ 'Seconds' ] * 1000;\r
- this.disatcher[ 'asyncDispatch' ]( X_EVENT_READY );\r
+ this.dispatcher[ 'asyncDispatch' ]( X_EVENT_READY );\r
break;\r
\r
case 'MediaEnded' :\r
case 'Opening' :\r
switch( this._lastUserAction ){\r
case 'play' :\r
- this.disatcher[ 'dispatch' ]( X_EVENT_MEDIA_WAITING );\r
+ this.dispatcher[ 'dispatch' ]( X_EVENT_MEDIA_WAITING );\r
break;\r
case 'seek' :\r
- this.disatcher[ 'dispatch' ]( X_EVENT_MEDIA_SEEKING );\r
+ this.dispatcher[ 'dispatch' ]( X_EVENT_MEDIA_SEEKING );\r
break;\r
case 'pause' :\r
break;\r
this.playing = false;\r
this._ended = true;\r
this._paused = false;\r
- this.disatcher[ 'dispatch' ]( X_EVENT_ERROR );\r
+ this.dispatcher[ 'dispatch' ]( X_EVENT_ERROR );\r
this[ 'kill' ]();\r
break;\r
\r
//this.seekTime = 0;\r
this._ended = true;\r
this._paused = false;\r
- //this.disatcher[ 'dispatch' ]( X_EVENT_MEDIA_ENDED );\r
+ //this.dispatcher[ 'dispatch' ]( X_EVENT_MEDIA_ENDED );\r
//this.setCurrentTime( this.startTime );\r
break;\r
case 'pause':\r
//this.playing = true;\r
this._ended = false;\r
this._paused = false;\r
- this.disatcher[ 'dispatch' ]( X_EVENT_MEDIA_PLAYING );\r
+ this.dispatcher[ 'dispatch' ]( X_EVENT_MEDIA_PLAYING );\r
break;\r
\r
// stop()\r
break;\r
\r
case X_EVENT_KILL_INSTANCE :\r
- this.playing && this.disatcher[ 'dispatch' ]( X_EVENT_MEDIA_ENDED );\r
+ this.playing && this.dispatcher[ 'dispatch' ]( X_EVENT_MEDIA_ENDED );\r
this.playing && this.actualPause();\r
\r
if( this._onload ){\r
delete this._interval;\r
return X_CALLBACK_UN_LISTEN;\r
};\r
- this.disatcher[ 'dispatch' ]( X_EVENT_MEDIA_PLAYING );\r
+ this.dispatcher[ 'dispatch' ]( X_EVENT_MEDIA_PLAYING );\r
},\r
\r
_onEnded : function(){\r
console.log( ' > ' + time );\r
this._ended && this[ '_rawObject' ].play();\r
this._ended = false;\r
- this.disatcher[ 'dispatch' ]( X_EVENT_MEDIA_WAITING );\r
+ this.dispatcher[ 'dispatch' ]( X_EVENT_MEDIA_WAITING );\r
this._timerID = X_Timer_once( X_Audio_getEndTime( this ) - time, this, this._onEnded );\r
return;\r
};\r
\r
if( this.autoLoop ){\r
console.log( '========= loop?' );\r
- if( !( this.disatcher[ 'dispatch' ]( X_EVENT_MEDIA_BEFORE_LOOP ) & X_CALLBACK_PREVENT_DEFAULT ) ){\r
+ if( !( this.dispatcher[ 'dispatch' ]( X_EVENT_MEDIA_BEFORE_LOOP ) & X_CALLBACK_PREVENT_DEFAULT ) ){\r
console.log( '========== loopした' );\r
this.looped = true;\r
- this.disatcher[ 'dispatch' ]( X_EVENT_MEDIA_LOOPED );\r
+ this.dispatcher[ 'dispatch' ]( X_EVENT_MEDIA_LOOPED );\r
this.actualPlay();\r
};\r
} else {\r
console.log( '========= pause' );\r
this.actualPause();\r
- this.disatcher[ 'dispatch' ]( X_EVENT_MEDIA_ENDED );\r
+ this.dispatcher[ 'dispatch' ]( X_EVENT_MEDIA_ENDED );\r
};\r
};\r
},\r
_seekDirection : 0,
_timerID : 0,
- 'Constructor' : function( disatcher, source, option ){
- this.disatcher = disatcher || this;
+ 'Constructor' : function( dispatcher, source, option ){
+ this.dispatcher = dispatcher || this;
this._source = source;
if( 7 <= X_Plugin_WMP_VERSION ){
break;
case X_EVENT_KILL_INSTANCE :
- this.playing && this.disatcher[ 'dispatch' ]( X_EVENT_MEDIA_ENDED );
+ this.playing && this.dispatcher[ 'dispatch' ]( X_EVENT_MEDIA_ENDED );
this.playing && this.actualPause();
this.wmp.stop();
this.xnodeObject[ 'kill' ]();
progress = this.wmp[ 'BufferingProgress' ];
};
if( progress < 100 ){
- this.disatcher[ 'dispatch' ]( { type : X_EVENT_PROGRESS, 'percent' : progress } );
+ this.dispatcher[ 'dispatch' ]( { type : X_EVENT_PROGRESS, 'percent' : progress } );
} else {
this._readyState = 2;
if( 7 <= X_Plugin_WMP_VERSION ){
} else {
this.duration = this.wmp[ 'Duration' ] * 1000 | 0;
};
- this.disatcher[ 'dispatch' ]( X_EVENT_READY );
+ this.dispatcher[ 'dispatch' ]( X_EVENT_READY );
};
} else
// ended の判定
// waiting
if( this._seekDirection ){
if( this._seekDirection === 1 ? ( time < this._beginTime ) : ( this._lastCurrentTime <= time ) ){
- this.disatcher[ 'dispatch' ]( X_EVENT_MEDIA_SEEKING );
+ this.dispatcher[ 'dispatch' ]( X_EVENT_MEDIA_SEEKING );
return;
};
delete this._seekDirection;
};
if( time === this._lastCurrentTime ){
- this.disatcher[ 'dispatch' ]( X_EVENT_MEDIA_WAITING );
+ this.dispatcher[ 'dispatch' ]( X_EVENT_MEDIA_WAITING );
return;
};
this._lastCurrentTime = time;
// ended ではない
if( time - X_Audio_getEndTime( this ) < -50 ){
- this.disatcher[ 'dispatch' ]( X_EVENT_MEDIA_PLAYING );
+ this.dispatcher[ 'dispatch' ]( X_EVENT_MEDIA_PLAYING );
return;
};
// ended
if( this.autoLoop ){
- if( !( this.disatcher[ 'dispatch' ]( X_EVENT_MEDIA_BEFORE_LOOP ) & X_CALLBACK_PREVENT_DEFAULT ) ){
+ if( !( this.dispatcher[ 'dispatch' ]( X_EVENT_MEDIA_BEFORE_LOOP ) & X_CALLBACK_PREVENT_DEFAULT ) ){
this.looped = true;
- this.disatcher[ 'dispatch' ]( X_EVENT_MEDIA_LOOPED );
+ this.dispatcher[ 'dispatch' ]( X_EVENT_MEDIA_LOOPED );
this.actualPlay();
};
} else {
this.actualPause();
- this.disatcher[ 'dispatch' ]( X_EVENT_MEDIA_ENDED );
+ this.dispatcher[ 'dispatch' ]( X_EVENT_MEDIA_ENDED );
delete this._timerID;
return X_CALLBACK_UN_LISTEN;
};
bgmName : '',\r
bgmLooped : false,\r
bgmPlaying : false,\r
- event : null\r
+ tmpEvent : null\r
},\r
X_AudioSprite,\r
X_AudioSprite_numTracks,\r
\r
X_Audio_startDetectionBackend(\r
X_Audio_BACKENDS[ 0 ],\r
- X_AudioSprite,\r
+ X_AudioSprite, // dispatcher として\r
X_Array_copy( urls ),\r
{\r
'volume' : 0 <= volume && volume <= 1 ? volume : 1,\r
// HTMLAudio\r
( e[ 'needTouchForLoad' ] && ( _e[ 'needTouchForLoad' ] = true ) )\r
){\r
- X_AudioSprite_TEMP.event = _e;\r
+ X_AudioSprite_TEMP.tmpEvent = _e;\r
last[ 'listenOnce' ]( X_EVENT_MEDIA_WAIT_FOR_TOUCH, X_AudioSprite_backendHandler );\r
} else {\r
X_AudioSprite[ 'asyncDispatch' ]( _e );\r
\r
case X_EVENT_MEDIA_WAIT_FOR_TOUCH :\r
// TODO 全ての track の MEDIA_WAIT_FOR_TOUCH で!\r
- X_AudioSprite[ 'asyncDispatch' ]( X_AudioSprite_TEMP.event );\r
- delete X_AudioSprite_TEMP.event;\r
+ X_AudioSprite[ 'asyncDispatch' ]( X_AudioSprite_TEMP.tmpEvent );\r
+ delete X_AudioSprite_TEMP.tmpEvent;\r
break;\r
\r
case X_EVENT_PROGRESS :\r
\r
case X_EVENT_READY :\r
console.log( 'X.AudioSprite - Ready!' );\r
+ \r
+ if( X_AudioSprite_TEMP.tmpEvent ){\r
+ // このタイミングで tmpEvent が存在する場合は、タッチをスキップして Web Audio が再生可能になった\r
+ // つまり他の Web Audio インスタンスでタッチによる再生が開始され、自身も再生可能になった\r
+ \r
+ _e = X_AudioSprite_TEMP.tmpEvent;\r
+ _e[ 'needTouchForPlay' ] = false;\r
+ \r
+ X_AudioSprite\r
+ [ 'unlisten' ]( X_EVENT_MEDIA_WAIT_FOR_TOUCH, X_AudioSprite_backendHandler )\r
+ [ 'asyncDispatch' ]( _e );\r
+ \r
+ delete X_AudioSprite_TEMP.tmpEvent;\r
+ }; \r
+ \r
for( i = 0; i < X_AudioSprite_numTracks; ++i ){\r
track = X_AudioSprite_TEMP.tracks[ i ];\r
( track.autoplay || track._playReserved ) && track.actualPlay();\r