OSDN Git Service

Version 0.6.184, fi x X.AudioSprite & X.Audio, add X.WMPAudio.
authoritozyun <itozyun@user.sourceforge.jp>
Mon, 26 Oct 2015 14:22:22 +0000 (23:22 +0900)
committeritozyun <itozyun@user.sourceforge.jp>
Mon, 26 Oct 2015 14:22:22 +0000 (23:22 +0900)
12 files changed:
0.6.x/js/01_core/12_XClosure.js
0.6.x/js/01_core/21_XViewPort.js
0.6.x/js/02_dom/04_XBoxModel.js
0.6.x/js/02_dom/20_XNode.js
0.6.x/js/03_plugin/00_XPlugin.js
0.6.x/js/05_util/04_XXML.js
0.6.x/js/07_audio/00_XAudio.js
0.6.x/js/07_audio/01_XWebAudio.js
0.6.x/js/07_audio/02_XHTMLAudio.js
0.6.x/js/07_audio/03_XSilverlightAudio.js
0.6.x/js/07_audio/05_XWMPAudio.js [new file with mode: 0644]
0.6.x/js/07_audio/10_XAudioSprite.js

index a25dee0..deca998 100644 (file)
@@ -208,21 +208,14 @@ function X_Closure_proxyCallback( xfunc, _args ){
 function X_Closure_correct( f ){\r
        var i = X_CLOSURE_LIVE_LIST.indexOf( f ),\r
                obj;\r
+\r
        if( i !== -1 ){\r
                X_CLOSURE_LIVE_LIST.splice( i, 1 );\r
                X_CLOSURE_POOL_LIST[ X_CLOSURE_POOL_LIST.length ] = f;\r
                obj = f( X_Closure_COMMAND_BACK );\r
-               /*\r
-               delete obj.cbKind;\r
-               if( obj.funcName ) delete obj.funcName;\r
-               if( obj.func ) delete obj.func;\r
-               if( obj.context ) delete obj.context;\r
-               if( obj.supplement ) delete obj.supplement;\r
-               delete obj.proxy; */\r
                X_Object_clear( obj );\r
                return true;\r
        };\r
-       return false;\r
 };\r
 \r
 function X_Closure_monitor(){\r
index a89df05..5f1f098 100644 (file)
@@ -41,7 +41,7 @@ X_ViewPort = X_Class_override(
                                case 'beforeunload' :
                                        // ie では a href='javascript' な要素でも beforeunload が起こる
                                        href = e.target && e.target[ 'attr' ] && e.target[ 'attr' ]( 'href' );
-                                       if( href && href.indexOf && href.indexOf( 'javascript:' ) === 0 ) return X_CALLBACK_PREVENT_DEFAULT | X_CALLBACK_STOP_PROPAGATION;
+                                       if( X_Type_isString( href ) && !href.toLowerCase().indexOf( 'javascript:' ) ) return X_CALLBACK_PREVENT_DEFAULT | X_CALLBACK_STOP_PROPAGATION;
                                        
                                        return X_ViewPort[ 'dispatch' ]( X_EVENT_BEFORE_UNLOAD );
                                        
@@ -136,6 +136,7 @@ function X_ViewPort_changeFocus(){
 };
 
 
+// TODO EventDispatcherProxy
 /**
  * window に相当する ViewPort 情報を提供するオブジェクト。
  * @namespace X.ViewPort
index a609fc4..37391ce 100644 (file)
@@ -275,7 +275,7 @@ var X_Node_getPosition =
             var ey  =   0;\r
             //\r
             var el  =   target;\r
-            var bd  =   document.body;\r
+            var bd  =   X_elmBody;\r
             \r
             do\r
             { \r
index b775d71..c303b3d 100644 (file)
@@ -562,7 +562,7 @@ function X_Node_append( v ){
                        // 親の xnodes から v を消す
                        v.parent && v[ 'remove' ]();
                        // IE4 でテキストノードの追加、FIXED 済でない場合、親に要素の追加を通知
-                       if( X_UA[ 'IE4' ] && !v[ '_tag' ] && ( this[ '_flags' ] & X_NodeFlags_IE4_FIXED ) === 0 ) this[ '_flags' ] |= X_NodeFlags_IE4_DIRTY_CHILDREN;
+                       if( X_UA[ 'IE4' ] && !v[ '_tag' ] && ( ( this[ '_flags' ] & X_NodeFlags_IE4_FIXED ) === 0 ) ) this[ '_flags' ] |= X_NodeFlags_IE4_DIRTY_CHILDREN;
                        break;
                default :
                        return this;
@@ -638,7 +638,7 @@ function X_Node_appendAt( start, v ){
                                v[ 'remove' ]();
                        };
                        // IE4 でテキストノードの追加、FIXED 済でない場合、親に要素の追加を通知
-                       if( X_UA[ 'IE4' ] && !v[ '_tag' ] && ( this[ '_flags' ] & X_NodeFlags_IE4_FIXED ) === 0 ) this[ '_flags' ] |= X_NodeFlags_IE4_DIRTY_CHILDREN;
+                       if( X_UA[ 'IE4' ] && !v[ '_tag' ] && ( ( this[ '_flags' ] & X_NodeFlags_IE4_FIXED ) === 0 ) ) this[ '_flags' ] |= X_NodeFlags_IE4_DIRTY_CHILDREN;
                        break;
                default :
                        return this;
@@ -791,7 +791,7 @@ function X_Node_remove(){
                                X_Node_reserveRemoval[ X_Node_reserveRemoval.length ] = this;
                                X_Node_reserveUpdate();                 
                        } else
-                       if( !this[ '_tag' ] && ( parent[ '_flags' ] & X_NodeFlags_IE4_FIXED ) === 0 ){
+                       if( !this[ '_tag' ] && ( ( parent[ '_flags' ] & X_NodeFlags_IE4_FIXED ) === 0 ) ){
                                parent[ '_flags' ] |= X_NodeFlags_IE4_DIRTY_CHILDREN;
                        };
                } else {
@@ -854,7 +854,7 @@ function X_Node_onKill( that ){
                        X_Node_reserveRemoval[ X_Node_reserveRemoval.length ] = elm;
                        X_Node_reserveUpdate();                 
                } else
-               if( !that[ '_tag' ] && ( parent[ '_flags' ] & X_NodeFlags_IE4_FIXED ) === 0 ){
+               if( !that[ '_tag' ] && ( ( parent[ '_flags' ] & X_NodeFlags_IE4_FIXED ) === 0 ) ){
                        parent[ '_flags' ] |= X_NodeFlags_IE4_DIRTY_CHILDREN;
                };
        } else {
@@ -1452,7 +1452,7 @@ var X_Node__commitUpdate =
                        accumulatedFlags |= that[ '_flags' ];
                        
                        if( that[ '_flags' ] & X_NodeFlags_IE5_DISPLAY_NONE_FIX ){
-                               if( accumulatedFlags & ( X_NodeFlags_DIRTY_POSITION | X_NodeFlags_DIRTY_ID | X_NodeFlags_DIRTY_CLASSNAME ) === 0 ){
+                               if( ( accumulatedFlags & ( X_NodeFlags_DIRTY_POSITION | X_NodeFlags_DIRTY_ID | X_NodeFlags_DIRTY_CLASSNAME ) ) === 0 ){
                                        return nextElement;
                                };
                        };
@@ -1481,6 +1481,8 @@ var X_Node__commitUpdate =
                                } else
                                if( that[ '_flags' ] & X_NodeFlags_IS_SVG ){
                                        elm = document.createElementNS( 'http://www.w3.org/2000/svg', that[ '_tag' ].toLowerCase() );
+                                       
+                                       // math http://www.w3.org/1998/Math/MathML
                                } else {
                                        elm = document.createElement( that[ '_tag' ] );
                                };
@@ -1534,7 +1536,7 @@ var X_Node__commitUpdate =
                                        parentElement.appendChild( elm );
                        };
                        
-                       if( that[ '_listeners' ] && ( that[ '_flags' ] & X_NodeFlags_ACTUAL_LISTENING ) === 0 ){
+                       if( that[ '_listeners' ] && ( ( that[ '_flags' ] & X_NodeFlags_ACTUAL_LISTENING ) === 0 ) ){
                                X_EventDispatcher_toggleAllEvents( that, true );// イベントの退避
                                that[ '_flags' ] |= X_NodeFlags_ACTUAL_LISTENING;
                        };
index 07420dd..ffcdedc 100644 (file)
@@ -60,8 +60,20 @@ var X_Pulgin_FLASH_VERSION =
                            return X_Script_createActiveXObjectSafty( 'Gears.Factory' );
                        })() :
                        X_Object_find( navigator, 'mimeTypes>application/x-googlegears>enabledPlugin' )
-               );
-       
+               ),
+
+// https://support.microsoft.com/ja-jp/kb/279022
+// Windows Media Player 7 がクライアントにインストールされている場合に、自動的に Web ページに埋め込む方法
+// TODO GeckoActiveXObject
+       X_Pulgin_WMP_VERSION =  
+               !X_UA[ 'IE' ] || !X_UA[ 'ActiveX' ] ? parseFloat( X_Object_find( navigator, 'plugins>Windows Media Player Plug-in Dynamic Link Library>version' ) || 0 ) :
+               (function(){
+                           var obj = X_Script_createActiveXObjectSafty( 'WMPlayer.OCX.7' );
+
+                           return obj ? parseFloat( obj[ 'versionInfo' ] ) :
+                               X_Script_createActiveXObjectSafty( '{22D6F312-B0F6-11D0-94AB-0080C74C7E95}' ) ? 6.4 : 0;
+                       })();
+
        // QuickTime Plug-in 7.7.6
        /*
        X_Pulgin_QUICKTIME_VERSION =
@@ -79,7 +91,6 @@ var X_Pulgin_FLASH_VERSION =
                                })() :
                                0, */
 
-
 /**
  * @namespace X.Pulgin
  */
@@ -95,7 +106,9 @@ X[ 'Pulgin' ] = {
        
        //'QuickTime'          : X_Pulgin_QUICKTIME_VERSION,
        
-       'Gears'       : !!X_Pulgin_GEARS_ENABLED
+       'Gears'       : !!X_Pulgin_GEARS_ENABLED,
+       
+       'WMP'         : X_Pulgin_WMP_VERSION
        
 };
 
index 44a020d..38fcaf3 100644 (file)
@@ -540,7 +540,7 @@ var XMLWrapper_filter = {
                        for( ; xnode = xmlList[i]; ++i ){\r
                                tmp = true;\r
                                for( node = xnode.firstChild; node; node = node.nextSibling ){\r
-                                       if( node.nodeType === 1 || ( node.nodeType === 3 && node._text ) ){\r
+                                       if( node.nodeType === 1 || ( node.nodeType === 3 && node.nodeValue ) ){\r
                                                tmp = false;\r
                                                break;\r
                                        };                              \r
index 4de81ae..49d1ee1 100644 (file)
@@ -82,6 +82,7 @@ X[ 'Audio' ] = X_EventDispatcher[ 'inherits' ](
                                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
                },\r
                \r
                /**\r
@@ -176,7 +177,7 @@ X[ 'Audio' ] = X_EventDispatcher[ 'inherits' ](
 );\r
 \r
 function X_Audio_handleEvent( e ){\r
-       var backend;\r
+       var backend, pair;\r
        \r
        switch( e.type ){\r
                case X_EVENT_BACKEND_READY :\r
@@ -185,17 +186,28 @@ function X_Audio_handleEvent( e ){
                        this[ 'unlisten' ]( X_EVENT_BACKEND_NONE, X_Audio_handleEvent );\r
                        this[ 'source' ]      = e[ 'source' ];\r
                        this[ 'backendName' ] = backend.backendName;\r
+                       \r
                        X_Pair_create( this, backend.klass( this, e[ 'source' ], e[ 'option' ] ) );\r
+                       this[ 'listenOnce' ]( X_EVENT_READY, X_Audio_handleEvent );\r
+                       break;\r
+               \r
+               case X_EVENT_READY :\r
+                       pair = X_Pair_get( this );\r
+                       ( pair.autoplay || pair._playReserved ) && pair.actualPlay();\r
+                       delete pair._playReserved;\r
                        break;\r
                \r
                case X_EVENT_BACKEND_NONE :\r
+               case X_EVENT_UNLOAD :\r
                        this[ 'kill' ]();\r
                        break;\r
                \r
                case X_EVENT_KILL_INSTANCE :\r
-                       backend = X_Pair_get( this );\r
-                       backend && backend[ 'kill' ]();\r
-                       X_Pair_release( this, backend );\r
+                       X_ViewPort[ 'unlisten' ]( X_EVENT_UNLOAD, this, X_AudioSprite_handleEvent );\r
+                       if( backend = X_Pair_get( this ) ){\r
+                               backend[ 'kill' ]();\r
+                               X_Pair_release( this, backend );\r
+                       };\r
                        break;\r
        };\r
 };\r
@@ -255,8 +267,8 @@ var X_AudioBase = X_EventDispatcher[ 'inherits' ](
        {\r
                disatcher     : null,\r
                \r
-               startTime     : 0,    //\r
-               endTime       : -1,   //\r
+               startTime     : 0,    // state_startTime\r
+               endTime       : -1,   // state_startTime\r
                loopStartTime : -1,\r
                loopEndTime   : -1,\r
                seekTime      : -1,\r
@@ -269,6 +281,8 @@ var X_AudioBase = X_EventDispatcher[ 'inherits' ](
                autoplay      : false,//\r
                gain          : 0.5,\r
                \r
+               _playReserved : false,\r
+               \r
                play : function( startTime, endTime, loop, loopStartTime, loopEndTime ){\r
                        if( 0 <= startTime ){\r
                                this.setState( {\r
@@ -292,6 +306,7 @@ var X_AudioBase = X_EventDispatcher[ 'inherits' ](
                },\r
                \r
                pause : function(){\r
+                       this.seekTime = this.getActualCurrentTime();\r
                        this.playing && this.actualPause();\r
                        // delete this.autoplay\r
                        // delete this.playing\r
@@ -344,7 +359,7 @@ var X_AudioBase = X_EventDispatcher[ 'inherits' ](
                        for( k in obj ){\r
                                v = obj[ k ];\r
                                switch( k ){\r
-                                       case 'currentTime' :\r
+                                       case 'currentTime'   :\r
                                                v = X_Audio_timeStringToNumber( v );\r
                                                if( X_Type_isNumber( v ) ){\r
                                                        if( playing ){\r
@@ -440,7 +455,7 @@ var X_AudioBase = X_EventDispatcher[ 'inherits' ](
                                        case 'useVideo' :\r
                                                break;\r
                                        default :\r
-                                               throw ( 'bad arg! ' + k );\r
+                                               alert( 'bad arg! ' + k );\r
                                };\r
                        };\r
                        \r
@@ -463,6 +478,7 @@ var X_AudioBase = X_EventDispatcher[ 'inherits' ](
 \r
 function X_Audio_timeStringToNumber( time ){\r
        var ary, ms, s = 0, m = 0, h = 0;\r
+\r
        if( X_Type_isNumber( time ) ) return time;\r
        if( !X_Type_isString( time ) || !time.length ) return;\r
 \r
@@ -497,34 +513,34 @@ function X_Audio_timeStringToNumber( time ){
        return ms < 0 ? 0 : ms;\r
 };\r
 \r
-function X_Audio_getStartTime( audioWrapper, endTime, delSeekTime ){\r
-       var seek = audioWrapper.seekTime;\r
+function X_Audio_getStartTime( audioBase, endTime, delSeekTime ){\r
+       var seek = audioBase.seekTime;\r
        \r
-       if( delSeekTime ) delete audioWrapper.seekTime;\r
+       if( delSeekTime ) delete audioBase.seekTime;\r
        \r
        if( 0 <= seek ){\r
-               if( audioWrapper.duration <= seek || endTime < seek ) return 0;\r
+               if( audioBase.duration <= seek || endTime < seek ) return 0;\r
                return seek;\r
        };\r
        \r
-       if( audioWrapper.looped && 0 <= audioWrapper.loopStartTime ){\r
-               if( audioWrapper.duration <= audioWrapper.loopStartTime || endTime < audioWrapper.loopStartTime ) return 0;\r
-               return audioWrapper.loopStartTime;\r
+       if( audioBase.looped && 0 <= audioBase.loopStartTime ){\r
+               if( audioBase.duration <= audioBase.loopStartTime || endTime < audioBase.loopStartTime ) return 0;\r
+               return audioBase.loopStartTime;\r
        };\r
        \r
-       if( audioWrapper.startTime < 0 || audioWrapper.duration <= audioWrapper.startTime ) return 0;\r
-       return audioWrapper.startTime;\r
+       if( audioBase.startTime < 0 || audioBase.duration <= audioBase.startTime ) return 0;\r
+       return audioBase.startTime;\r
 };\r
 \r
-function X_Audio_getEndTime( audioWrapper ){\r
-       var duration = audioWrapper.duration;\r
+function X_Audio_getEndTime( audioBase ){\r
+       var duration = audioBase.duration;\r
        \r
-       if( audioWrapper.looped && 0 <= audioWrapper.loopEndTime ){\r
-               if( duration <= audioWrapper.loopEndTime ) return duration;\r
-               return audioWrapper.loopEndTime;\r
+       if( audioBase.looped && 0 <= audioBase.loopEndTime ){\r
+               if( duration <= audioBase.loopEndTime ) return duration;\r
+               return audioBase.loopEndTime;\r
        };\r
        \r
-       if( audioWrapper.endTime < 0 || duration <= audioWrapper.endTime ) return duration;\r
-       return audioWrapper.endTime;\r
+       if( audioBase.endTime < 0 || duration <= audioBase.endTime ) return duration;\r
+       return audioBase.endTime;\r
 };\r
 \r
index 47026ef..e33630b 100644 (file)
@@ -88,6 +88,7 @@ var X_WebAudio_context      = // 4s 以下ではない iPad 2G または iPad mi
                                                                ( window[ 'AudioContext' ] || window[ 'webkitAudioContext' ] ),
        X_WebAudio_BUFFER_LIST  = [],
        X_WebAudio_need1stTouch = X_UA[ 'iOS' ],
+       X_WebAudio_touchState   = X_WebAudio_need1stTouch,
        X_WebAudio,
        X_WebAudio_BufferLoader,
        X_WebAudio_fpsFix;
@@ -122,9 +123,13 @@ if( X_WebAudio_context ){
                        },
                        
                        handleEvent : function( e ){
+                               var i, l;
+                               
                                switch( e.type ){
                                        case X_EVENT_PROGRESS :
-                                               this[ 'dispatch' ]( { type : 'progress', 'percent' : e[ 'percent' ] } );
+                                               for( i = 0, l = this.webAudioList.length; i < l; ++i ){
+                                                       this.webAudioList[ i ][ 'dispatch' ]( { type : X_EVENT_PROGRESS, 'percent' : e[ 'percent' ] } );
+                                               };
                                                return;
                                        
                                        case X_EVENT_SUCCESS :
@@ -298,9 +303,6 @@ if( X_WebAudio_context ){
                                        this.disatcher[ 'asyncDispatch' ]( X_EVENT_READY );
                        
                        console.log( 'WebAudio buffer ready' );
-                       
-                       this.autoplay && !X_WebAudio_need1stTouch && X_Timer_once( 16, this, this.actualPlay );
-                                       
                                },
                        
                        actualPlay : function(){
@@ -309,17 +311,18 @@ if( X_WebAudio_context ){
                                console.log( '[WebAudio] play abuf:' + !!this.audioBuffer );
                                
                    if( !this.audioBuffer ){
-                       this.autoplay = true;
+                       this._playReserved = true;
                        return;
                    };
                                
-                               if( X_WebAudio_need1stTouch ){
+                               if( X_WebAudio_touchState ){
                                        e = X_EventDispatcher_CURRENT_EVENTS[ X_EventDispatcher_CURRENT_EVENTS.length - 1 ];
                                        if( !e || !e[ 'pointerType' ] ){
-                                               alert( 'タッチイベント以外での play! ' + ( e ? e.type : '' ) );
+                                               // alert( 'タッチイベント以外での play! ' + ( e ? e.type : '' ) );
                                                return;
                                        };
                                };
+                               X_WebAudio_touchState = false;
                                
                                end   = X_Audio_getEndTime( this );
                                begin = X_Audio_getStartTime( this, end, true );
@@ -408,12 +411,8 @@ if( X_WebAudio_context ){
                                },
                        
                        actualPause : function(){
-                               //if( !this.playing ) return this;
-                               
                                console.log( '[WebAudio] pause' );
                                
-                               this.seekTime = this.getActualCurrentTime();
-                               
                    this._timerID && X_Timer_remove( this._timerID );
                                delete this._timerID;
                                delete this.playing;
index 2c64eeb..786f343 100644 (file)
@@ -60,7 +60,7 @@ var
         */\r
        X_HTMLAudio_volumeEnabled   = !( X_UA[ 'WinPhone' ] && X_UA[ 'IE9' ] ) && !X_UA[ 'Opera' ],\r
        // Gecko PC + Android でseek時に再生がしばしば止まる問題の修正\r
-       X_HTMLAudio_needPlayForSeek = X_UA[ 'Gecko' ],\r
+       X_HTMLAudio_needPlayForSeek = X_UA[ 'iOS' ] || X_UA[ 'Gecko' ],\r
        // \r
        X_HTMLAudio_pauseFix            = 12 <= X_UA[ 'Opera' ] && 0 < ' XP XPSP2 2003|XP64'.indexOf( X_UA[ 'Windows' ] ), // XP + Opera12 のみ?\r
 \r
@@ -133,7 +133,6 @@ if( X_Audio_constructor ){
                                        X_elmBody.appendChild( raw );\r
                                } else {\r
                                        raw = X_TEMP.rawAudio || new X_Audio_constructor( '' );\r
-                                       // raw.loop = false; // loop を使えば ended で止まること回避できるかも 但し ended イベントが起きなくなる\r
                                        \r
                                        if( X_TEMP.rawAudio ) delete X_TEMP.rawAudio;\r
                                };\r
@@ -160,14 +159,18 @@ if( X_Audio_constructor ){
                                                'playing', 'waiting', 'seeking',\r
                                                'durationchange', 'timeupdate', 'ended' ], this.onDebug );\r
 \r
+                               if( X_HTMLAudio_endedFixAOSP2 || X_HTMLAudio_endedFixAOSP4 ){\r
+                                       raw.loop = true; // loop を使えば ended で止まること回避できるかも 但し ended イベントが起きなくなる\r
+                               };\r
+\r
                                if( X_HTMLAudio_need1stTouch ){\r
                                        raw.src = source;\r
                                } else {\r
                                        // if( this.autoplay ){\r
                                                raw.preload  = 'auto';\r
                                                raw.autoplay = true; // Android 4.0-4.1.x で必要\r
+                                               //raw.autobuffer = true;\r
                                        //};\r
-                                       //raw.autobuffer = true;\r
                                        raw.src = source;\r
                                        raw.load(); // Android4.1.1 HTL21 では必要!\r
                                };\r
@@ -177,25 +180,21 @@ if( X_Audio_constructor ){
                                this.disatcher[ 'dispatch' ]( {\r
                                        type       : X_EVENT_DEBUG,\r
                                        'rawEvent' : e.type,\r
-                                       current    : this[ '_rawObject' ].currentTime,\r
+                                       'current'  : this[ '_rawObject' ].currentTime,\r
                                        duration   : this[ '_rawObject' ].duration } );\r
                        },\r
                        \r
                        handleEvent : function( e ){\r
-                               if( !e || !e.type ) alert( 888 );\r
-                               \r
                                var raw    = this[ '_rawObject' ],\r
                                        actualEnded = e.type === 'ended',\r
                                        ended       = actualEnded,\r
+                                       i, l, buf, time,\r
                                        ready,\r
                                        eventType, duration, end, now;\r
                                \r
                                if( this._closed ) return;\r
-                               \r
-                               // global に公開\r
-                               //window[ '__rawAudio' ] = this[ '_rawObject' ];\r
-                               \r
-                               e.type !== 'timeupdate' && console.log( ' > ' + e.type );\r
+\r
+                               //e.type !== 'timeupdate' && console.log( ' > ' + e.type );\r
                                        \r
                                switch( e.type ){\r
 \r
@@ -205,7 +204,7 @@ if( X_Audio_constructor ){
                                                \r
                                                // 【javascript】モバイル向けブラウザでも音を鳴らしたい【WebAudio】\r
                                                // http://ingaouhou.com/archives/3633\r
-                                               // ・使い終わったインスタンスはload()しておくとやや安定                                          \r
+                                               // ・使い終わったインスタンスはload()しておくとやや安定\r
                                                raw.src = '';\r
                                                raw.load();\r
                                                \r
@@ -218,7 +217,14 @@ if( X_Audio_constructor ){
                                                // console.log( e.loaded + ' ' + e.total * 100 + '%' );\r
                                                // iem9 で常に0 raw.networkState;\r
                                                // opera Android 12 で buffered.end() へのアクセスはエラー try catch も無効、iem9 は常に end(0) = 0\r
-                                               //console.log( 'buffered.end ' + raw.buffered && raw.buffered.end(0) ); \r
+                                               if( !( X_UA[ 'Opera' ] && X_UA[ 'Android' ] ) && !( X_UA[ 'WinPhones' ] && X_UA[ 'IE9' ] ) && this.duration ){\r
+                                                       buf  = raw.buffered;\r
+                                                       time = 0;\r
+                                                       for( i = 0, l = 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 } );\r
+                                               };\r
                                                break;\r
                                        \r
                                        case 'loadeddata' :      //     コンテンツの表示を現在の再生位置で初めて行えるようになった場合に発生\r
@@ -254,7 +260,7 @@ if( X_Audio_constructor ){
                                                        duration = raw.duration;\r
                                                        eventType = X_EVENT_MEDIA_WAITING;\r
                                                } else\r
-                                               if( !X_HTMLAudio_durationFix && X_HTMLAudio_need1stTouch && this._touchState === 3 ){\r
+                                               if( this._touchState === 3 && !X_HTMLAudio_durationFix ){\r
                                                        this._touchState  = 0;\r
                                                        this._readyState |= 1;\r
                                                } else\r
@@ -264,12 +270,12 @@ if( X_Audio_constructor ){
                                                if( this.playing ){\r
                                                        end = X_Audio_getEndTime( this ) + this._shortPlayFixTime;\r
                                                        //console.log( now + ' / ' + end );\r
-                                                       // || now < this._lastCurrentTime // loop した場合\r
-                                                       if( 0 + end <= 0 + now ){ // 0+ なぜか iem9 で必要,,,\r
+                                                       if( ( 0 + end <= 0 + now ) || // 0+ なぜか iem9 で必要,,,\r
+                                                               ( now < this._lastCurrentTime ) ){ // loop した場合\r
                                                                if( this.autoLoop ){\r
                                                                        console.log( '☆★☆ 曲の最後に到達 @timeupdate now-end:' + ( now - end ) );\r
                                                                        ended = true;\r
-                                                                       if( X_HTMLAudio_endedFixIOS ) actualEnded = true;\r
+                                                                       //if( X_HTMLAudio_endedFixIOS ) actualEnded = true;\r
                                                                } else {\r
                                                                        this.actualPause();\r
                                                                        eventType = X_EVENT_MEDIA_ENDED;\r
@@ -325,15 +331,14 @@ if( X_Audio_constructor ){
                                                console.log( '▼ DurationFix の終了 @' + e.type );\r
                                                this._durationFixPhase = 8;\r
                                                \r
-                                               if( this.autoplay ){\r
+                                               if( this.autoplay || this._playReserved ){\r
                                                        console.log( '☆ 再生 <- DurationFix の終了' );\r
+                                                       delete this._playReserved;\r
                                                        this.actualPlay();\r
                                                } else\r
                                                if( X_HTMLAudio_pauseFix ){\r
                                                        console.log( '☆ PAUSE <- DurationFix の終了' );\r
-                                                       //raw.src = '';\r
-                                                       //raw.load();\r
-                                                       this.actualPause();                             \r
+                                                       this.actualPause();\r
                                                };\r
                                        } else\r
                                        if( this._durationFixPhase & 3 ){ // === 1 | 2\r
@@ -353,10 +358,7 @@ if( X_Audio_constructor ){
                                                if( !( this.disatcher[ 'dispatch' ]( X_EVENT_MEDIA_BEFORE_LOOP ) & X_CALLBACK_PREVENT_DEFAULT ) ){\r
                                                        this.looped = true;\r
                                                        this.disatcher[ 'dispatch' ]( X_EVENT_MEDIA_LOOPED );\r
-                                                       ( X_HTMLAudio_endedFixAOSP3 || X_HTMLAudio_endedFixAOSP4 || X_HTMLAudio_endedFixCWV || X_HTMLAudio_endedFixIOS ) && actualEnded && console.log( '☆★☆ 音声の継続用の play() @ended' );\r
-                                                       this.actualPlay(\r
-                                                               ( X_HTMLAudio_endedFixAOSP4 || X_HTMLAudio_endedFixCWV || X_HTMLAudio_endedFixIOS ) && actualEnded,\r
-                                                               ( X_HTMLAudio_endedFixAOSP3 || X_HTMLAudio_endedFixAOSP2 ) && actualEnded );\r
+                                                       this.actualPlay( X_HTMLAudio_endedFixCWV && actualEnded, X_HTMLAudio_endedFixAOSP3 && actualEnded );\r
                                                };\r
                                        } else {\r
                                                this.seekTime = 0;\r
@@ -367,7 +369,6 @@ if( X_Audio_constructor ){
                                if( this._readyState === 1 && this.duration ){\r
                                        this._readyState = 3;\r
                                        this.disatcher[ 'asyncDispatch' ]( X_EVENT_READY );\r
-                                       this.autoplay && X_Timer_once( 16, this, this.actualPlay );\r
                                        console.log( '> Audio Loaded!! ' + e.type + ' d:' + ( this.duration | 0 ) );\r
                                } else\r
                                if( eventType ){\r
@@ -396,7 +397,7 @@ if( X_Audio_constructor ){
                                        this._touchState = 3;\r
                                } else\r
                                if( this._readyState !== 3 && this._durationFixPhase < 2 ){\r
-                                       this.autoplay = true;\r
+                                       this._playReserved = true;\r
                                        return;\r
                                };\r
                                \r
@@ -431,7 +432,7 @@ if( X_Audio_constructor ){
                                        } else\r
                                        if( X_HTMLAudio_needPlayForSeek || forcePlay ){\r
                                                raw.play();\r
-                                               console.log( '[HTMLAudio] currentTime より先.' );\r
+                                               //console.log( '[HTMLAudio] currentTime より先.' );\r
                                        };\r
                                        \r
                                        //http://himaxoff.blog111.fc2.com/blog-entry-97.html\r
@@ -444,15 +445,12 @@ if( X_Audio_constructor ){
 \r
                                        console.log( '[HTMLAudio] play ' + begin + ' -> ' + end + ' crt:' + ( raw.currentTime | 0 ) + ' last:' + this._lastCurrentTime );\r
 \r
-                                       if( forceReload || ( X_HTMLAudio_endedFixAOSP4 && raw.duration && raw.currentTime === raw.duration ) ){\r
-                                               raw.src          = '';\r
-                                               raw.src          = this._src;\r
+                                       if( forceReload ){\r
                                                this.playing     = false;\r
                                                this._endedFixON = true;\r
+                                               raw.src = this._src;\r
                                                console.log( '△ onEndedFix の開始' );\r
-                                               raw.currentTime  = this._lastCurrentTime;\r
                                                this.disatcher[ 'dispatch' ]( X_EVENT_MEDIA_WAITING );\r
-                                               X_HTMLAudio_endedFixAOSP2 && raw.load();\r
                                        };\r
                                };\r
 \r
@@ -466,8 +464,6 @@ if( X_Audio_constructor ){
                                var raw = this[ '_rawObject' ];\r
                                \r
                                console.log( '[HTMLAudio] pause' );\r
-                               \r
-                               this.seekTime = this.getActualCurrentTime();\r
 \r
                                delete this._currentFixStart;\r
 \r
index 97582a7..ff2f7b5 100644 (file)
@@ -15,7 +15,7 @@
 var X_SLAudio,\r
        X_SLAudio_uid = 0;\r
 \r
-if( X[ 'Pulgin' ][ 'Silverlight' ] ){\r
+if( X_Pulgin_SILVER_LIGHT_VERSION ){\r
        \r
        X_TEMP.slaudioInit = function(){\r
                //\r
@@ -131,8 +131,6 @@ if( X[ 'Pulgin' ][ 'Silverlight' ] ){
                                                // 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
-                               \r
-                               this.autoplay && X_Timer_once( 16, this, this.actualPlay );\r
                                                break;\r
 \r
                                        case 'MediaEnded' :\r
@@ -253,7 +251,7 @@ if( X[ 'Pulgin' ][ 'Silverlight' ] ){
                                // もし kill 後に autoplayTimer で呼ばれても、_closed==true なので平気\r
                                if( this.error ) return;\r
                                if( !this.duration ){\r
-                                       this.autoplay = true;\r
+                                       this._playReserved = true;\r
                                        return;\r
                                };\r
                                \r
@@ -349,16 +347,14 @@ if( X[ 'Pulgin' ][ 'Silverlight' ] ){
                        \r
                        // SilverlightAudio.pause\r
                        actualPause : function(){\r
-                               if( this.error /*  || !this.playing */ ) return;\r
+                               if( this.error ) return;\r
                                \r
                                this._lastUserAction = 'pause';\r
-                               this.seekTime = this.getActualCurrentTime();\r
                                this.playing  = false;\r
                                this._paused  = true;\r
                                this._ended   = false;\r
                                \r
                                this[ '_rawObject' ].pause();\r
-                               //this.disatcher[ 'dispatch' ]( 'pause' );\r
                        },\r
 \r
                        getActualCurrentTime : function(){\r
@@ -366,6 +362,8 @@ if( X[ 'Pulgin' ][ 'Silverlight' ] ){
                        },\r
                        \r
                        afterUpdateState : function( result ){\r
+                               var end, halfway;\r
+                               \r
                                if( result & 3 ){ // seek\r
                        this.actualPlay();\r
                                } else\r
diff --git a/0.6.x/js/07_audio/05_XWMPAudio.js b/0.6.x/js/07_audio/05_XWMPAudio.js
new file mode 100644 (file)
index 0000000..075f537
--- /dev/null
@@ -0,0 +1,233 @@
+// https://msdn.microsoft.com/ja-jp/library/cc410695.aspx
+// Windows Media Player コントロール Version 6.4
+
+// http://www.tohoho-web.com/wwwmmd2.htm
+
+// http://devedge.primedirective.net/viewsource/2003/windows-media-in-netscape/index.html
+
+var X_WMPAudio;
+
+if( X_Pulgin_WMP_VERSION ){ // IETester で 6.x は不可
+       X_WMPAudio = X_AudioBase[ 'inherits' ](
+               'X.WMPAudio',
+               X_Class.POOL_OBJECT,
+               {
+               xnodeObject     : null,
+               wmp             : null,
+               _wmp            : null,
+               // 0 : no <object>
+               // 1 : loading
+               // 2 : loaded
+               _readyState     : 0,
+               _seekDirection  : 0,
+                       _timerID        : 0,
+                       
+                       'Constructor' : function( disatcher, source, option ){
+                               this.disatcher   = disatcher || this;
+                               this._source     = source;
+                               
+                               if( 7 <= X_Pulgin_WMP_VERSION ){
+                               this.xnodeObject = X_Node_systemNode[ 'create' ]( 'object', {
+                                                       'classID' : 'CLSID:6BF52A52-394A-11d3-B153-00C04F79FAA6',
+                                                       width     : 1,
+                                                       height    : 1
+                                               })[ 'html' ](
+                                                       X_UA[ 'IE55' ] ? '' : '<param name="uiMode" value="none">'
+                                                       //+ '<param name="URL" value="' + source + '">'
+                                                       //+ '<param name="AutoStart" value="' + option.autoplay + '">'
+                                               );
+                               } else {
+                               this.xnodeObject = X_Node_systemNode[ 'create' ]( 'object', {
+                                                       classID  : 'CLSID:22D6F312-B0F6-11D0-94AB-0080C74C7E95',
+                                                       width    : 0,
+                                                       height   : 0
+                                               })[ 'html' ](
+                                                       X_UA[ 'IE55' ] ? '' : '<param name="ShowControls" value="false">'
+                                                       //+ '<param name="FileName" value="' + source + '">'
+                                                       //+ '<param name="AutoStart" value="' + option.autoplay + '">'
+                                               );
+                               };
+                               // TODO embed
+
+                               this.setState( option );
+
+                               X_ViewPort[ 'listenOnce' ]( X_EVENT_AFTER_UPDATE, this );
+                               this[ 'listenOnce' ]( X_EVENT_KILL_INSTANCE );
+                       },
+                       
+                       handleEvent : function( e ){
+                               switch( e.type ){
+                                       case X_EVENT_AFTER_UPDATE :
+                                               this._readyState = 1;
+                                               if( 7 <= X_Pulgin_WMP_VERSION ){
+                                                       this._wmp          = this.xnodeObject[ '_rawObject' ];
+                                                       this._wmp[ 'URL' ] = this._source;
+                                                       this.wmp           = this._wmp[ 'controls' ];
+                                               } else {
+                                                       this.wmp = this.xnodeObject[ '_rawObject' ];
+                                                       this.wmp[ 'FileName' ] = this._source;
+                                               };
+                                               this._timerID = X_Timer_add( 100, 0, this, this._onTimer );
+                                               break;
+
+                                       case X_EVENT_KILL_INSTANCE :
+                                               this.playing && this.disatcher[ 'dispatch' ]( X_EVENT_MEDIA_ENDED );
+                                               this.playing && this.actualPause();
+                                           this.wmp.stop();
+                                               this.xnodeObject[ 'kill' ]();
+                                               break;
+                               };
+                       },
+                       
+                       // WMPAudio.play
+                       actualPlay : function(){
+                               var begin, offset, end;
+
+                               if( this._readyState < 2 ){
+                                       this._playReserved = true;
+                                       return;
+                               };
+                               
+                               end   = X_Audio_getEndTime( this );
+                               begin = this._beginTime = X_Audio_getStartTime( this, end, true ) | 0;
+
+                           console.log( '[play] ' + begin + ' -> ' + end );
+                           
+                           if( !this.playing ){
+                                       this.setVolume();
+                                       this.wmp.play();
+                                       
+                           this.playing = true;
+                           } else {
+                               this._seekDirection = this.getActualCurrentTime() < begin ? 1 : -1;
+                           };
+                           
+                               // 1 秒以下は指定できないため四捨五入
+                               //begin = ( begin / 1000 | 0 ) * 1000 + ( 500 < begin % 1000 ? 1000 : 0 );
+                           this.wmp[ 'CurrentPosition' ] = begin / 1000;
+                               
+                               if( !this._timerID ) this._timerID = X_Timer_add( 100, 0, this, this._onTimer );
+                       },
+                               
+                               _onTimer : function(){
+                                       var progress, time;
+                                       
+                                       // road 中の場合
+                                       if( this._readyState === 1 ){
+                                               if( 7 <= X_Pulgin_WMP_VERSION ){
+                                               progress = this._wmp[ 'network' ][ 'downloadProgress' ];
+                                               } else {
+                                               progress = this.wmp[ 'BufferingProgress' ];
+                                               };
+                                               if( progress < 100 ){
+                                                       this.disatcher[ 'dispatch' ]( { type : X_EVENT_PROGRESS, 'percent' : progress } );
+                                               } else {
+                                                       this._readyState = 2;
+                                                       if( 7 <= X_Pulgin_WMP_VERSION ){
+                                                       this.duration = this._wmp[ 'currentMedia' ].duration * 1000 | 0;
+                                                       } else {
+                                                       this.duration = this.wmp[ 'Duration' ] * 1000 | 0;
+                                                       };
+                                                       this.disatcher[ 'dispatch' ]( X_EVENT_READY );
+                                               };
+                                       } else
+                                       // ended の判定
+                           if( this.playing ){
+                               time = this.getActualCurrentTime();
+                               
+                               // waiting
+                               if( this._seekDirection ){
+                                       if( this._seekDirection === 1 ? ( time < this._beginTime ) : ( this._lastCurrentTime <= time ) ){
+                                               this.disatcher[ 'dispatch' ]( X_EVENT_MEDIA_SEEKING );
+                                               return;
+                                       };
+                                       delete this._seekDirection;
+                               };
+                               if( time === this._lastCurrentTime ){
+                                       this.disatcher[ 'dispatch' ]( X_EVENT_MEDIA_WAITING );
+                                       return;
+                               };              
+                               this._lastCurrentTime = time;
+                               
+                               // ended ではない
+                               if( time - X_Audio_getEndTime( this ) < -50 ){
+                                       this.disatcher[ 'dispatch' ]( X_EVENT_MEDIA_PLAYING );
+                                       return;
+                               };
+                               
+                               // ended
+                               if( this.autoLoop ){
+                                       if( !( this.disatcher[ 'dispatch' ]( X_EVENT_MEDIA_BEFORE_LOOP ) & X_CALLBACK_PREVENT_DEFAULT ) ){
+                                               this.looped = true;
+                                               this.disatcher[ 'dispatch' ]( X_EVENT_MEDIA_LOOPED );
+                                               this.actualPlay();
+                                       };
+                               } else {
+                                       this.actualPause();
+                                       this.disatcher[ 'dispatch' ]( X_EVENT_MEDIA_ENDED );
+                                       delete this._timerID;
+                                                       return X_CALLBACK_UN_LISTEN;
+                               };
+                           };
+                               },
+                       
+                       // WMPAudio.pause
+                       actualPause : function(){
+                               this.playing  = false;
+                               this._timerID && X_Timer_remove( this._timerID );
+                               delete this._timerID;
+                               
+                           this.wmp.pause();
+                       },
+
+                       setVolume : function(){
+                               if( 7 <= X_Pulgin_WMP_VERSION ){
+                               this._wmp[ 'settings' ][ 'Volume' ] = this.gain * 100;
+                               } else {
+                               this.wmp[ 'Volume' ] = ( 1 - this.gain ) * 10000;
+                               };                              
+                       },
+
+                       getActualCurrentTime : function(){
+                           return this.wmp[ 'CurrentPosition' ] * 1000 | 0;
+                       },
+                       
+                       afterUpdateState : function( result ){
+                               if( result & 3 ){ // seek
+                       this.actualPlay();
+                               } else
+                               if( result & 4 ){
+                                       this.setVolume();
+                               };                      
+                       }
+
+               }
+       );
+
+       X_Audio_BACKENDS.push( {
+               backendID   : 16,
+               
+               backendName : 'WMP' + X_Pulgin_WMP_VERSION,
+
+               canPlay : {
+                       'mp3'  : true,
+                       'wma'  : true,
+                       'wav'  : true,
+                       'mid'  : true,
+                       'midi' : true,
+                       'snd'  : true,
+                       'au'   : true,
+                       'aif'  : true,
+                       'aicf' : true,
+                       'aiff' : true
+               },
+
+               detect : function( proxy, source, ext ){
+                       proxy[ 'asyncDispatch' ]( { type : X_EVENT_COMPLETE, canPlay : ext === 'mp3' || ext === 'wma' || ext === 'wav' } );                             
+               },
+               
+               klass : X_WMPAudio
+               
+       } );
+
+};
\ No newline at end of file
index 57e5d41..763eca7 100644 (file)
@@ -17,7 +17,6 @@ var X_AudioSprite_shouldUse         = X_HTMLAudio && ( X_UA[ 'iOS' ] || X_UA[ 'A
        X_AudioSprite_lengthSilence    = 10000, // 一番最初の無音部分の長さ\r
        X_AudioSprite_lengthDistance   = 5000,  // 音間の無音の長さ\r
        X_AudioSprite_uid              = 0,\r
-       X_AudioSprite_members          = {},\r
        X_AudioSprite_TEMP             = {\r
                presets     : {},\r
                BGMs        : {},\r
@@ -30,7 +29,7 @@ var X_AudioSprite_shouldUse         = X_HTMLAudio && ( X_UA[ 'iOS' ] || X_UA[ 'A
                bgmLooped   : false,\r
                bgmPlaying  : false\r
        },\r
-       X_AudioSprite_instance,\r
+       X_AudioSprite,\r
        X_AudioSprite_numTracks,\r
        X_AudioSprite_useVideo;\r
 \r
@@ -61,18 +60,12 @@ X[ 'AudioSprite' ] = function( setting ){
                urls    = setting[ 'urls' ],\r
                video   = setting[ 'useVideo' ],\r
                n       = video ? 1 : setting[ 'numTracks' ] || 1,\r
-               option  = {\r
-                       volume    : setting[ 'volume' ] || 0.5,\r
-                       autoplay  : true,\r
-                       startTime : 0,\r
-                       endTime   : X_AudioSprite_lengthSilence,\r
-                       loop      : true\r
-               },\r
-               k, i, v, track; \r
+               volume  = setting[ 'volume' ],\r
+               k, i, v, track;\r
        \r
-       if( !X_AudioSprite_instance ){\r
-               X_AudioSprite_instance = X_Class_override( X_EventDispatcher(), X_AudioSprite_members );\r
-               X_ViewPort[ 'listen' ]( [ X_EVENT_VIEW_ACTIVATE, X_EVENT_VIEW_DEACTIVATE ], X_AudioSprite_instance, X_AudioSprite_handleEvent );\r
+       if( !X_AudioSprite ){\r
+               X_AudioSprite = X_Class_override( X_EventDispatcher(), X_AudioSprite_members );\r
+               X_ViewPort[ 'listen' ]( [ X_EVENT_VIEW_ACTIVATE, X_EVENT_VIEW_DEACTIVATE, X_EVENT_UNLOAD ], X_AudioSprite, X_AudioSprite_handleEvent );\r
        };\r
        \r
        n = n <= X_AudioSprite_maxTracks ? n : X_AudioSprite_maxTracks;\r
@@ -96,15 +89,25 @@ X[ 'AudioSprite' ] = function( setting ){
                };\r
        };\r
        \r
-       X_Audio_startDetectionBackend( X_Audio_BACKENDS[ 0 ], X_AudioSprite_instance, X_Array_copy( urls ), option );\r
+       X_Audio_startDetectionBackend(\r
+               X_Audio_BACKENDS[ 0 ],\r
+               X_AudioSprite,\r
+               X_Array_copy( urls ),\r
+               {\r
+                       'volume'    : 0 <= volume && volume <= 1 ? volume : 1,\r
+                       'autoplay'  : true,\r
+                       'startTime' : 0,\r
+                       'endTime'   : X_AudioSprite_lengthSilence,\r
+                       'loop'      : true\r
+               });\r
 \r
-       X_AudioSprite_instance[ 'listenOnce' ]( [ X_EVENT_BACKEND_READY, X_EVENT_BACKEND_NONE ], X_AudioSprite_backendHandler );\r
-       X_AudioSprite_instance[ 'listenOnce' ]( X_EVENT_KILL_INSTANCE, X_AudioSprite_handleEvent );\r
+       X_AudioSprite[ 'listenOnce' ]( [ X_EVENT_BACKEND_READY, X_EVENT_BACKEND_NONE ], X_AudioSprite_backendHandler );\r
+       X_AudioSprite[ 'listenOnce' ]( X_EVENT_KILL_INSTANCE, X_AudioSprite_handleEvent );\r
        \r
        X_AudioSprite_useVideo  = video;\r
-       X_AudioSprite_numTracks = X_AudioSprite_instance[ 'numTracks' ] = n;\r
+       X_AudioSprite_numTracks = X_AudioSprite[ 'numTracks' ] = n;\r
 \r
-       return X_AudioSprite_instance;\r
+       return X_AudioSprite;\r
 };\r
 \r
 X[ 'AudioSprite' ][ 'shouldUse'        ] = X_AudioSprite_shouldUse;\r
@@ -114,7 +117,7 @@ X[ 'AudioSprite' ][ 'enableMultiTrack' ] = !X_AudioSprite_disableMultiTrack;
 // TODO 終わりかけのもの、と一番古いもの、どちらを再利用するか?これ以上に細かい実装を望む場合は X.AudioSprite は使わず自力で実装\r
 function X_AudioSprite_getTrackEnded(){\r
        var tracks  = X_AudioSprite_TEMP.tracks,\r
-               l = tracks.length,\r
+               l = X_AudioSprite_numTracks,\r
                i = 0, track, state, last = 1 / 0, _last, index;\r
        \r
        for( ; i < l; ++i ){\r
@@ -132,7 +135,7 @@ function X_AudioSprite_getTrackEnded(){
        return tracks[ index ];\r
 };\r
 \r
-X_AudioSprite_members =\r
+var X_AudioSprite_members =\r
 /** @lends X.AudioSprite.prototype */\r
 {\r
                /**\r
@@ -141,21 +144,6 @@ X_AudioSprite_members =
                'numTracks' : 0,\r
                \r
                /**\r
-                * モバイル用タッチイベント中に呼び出す\r
-                */\r
-               'on1stTouch' : function(){\r
-                       var i = 0, l = X_AudioSprite_TEMP.tracks.length;\r
-\r
-                       for( ; i < l; ++i ){\r
-                               //if( X_UA[ 'iOS' ] ){\r
-                               //      X_AudioSprite_TEMP.tracks[ i ][ '_rawObject' ].load();\r
-                               //} else {\r
-                                       X_AudioSprite_instance[ 'pause' ]( i );\r
-                               //};\r
-                       };\r
-               },\r
-               \r
-               /**\r
                 * 再生\r
                 * @param {string} name トラック名\r
                 * @return {number} uid\r
@@ -182,13 +170,13 @@ X_AudioSprite_members =
                                        if( bgm ){\r
                                                track = bgm;\r
                                        } else\r
-                                       if( 1 < tracks.length ){\r
+                                       if( 1 < X_AudioSprite_numTracks ){\r
                                                track = X_AudioSprite_TEMP.bgmTrack = X_AudioSprite_getTrackEnded();\r
                                        } else {\r
                                                track = X_AudioSprite_TEMP.bgmTrack = tracks[ 0 ];\r
                                        };\r
                                        \r
-                                       if( track[ 'listen' ]( [ X_EVENT_MEDIA_PLAYING, X_EVENT_MEDIA_WAITING, X_EVENT_MEDIA_SEEKING, X_EVENT_MEDIA_BEFORE_LOOP ], X_AudioSprite_instance, X_AudioSprite_handleEvent ).playing ){\r
+                                       if( track[ 'listen' ]( [ X_EVENT_MEDIA_PLAYING, X_EVENT_MEDIA_WAITING, X_EVENT_MEDIA_SEEKING, X_EVENT_MEDIA_BEFORE_LOOP ], X_AudioSprite, X_AudioSprite_handleEvent ).playing ){\r
                                                track.setState({\r
                                                                'loop'          : true,\r
                                                                'looped'        : X_AudioSprite_TEMP.bgmLooped,\r
@@ -205,10 +193,10 @@ X_AudioSprite_members =
                                        };\r
                                        \r
                                } else {\r
-                                       if( 1 < tracks.length ){\r
+                                       if( 1 < X_AudioSprite_numTracks ){\r
                                                track = X_AudioSprite_getTrackEnded( X_AudioSprite_TEMP.bgmPlaying );\r
                                                track\r
-                                                       [ 'listen' ]( [ X_EVENT_MEDIA_PLAYING, X_EVENT_MEDIA_WAITING, X_EVENT_MEDIA_SEEKING, X_EVENT_MEDIA_BEFORE_LOOP ], X_AudioSprite_instance, X_AudioSprite_handleEvent )\r
+                                                       [ 'listen' ]( [ X_EVENT_MEDIA_PLAYING, X_EVENT_MEDIA_WAITING, X_EVENT_MEDIA_SEEKING, X_EVENT_MEDIA_BEFORE_LOOP ], X_AudioSprite, X_AudioSprite_handleEvent )\r
                                                        .setState( { 'looped' : false } );\r
                                                track.play( preset[ 0 ], preset[ 1 ], true, 0, X_AudioSprite_lengthSilence );\r
                                        } else {\r
@@ -220,11 +208,11 @@ X_AudioSprite_members =
                                                };\r
                                                track = tracks[ 0 ];\r
                                        \r
-                                               if( track[ 'listen' ]( [ X_EVENT_MEDIA_PLAYING, X_EVENT_MEDIA_WAITING, X_EVENT_MEDIA_SEEKING, X_EVENT_MEDIA_BEFORE_LOOP ], X_AudioSprite_instance, X_AudioSprite_handleEvent ).playing ){\r
+                                               if( track[ 'listen' ]( [ X_EVENT_MEDIA_PLAYING, X_EVENT_MEDIA_WAITING, X_EVENT_MEDIA_SEEKING, X_EVENT_MEDIA_BEFORE_LOOP ], X_AudioSprite, X_AudioSprite_handleEvent ).playing ){\r
                                                        track.setState({\r
                                                                        'loop'          : true,\r
                                                                        'looped'        : false,\r
-                                                                       //'currentTime'   : preset[ 0 ],\r
+                                                                       'currentTime'   : preset[ 0 ],\r
                                                                        'startTime'     : preset[ 0 ],\r
                                                                        'endTime'       : preset[ 1 ],\r
                                                                        'loopStartTime' : 0,\r
@@ -242,26 +230,34 @@ X_AudioSprite_members =
                },\r
                \r
                /**\r
-                * ポーズ\r
-                * @param {number} uid トラックID\r
-                * @return {number} uid\r
+                * ポーズ, uid を指定しない、または '*' で呼び出した場合、全てのトラックを pause する。\r
+                * @param {number} uid=undefined トラックID, '*'\r
+                * @return {AudioSprite}\r
                 */\r
                'pause' : function( uid ){\r
-                       var track = X_AudioSprite_TEMP.tracks[ uid ];\r
+                       var tracks = X_AudioSprite_TEMP.tracks,\r
+                               i, l, track;\r
                        \r
-                       if( X_AudioSprite_TEMP.bgmTrack === track ){\r
-                               X_AudioSprite_TEMP.bgmPosition = track.currentTime();\r
-                               X_AudioSprite_TEMP.bgmPlaying  = false;\r
-                               X_AudioSprite_TEMP.bgmTrack    = null;\r
+                       if( uid === '*' || uid === undefined ){\r
+                               for( i = 0, l = X_AudioSprite_numTracks; i < l; ++i ){\r
+                                       X_AudioSprite[ 'pause' ]( i );\r
+                               };\r
+                       } else\r
+                       if( track = tracks[ uid ] ){\r
+                               if( X_AudioSprite_TEMP.bgmTrack === track ){\r
+                                       X_AudioSprite_TEMP.bgmPosition = track.currentTime();\r
+                                       X_AudioSprite_TEMP.bgmPlaying  = false;\r
+                                       X_AudioSprite_TEMP.bgmTrack    = null;\r
+                               };\r
+                               track.play( 0, X_AudioSprite_lengthSilence, true, 0, X_AudioSprite_lengthSilence );\r
+                               track.seek( 0 );\r
+                               X_AudioSprite[ 'asyncDispatch' ]( X_EVENT_MEDIA_PAUSED );                               \r
                        };\r
-                       track && track.play( 0, X_AudioSprite_lengthSilence, true, 0, X_AudioSprite_lengthSilence );\r
-                       track && track.seek( 0 );\r
-                       X_AudioSprite_instance[ 'asyncDispatch' ]( X_EVENT_MEDIA_PAUSED );\r
-                       return X_AudioSprite_instance;\r
+                       return X_AudioSprite;\r
                },\r
                \r
                /**\r
-                * シーク\r
+                * シーク, 現在のトラックの長さ内で相対指定する\r
                 * @param {number} uid トラックID\r
                 * @param {number} position ms\r
                 * @return {AudioSprite}\r
@@ -275,7 +271,7 @@ X_AudioSprite_members =
                                start = X_Audio_getStartTime( track, end );\r
                                0 <= position && position <= ( end - start ) && track.seek( start + position );\r
                        };\r
-                       return X_AudioSprite_instance;\r
+                       return X_AudioSprite;\r
                },\r
                \r
                /**\r
@@ -291,17 +287,17 @@ X_AudioSprite_members =
                                if( opt_volume === undefined ){\r
                                        return X_AudioSprite_TEMP.volume;\r
                                };\r
-                               for( i = X_AudioSprite_TEMP.tracks.length; i; ){\r
+                               for( i = X_AudioSprite_numTracks; i; ){\r
                                        X_AudioSprite_TEMP.tracks[ --i ].volume( opt_volume );\r
                                };\r
-                               return X_AudioSprite_instance;\r
+                               return X_AudioSprite;\r
                        };\r
                        track = X_AudioSprite_TEMP.tracks[ uid ];\r
                        if( opt_volume === undefined ){\r
                                return track ? track.gain : -1;\r
                        };\r
                        track && track.volume( opt_volume );\r
-                       return X_AudioSprite_instance;\r
+                       return X_AudioSprite;\r
                },\r
                \r
                /**\r
@@ -329,12 +325,12 @@ X_AudioSprite_members =
                                return { 'volume' : X_AudioSprite_TEMP.volume, 'playing' : false };\r
                        };\r
                        track && track.setState( opt_obj );\r
-                       return X_AudioSprite_instance;\r
+                       return X_AudioSprite;\r
                }\r
 };\r
 \r
 function X_AudioSprite_backendHandler( e ){\r
-       var i, backend, option, src, name, last, _e;\r
+       var i, backend, option, src, name, last, _e, track;\r
        \r
        switch( e.type ){\r
                case X_EVENT_BACKEND_READY :\r
@@ -342,19 +338,21 @@ function X_AudioSprite_backendHandler( e ){
                        backend = X_Audio_BACKENDS[ e[ 'backendID' ] ];\r
                        option  = e[ 'option' ];\r
                        \r
-                       X_AudioSprite_instance[ 'unlisten' ]( X_EVENT_BACKEND_NONE, X_AudioSprite_backendHandler );\r
-                       X_AudioSprite_instance[ 'source' ]      = src = e[ 'source' ];\r
-                       X_AudioSprite_instance[ 'backendName' ] = name = backend.backendName;\r
+                       X_AudioSprite[ 'unlisten' ]( X_EVENT_BACKEND_NONE, X_AudioSprite_backendHandler );\r
+                       X_AudioSprite[ 'source' ]      = src = e[ 'source' ];\r
+                       X_AudioSprite[ 'backendName' ] = name = backend.backendName;\r
                \r
                        //console.log( i + ' / ' + X_AudioSprite_numTracks );\r
                \r
                        for( i = 0; i < X_AudioSprite_numTracks; ++i ){\r
                                if( X_AudioSprite_useVideo || ( i === 1 && X_AudioSprite_useVideoForMulti ) ){\r
+                                       option = X_Object_deepCopy( option );\r
                                        option[ 'useVideo' ] = true;\r
                                        console.log( 'use video' );\r
                                };\r
                                // Audiobackend の owner として null を渡すとAudioBackend 自身へ dispatch する\r
-                               X_AudioSprite_TEMP.tracks.push( last = backend.klass( null, e[ 'source' ], option )[ 'listen' ]( X_EVENT_DEBUG, X_AudioSprite_instance, X_AudioSprite_handleEvent ) );\r
+                               X_AudioSprite_TEMP.tracks.push(\r
+                                       last = backend.klass( null, e[ 'source' ], option )[ 'listen' ]( X_EVENT_DEBUG, X_AudioSprite, X_AudioSprite_handleEvent ) );\r
                        };\r
 \r
                        _e = {\r
@@ -363,51 +361,33 @@ function X_AudioSprite_backendHandler( e ){
                                'backendName' : name\r
                        };\r
                        // touch 可能で backend ready\r
-                       \r
-                       if( name === 'WebAudio' ){\r
-                               if( _e[ 'needTouchForPlay' ] = X_WebAudio_need1stTouch ){\r
-                                       last[ 'listenOnce' ]( X_EVENT_READY, X_AudioSprite_instance, X_AudioSprite_instance[ 'asyncDispatch' ], [ _e ] );\r
-                               } else {\r
-                                       X_AudioSprite_instance[ 'asyncDispatch' ]( _e );\r
-                               };\r
-                               last[ 'listenOnce' ]( X_EVENT_READY, X_AudioSprite_instance, X_AudioSprite_backendHandler );\r
+                       // WebAudio\r
+                       if( backend.backendID === 1 && ( _e[ 'needTouchForPlay' ] = X_WebAudio_need1stTouch ) ){\r
+                               last[ 'listenOnce' ]( X_EVENT_READY, X_AudioSprite, X_AudioSprite[ 'asyncDispatch' ], [ _e ] );\r
                        } else\r
-                       if( name === 'HTMLAudio' ){\r
-                               if( _e[ 'needTouchForLoad' ] = X_HTMLAudio_need1stTouch ){\r
-                                       last[ 'listenOnce' ]( X_EVENT_MEDIA_TOUCH_FOR_LOAD, X_AudioSprite_instance, X_AudioSprite_instance[ 'asyncDispatch' ], [ _e ] );\r
-                                       last[ 'listenOnce' ]( X_EVENT_READY, X_AudioSprite_instance, X_AudioSprite_backendHandler );\r
-                               } else {\r
-                                       X_AudioSprite_instance[ 'asyncDispatch' ]( _e );\r
-                                       last[ 'listenOnce' ]( X_EVENT_READY, X_AudioSprite_instance, X_AudioSprite_backendHandler );\r
-                                       \r
-                                       // READY, needTouchForPlay, needTouchForLoad\r
-                                       if( X_HTMLAudio_durationFix ){\r
-                                               for( i = 0; i < X_AudioSprite_TEMP.tracks.length; ++i ){\r
-                                                       X_AudioSprite_instance[ 'pause' ]( i );\r
-                                               };\r
-                                       };\r
-                               };\r
-                               \r
+                       // HTMLAudio\r
+                       if( backend.backendID === 2 && ( _e[ 'needTouchForLoad' ] = X_HTMLAudio_need1stTouch ) ){\r
+                               last[ 'listenOnce' ]( X_EVENT_MEDIA_TOUCH_FOR_LOAD, X_AudioSprite, X_AudioSprite[ 'asyncDispatch' ], [ _e ] );\r
                        } else {\r
-                               X_AudioSprite_instance[ 'asyncDispatch' ]( _e );\r
-                               \r
-                               console.log( 'AudioSprite - X_EVENT_BACKEND_READY' );\r
-                               \r
-                               last[ 'listenOnce' ]( X_EVENT_READY, X_AudioSprite_instance, X_AudioSprite_backendHandler );\r
+                               X_AudioSprite[ 'asyncDispatch' ]( _e );\r
                        };\r
+                       \r
+                       last[ 'listenOnce' ]( X_EVENT_READY, X_AudioSprite, X_AudioSprite_backendHandler );\r
                        return X_CALLBACK_STOP_NOW;\r
 \r
                case X_EVENT_BACKEND_NONE :\r
-                       X_AudioSprite_instance[ 'unlisten' ]( X_EVENT_BACKEND_READY, X_AudioSprite_instance, X_AudioSprite_backendHandler )\r
+                       X_AudioSprite[ 'unlisten' ]( X_EVENT_BACKEND_READY, X_AudioSprite, X_AudioSprite_backendHandler )\r
                                [ 'asyncDispatch' ]( X_EVENT_BACKEND_NONE );\r
                        return X_CALLBACK_STOP_NOW;\r
                \r
                case X_EVENT_READY :\r
                        console.log( 'X.AudioSprite - Ready!' );\r
-                       for( i = 0; i < X_AudioSprite_TEMP.tracks.length; ++i ){\r
-                               X_AudioSprite_instance[ 'pause' ]( i );\r
+                       for( i = 0; i < X_AudioSprite_numTracks; ++i ){\r
+                               track = X_AudioSprite_TEMP.tracks[ i ];\r
+                               ( track.autoplay || track._playReserved ) && track.actualPlay();\r
+                               delete track._playReserved;\r
                        };\r
-                       X_AudioSprite_instance[ 'asyncDispatch' ]( X_EVENT_READY );\r
+                       X_AudioSprite[ 'asyncDispatch' ]( X_EVENT_READY );\r
                        break;\r
        };\r
 };\r
@@ -418,22 +398,22 @@ function X_AudioSprite_handleEvent( e ){
        \r
        switch( e.type ){\r
                case X_EVENT_MEDIA_PLAYING :\r
-                       ( e.target === X_AudioSprite_TEMP.bgmTrack || !e.target.looped ) &&  X_AudioSprite_instance[ 'asyncDispatch' ]( X_EVENT_MEDIA_PLAYING );\r
+                       ( e.target === X_AudioSprite_TEMP.bgmTrack || !e.target.looped ) &&  X_AudioSprite[ 'asyncDispatch' ]( X_EVENT_MEDIA_PLAYING );\r
                        break;\r
                case X_EVENT_MEDIA_WAITING :\r
                case X_EVENT_MEDIA_SEEKING :\r
-                       ( e.target === X_AudioSprite_TEMP.bgmTrack || !e.target.looped ) &&  X_AudioSprite_instance[ 'asyncDispatch' ]( e.type );\r
+                       ( e.target === X_AudioSprite_TEMP.bgmTrack || !e.target.looped ) &&  X_AudioSprite[ 'asyncDispatch' ]( e.type );\r
                        break;\r
                \r
                case X_EVENT_MEDIA_BEFORE_LOOP :\r
                        if( e.target === X_AudioSprite_TEMP.bgmTrack ){\r
                                X_AudioSprite_TEMP.bgmLooped = true;\r
-                                X_AudioSprite_instance[ 'asyncDispatch' ]( X_EVENT_MEDIA_LOOPED ); // TODO uid\r
+                               X_AudioSprite[ 'asyncDispatch' ]( X_EVENT_MEDIA_LOOPED ); // TODO uid\r
                        } else {\r
                                if( e.target.looped ){\r
-                                       // X_AudioSprite_instance[ 'asyncDispatch' ]( X_EVENT_MEDIA_LOOPED ); // TODO uid\r
+                                       // X_AudioSprite[ 'asyncDispatch' ]( X_EVENT_MEDIA_LOOPED ); // TODO uid\r
                                } else {\r
-                                        X_AudioSprite_instance[ 'asyncDispatch' ]( X_EVENT_MEDIA_ENDED ); // TODO uid\r
+                                        X_AudioSprite[ 'asyncDispatch' ]( X_EVENT_MEDIA_ENDED ); // TODO uid\r
                                };\r
                                \r
                                //console.log( '[AudioSprite] bgmPlaying:' + X_AudioSprite_TEMP.bgmPlaying + ' ' + !X_AudioSprite_TEMP.bgmTrack );\r
@@ -441,7 +421,7 @@ function X_AudioSprite_handleEvent( e ){
                                // single track | iOS\r
                                if( X_AudioSprite_TEMP.bgmPlaying && !X_AudioSprite_TEMP.bgmTrack ){\r
                                        X_AudioSprite_TEMP.bgmTrack = e.target;\r
-                                        X_AudioSprite_instance.play( X_AudioSprite_TEMP.bgmName );\r
+                                       X_AudioSprite.play( X_AudioSprite_TEMP.bgmName );\r
                                        return X_CALLBACK_PREVENT_DEFAULT;\r
                                };\r
                        };\r
@@ -452,7 +432,7 @@ function X_AudioSprite_handleEvent( e ){
                        i = X_AudioSprite_TEMP.tracks.indexOf( e.target );\r
                        if( 0 <= i ){\r
                                e[ 'trackID' ] = i;\r
-                               X_AudioSprite_instance[ 'dispatch' ]( e );\r
+                               X_AudioSprite[ 'dispatch' ]( e );\r
                        };\r
                        break;\r
                \r
@@ -468,15 +448,17 @@ function X_AudioSprite_handleEvent( e ){
                        console.log( '■ デアクティブ' );\r
                        // track.pause();\r
                        tracks = X_AudioSprite_TEMP.tracks;\r
-                       i      = tracks.length;\r
+                       i      = X_AudioSprite_numTracks;\r
                        for( ; i; ){\r
                                track = tracks[ --i ];\r
                                track.playing && X_AudioSprite_TEMP.pauseTracks.push( track ) && track.pause();\r
                        };\r
                        break;\r
                \r
+               case X_EVENT_UNLOAD :\r
+                       console.log( '■ unload' );\r
+               \r
                case X_EVENT_KILL_INSTANCE :\r
-                       \r
                        while( X_AudioSprite_TEMP.tracks.length ){\r
                                X_AudioSprite_TEMP.tracks.pop()[ 'kill' ]();\r
                        };\r
@@ -494,7 +476,7 @@ function X_AudioSprite_handleEvent( e ){
                        X_AudioSprite_TEMP.bgmLooped   = false;\r
                        X_AudioSprite_TEMP.bgmPlaying  = false;\r
                        \r
-                       X_ViewPort[ 'unlisten' ]( [ X_EVENT_VIEW_ACTIVATE, X_EVENT_VIEW_DEACTIVATE ],  X_AudioSprite_instance, X_AudioSprite_handleEvent );\r
+                       X_ViewPort[ 'unlisten' ]( [ X_EVENT_VIEW_ACTIVATE, X_EVENT_VIEW_DEACTIVATE, X_EVENT_UNLOAD ],  X_AudioSprite, X_AudioSprite_handleEvent );\r
                        break;\r
        };\r
 };\r