OSDN Git Service

Version 0.6.114, add AudioSprite, etc.
authoritozyun <itozyun@user.sourceforge.jp>
Tue, 25 Nov 2014 18:41:45 +0000 (03:41 +0900)
committeritozyun <itozyun@user.sourceforge.jp>
Tue, 25 Nov 2014 18:41:45 +0000 (03:41 +0900)
14 files changed:
0.6.x/js/02_dom/06_XNodeCSS.js
0.6.x/js/05_util/01_XNinjaIframe.js
0.6.x/js/05_util/03_XUtilImage.js
0.6.x/js/06_net/01_XNetXHR.js
0.6.x/js/06_net/02_XNetJSONP.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/10_XAudioSprite.js [new file with mode: 0644]
0.6.x/js/20_ui/14_ChromeBox.js
0.6.x/js/20_ui/15_ScrollBox.js
0.6.x/js/20_ui/20_PageRoot.js
0.6.x/js/import.js

index 8bb9256..f898b74 100644 (file)
@@ -730,8 +730,11 @@ X.CSS = {
                };
        };
        
-       testStyle.cssText = 'background:rgba(0,0,0,0.5)';
-       X_Node_CSS_Support[ 'rgba' ] = !!testStyle.background;
+       testStyle.cssText = 'background:rgba(0,0,0,0.5);border-color:transparent';
+       X_Node_CSS_Support[ 'rgba' ] = !!testStyle[ 'background' ];
+       X_Node_CSS_Support[ 'transparent' ] = !!testStyle[ 'borderColor' ];
+       // TODO border による三角形の可否
+       // 2:完全、 1:透過に非対応(IE7-) 0:borderの描画が非標準で三角形が作れない
        
                /*
                 * chrome 1+, ff3.5(1.9.1), ie9+, opera10.5+, Safari3+(522)
index 93f62f1..8a026f0 100644 (file)
@@ -3,6 +3,7 @@
  * 孤立するとウィンドウ オブジェクトのプロパティが消去される\r
  */\r
 \r
+// TODO Node.inherits\r
 X.Util.NinjaIframe = X.EventDispatcher.inherits(\r
        'NinjaIframe',\r
        {\r
@@ -26,8 +27,9 @@ X.Util.NinjaIframe = X.EventDispatcher.inherits(
                                {\r
                                        className         : 'hidden-iframe',\r
                                        scrolling         : 'no',\r
+                                       allowtransparency : 'no',                                       \r
                                        frameborder       : 0,\r
-                                       allowtransparency : 'no',\r
+                                       tabindex          : -1,\r
                                        name              : this._name,\r
                                        id                : this._name\r
                                }\r
@@ -59,7 +61,7 @@ X.Util.NinjaIframe = X.EventDispatcher.inherits(
                                        // こちらに名前をsetしないとtargetが動作しない\r
                                        this._iwin.name = this._name;\r
                                        \r
-                                       this.xnodeIframe.listen( X_UA.IE < 9 ? [ 'readystatechange', 'error' ] : [ 'load', 'error' ], this );\r
+                                       this.xnodeIframe.listen( [ X_UA.IE < 9 ? 'readystatechange' : 'load', 'error' ], this );\r
                                        \r
                                        if( !( X_UA.IE < 9 ) ){\r
                                                this._html && X_Util_NinjaIframe_writeToIframe( this );\r
@@ -73,7 +75,7 @@ X.Util.NinjaIframe = X.EventDispatcher.inherits(
                                        if( !this._ready ){\r
                                                this._html && X_Util_NinjaIframe_writeToIframe( this );\r
                                                this._ready = true;\r
-                                               return;                 \r
+                                               return;\r
                                        };\r
                                        // onload\r
                                case 'load' :\r
index e4c1457..0efef95 100644 (file)
@@ -8,6 +8,10 @@ X.Util.Image = {
 };\r
 \r
 /*\r
+ * Opacity不可 NetFront3.4\r
+ */\r
+\r
+/*\r
  * original\r
  * LICENSE: MIT\r
  * AUTHOR: uupaa.js@gmail.com\r
index b311ce7..71f24fc 100644 (file)
@@ -18,6 +18,13 @@ new ActiveXObject( 'Msxml2.XMLHTTP' );     // バージョンを省略すると
 new ActiveXObject( 'Msxml2.XMLHTTP.4.0' ); // バージョン4.0 は bugfix が行われないので、3.0 か 6.0 を指定すべき\r
 new ActiveXObject( 'Msxml2.XMLHTTP.5.0' ); // バージョン5.0 は bugfix が行われないので、3.0 か 6.0 を指定すべき\r
 \r
+[IE][Javascript][Json] IE+JsonではまったAdd Star\r
+http://d.hatena.ne.jp/khiker/20081026/javascript_json\r
+> AddCharset utf-8 json\r
+> AddType text/javascript json\r
+\r
+JavaScriptでJSONをeval\r
+http://d.hatena.ne.jp/sshi/20060904/p1\r
  */\r
 var X_Net_XHR_W3C      = ( !X_UA.IE7 || !X_URL_IS_LOCAL ) && window[ 'XMLHttpRequest' ] && new XMLHttpRequest(),\r
        X_Net_XHR_X_DOMAIN = window[ 'XDomainRequest' ] && new XDomainRequest(),\r
@@ -164,7 +171,7 @@ if( X_Net_XHR_W3C || X_Net_XHR_ACTIVE_X ){
                                };\r
                                \r
                                if( raw.timeout !== undefined ){\r
-                                       raw.timeout = timeout; //Firefox33 でエラー,,,\r
+                                       raw.timeout = timeout;\r
                                } else {\r
                                        this._timerID = X.Timer.once( timeout, this, this.onTimeout );\r
                                };      \r
@@ -286,12 +293,14 @@ if( X_Net_XHR_W3C || X_Net_XHR_ACTIVE_X ){
                                                                        break;\r
                                                                case 'json' :\r
                                                                case 'moz-json' :\r
-                                                                       data = raw[ 'response' ] || raw[ 'responseText' ]; // とりあえず\r
+                                                                       data = raw[ 'response' ] ||\r
+                                                                               ( JSON ? JSON.parse( raw[ 'responseText' ] ) : eval( '(' + raw[ 'responseText' ] + ')' ) ); // http://d.hatena.ne.jp/sshi/20060904/p1\r
                                                                        break;\r
                                                                case 'document' :\r
                                                                case 'xml' :\r
                                                                case 'html' :\r
                                                                case 'htm' :\r
+                                                               // svg, vml, xaml\r
                                                                        data = raw[ 'responseXML' ];\r
                                                                        break;\r
                                                                case 'blob' :\r
@@ -366,8 +375,8 @@ if( X_Net_XHR_W3C || X_Net_XHR_ACTIVE_X ){
                X_NET_XHRWrapper.listen( [ 'load', 'readystatechange', 'error', 'timeout' ] ); //, 'abort'\r
        };\r
        \r
-       if( X.Net.XHR.UL_PROGRESS ){\r
-               X_NET_XHRWrapper._rawObject.upload.addEventListener( 'progress', X.Net.XHR.xhr.onUploadProgress );\r
+       if( X_NET_XHRWrapper.onUploadProgress ){\r
+               X_NET_XHRWrapper._rawObject.upload.addEventListener( 'progress', X_NET_XHRWrapper.onUploadProgress );\r
        };\r
 };\r
 \r
index 69252c7..0355d58 100644 (file)
@@ -186,7 +186,7 @@ function X_NET_JSONP_iframeListener( e ){
        return X.Callback.UN_LISTEN;
 };
 
-
+// TODO extend NinjaIframe
 X_NET_JSONPWrapper = X_Class_override(
        new X.EventDispatcher(),
        {
index 945aa92..5418dfa 100644 (file)
@@ -14,7 +14,8 @@ X.Audio = {
        }\r
 };\r
 \r
-var X_Audio_BACKENDS = [];\r
+var X_Audio_BACKENDS = [],\r
+       X_Audio_WRAPPER_LIST = [];\r
 \r
 /*\r
  * TODO preplayerror play してみたら error が出た、backend の変更。\r
@@ -62,6 +63,12 @@ function X_Audio_detectComplete( e, proxy, option, sourceList, source, ext, sup
        };\r
 };\r
 \r
+function X_AudioProxy_getAudioWrapper( proxy ){\r
+       var i = X_Audio_WRAPPER_LIST.length;\r
+       for( ; i; ){\r
+               if( X_Audio_WRAPPER_LIST[ --i ].proxy === proxy ) return X_Audio_WRAPPER_LIST[ i ];\r
+       };\r
+};\r
 \r
 var X_AudioProxy = X.EventDispatcher.inherits(\r
        'X.AV.AudioProxy',\r
@@ -77,51 +84,53 @@ var X_AudioProxy = X.EventDispatcher.inherits(
                },\r
                \r
                close : function(){\r
-                       return this._backend !== -1 && X_Audio_BACKENDS[ this._backend ].close( this );\r
+                       return this._backend !== -1 && X_AudioProxy_getAudioWrapper( this ).close();\r
                },\r
                \r
-               play : function( startTime, endTime, loop, loopStartTime ){\r
+               play : function( startTime, endTime, loop, loopStartTime, loopEndTime ){\r
                        var state, duration;\r
-                       if( startTime ){\r
+                       if( 0 <= startTime ){\r
                                this.state( {\r
+                                       currentTime   : startTime,\r
                                        startTime     : startTime,\r
                                        endTime       : endTime,\r
                                        loop          : loop,\r
-                                       loopStartTime : loopStartTime\r
+                                       loopStartTime : loopStartTime,\r
+                                       loopEndTime   : loopEndTime\r
                                } );\r
                        };\r
-                       this._backend !== -1 && X_Audio_BACKENDS[ this._backend ].play( this );\r
+                       this._backend !== -1 && X_AudioProxy_getAudioWrapper( this ).play();\r
                        return this;\r
                },\r
                \r
                seek : function( seekTime ){\r
-                       var state = this.state();\r
-                       if( state.playing ){\r
-                               seekTime < state.endTime && this.state( { currentTime : seekTime } );\r
-                       } else {\r
-                               this.state( { startTime : seekTime } );\r
+                       var state = this.state(),\r
+                               end   = X_AudioWrapper_getEndTime( X_AudioProxy_getAudioWrapper( this ) );\r
+                       if( seekTime < end ){\r
+                               this.state( { currentTime : seekTime } );\r
                        };\r
                        return this;\r
                },\r
                \r
                pause : function(){\r
-                       this.state().playing && X_Audio_BACKENDS[ this._backend ].pause( this );\r
+                       this.state().playing && X_AudioProxy_getAudioWrapper( this ).pause();\r
                        return this;\r
                },\r
                \r
                state : function( obj ){\r
-                       var backend = this._backend !== -1 && X_Audio_BACKENDS[ this._backend ];\r
+                       var backend = this._backend !== -1 && X_AudioProxy_getAudioWrapper( this );\r
 \r
                        if( obj === undefined ){\r
                                return backend ?\r
-                                       backend.state( this ) :\r
+                                       backend.state() :\r
                                        {\r
                                        startTime     : -1,\r
                                        endTime       : -1,\r
                                        loopStartTime : -1,\r
+                                       loopEndTime   : -1,\r
                                        currentTime   : -1,\r
                                        loop          : false,\r
-                                       loaded        : false,\r
+                                       looded        : false,\r
                                        error         : false,\r
                                        playing       : false,\r
                                        \r
@@ -129,39 +138,39 @@ var X_AudioProxy = X.EventDispatcher.inherits(
                                        duration      : 0\r
                                        };\r
                        };\r
-                       backend && backend.state( this, obj );\r
+                       backend && backend.state( obj );\r
                        return this;\r
                },              \r
                \r
                loop : function( v ){\r
-                       var backend = this._backend !== -1 && X_Audio_BACKENDS[ this._backend ];\r
+                       var backend = this._backend !== -1 && X_AudioProxy_getAudioWrapper( this );\r
                        if( v === undefined ){\r
-                               return backend && backend.state( this ).loop;\r
+                               return backend && backend.state().loop;\r
                        };\r
-                       backend && backend.state( this, { loop : v } );\r
+                       backend && backend.state( { loop : v } );\r
                        return this;\r
                },\r
 \r
                volume : function( v ){\r
-                       var backend = this._backend !== -1 && X_Audio_BACKENDS[ this._backend ];\r
+                       var backend = this._backend !== -1 && X_AudioProxy_getAudioWrapper( this );\r
                        if( v === undefined ){\r
-                               return backend && backend.state( this ).volume;\r
+                               return backend && backend.state().volume;\r
                        };\r
-                       backend && backend.state( this, { volume : v } );\r
+                       backend && backend.state( { volume : v } );\r
                        return this;\r
                },\r
 \r
                currentTime : function( v ){\r
-                       var backend = this._backend !== -1 && X_Audio_BACKENDS[ this._backend ];\r
+                       var backend = this._backend !== -1 && X_AudioProxy_getAudioWrapper( this );\r
                        if( v === undefined ){\r
-                               return backend && backend.state( this ).currentTime;\r
+                               return backend && backend.state().currentTime;\r
                        };\r
-                       backend && backend.state( this, { currentTime : v } );\r
+                       backend && backend.state( { currentTime : v } );\r
                        return this;\r
                },\r
 \r
                isPlaying : function(){\r
-                       return this._backend !== -1 && X_Audio_BACKENDS[ this._backend ].state( this ).playing;\r
+                       return this._backend !== -1 && X_AudioProxy_getAudioWrapper( this ).state().playing;\r
                }\r
                \r
        }\r
@@ -173,7 +182,7 @@ function X_AudioProxy_handleEvent( e ){
                        this.unlisten( 'nobackend', X_AudioProxy_handleEvent );\r
                        this.source = e.source;\r
                        this.backendName = X_Audio_BACKENDS[ this._backend ].backendName;\r
-                       X_Audio_BACKENDS[ this._backend ].register( this, e.source, e.option );\r
+                       X_Audio_WRAPPER_LIST.push( new X_Audio_BACKENDS[ this._backend ].klass( this, e.source, e.option ) );\r
                        break;\r
                \r
                case 'nobackend' :\r
@@ -202,25 +211,35 @@ function X_AudioWrapper_updateStates( audioWrapper, obj ){
                                                        audioWrapper.seekTime = v;\r
                                                        seek = 2;\r
                                                };\r
-                                               break;\r
-                                       };                      \r
+                                       } else {\r
+                                               audioWrapper.seekTime = v;\r
+                                       };\r
                                } else {\r
                                        continue;\r
                                };\r
-                               k = 'startTime';\r
+                               break;\r
                                        \r
                        case 'startTime'     :\r
                        case 'endTime'       :\r
                        case 'loopStartTime' :\r
+                       case 'loopEndTime'   :\r
                                v = X_AudioWrapper_timeStringToNumber( v );\r
-                               if( X.Type.isNumber( v ) && audioWrapper[ k ] !== v ){\r
-                                       audioWrapper[ k ] = v;\r
-                                       // 再生中の endTime, currentTime の変更\r
-                                       if( playing && k === 'endTime' ) end = 1;\r
+                               console.log( k + ' ' + v );\r
+                               if( v || v === 0 ){\r
+                                       if( audioWrapper[ k ] !== v ){\r
+                                               audioWrapper[ k ] = v;\r
+                                               \r
+                                               // 再生中の endTime の変更\r
+                                               if( playing && ( k === 'endTime' || k === 'loopEndTime' ) ) end = 1;                                            \r
+                                       };\r
+                               } else {\r
+                                       delete audioWrapper[ k ];\r
+                                       if( playing && ( k === 'endTime' || k === 'loopEndTime' ) ) end = 1;\r
                                };\r
                                break;\r
 \r
                        case 'loop' :\r
+                       case 'looped' :\r
                                if( X.Type.isBoolean( v ) && audioWrapper[ k ] !== v ){\r
                                        audioWrapper[ k ] = v;\r
                                };\r
@@ -239,10 +258,10 @@ function X_AudioWrapper_updateStates( audioWrapper, obj ){
                };\r
        };\r
        \r
-       if( audioWrapper.endTime <= audioWrapper.startTime ||\r
-               audioWrapper.endTime <= audioWrapper.loopStartTime ||\r
-               audioWrapper.endTime  < audioWrapper.seekTime ||\r
-               audioWrapper.duration < audioWrapper.endTime\r
+       if( audioWrapper.endTime < audioWrapper.startTime ||\r
+               ( audioWrapper.loopEndTime < 0 ? audioWrapper.endTime : audioWrapper.loopEndTime ) < ( audioWrapper.loopStartTime < 0 ? audioWrapper.startTime : audioWrapper.loopStartTime ) ||\r
+               X_AudioWrapper_getEndTime( audioWrapper ) < audioWrapper.seekTime// ||\r
+               //audioWrapper.duration < audioWrapper.endTime\r
        ){\r
                //alert( 'error @updateStateObject() begin:' + audioWrapper.startTime + ' end:' + audioWrapper.endTime + ' d:' + audioWrapper.duration + ' ls:' + audioWrapper.loopStartTime );\r
                return 0;\r
@@ -286,3 +305,34 @@ function X_AudioWrapper_timeStringToNumber( time ){
        ms = ( h * 3600 + m * 60 + s ) * 1000 + ms;\r
        return ms < 0 ? 0 : ms;\r
 };\r
+\r
+function X_AudioWrapper_getStartTime( audioWrapper, endTime, delSeekTime ){\r
+       var seek = audioWrapper.seekTime;\r
+       if( delSeekTime ) delete audioWrapper.seekTime;\r
+       \r
+       if( 0 <= seek ){\r
+               if( audioWrapper.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
+       };\r
+       \r
+       if( audioWrapper.startTime < 0 || audioWrapper.duration <= audioWrapper.startTime ) return 0;\r
+       return audioWrapper.startTime;\r
+};\r
+\r
+function X_AudioWrapper_getEndTime( audioWrapper ){\r
+       var duration = audioWrapper.duration;\r
+       \r
+       if( audioWrapper.looped && 0 <= audioWrapper.loopEndTime ){\r
+               if( duration <= audioWrapper.loopEndTime ) return duration;\r
+               return audioWrapper.loopEndTime;\r
+       };\r
+       \r
+       if( audioWrapper.endTime < 0 || duration <= audioWrapper.endTime ) return duration;\r
+       return audioWrapper.endTime;\r
+};\r
+\r
index 8299229..07f4659 100644 (file)
@@ -1,76 +1,46 @@
 
-var X_Audio_WebAudio_context   = window.webkitAudioContext || window.AudioContext,
-       X_Audio_WebAudio_LIVE_LIST = [],
-       X_Audio_WebAudio_POOL_LIST = [],
-       X_Audio_WebAudio, X_Audio_WebAudioWrapper, X_Audio_rawAudio;
+var X_Audio_WebAudio_context = window.webkitAudioContext || window.AudioContext,
+       X_Audio_WebAudioWrapper;
 
 if( X_Audio_WebAudio_context ){
        
        X_Audio_WebAudio_context = new X_Audio_WebAudio_context;
        
-       function getWebAudioWrapper( proxy ){
-               var i = X_Audio_WebAudio_LIVE_LIST.length;
-               for( ; i; ){
-                       if( X_Audio_WebAudio_LIVE_LIST[ --i ].proxy === proxy ) return X_Audio_WebAudio_LIVE_LIST[ i ];
+       function X_Audio_WebAudio_getBuffer( url ){
+               var i = 0, l = X_Audio_WRAPPER_LIST.length;
+               for( i = 0; i < l; ++i ){
+                       if( X_Audio_WRAPPER_LIST[ i ].url === url ) return X_Audio_WRAPPER_LIST[ i ];
                };
        };
        
-       X_Audio_WebAudio = 
-               {
-                       backendName : 'Web Audio',
-
-                       detect : function( proxy, source, ext ){
-                               var ok = ext === 'mp3' || ext === 'ogg';
-                               
-                               proxy.asyncDispatch( ok ? 'support' : 'nosupport' );
-                       },
-                       
-                       register : function( proxy, source, option ){
-                               X_Audio_WebAudio_LIVE_LIST.push( new X_Audio_WebAudioWrapper( proxy, source, option ) );
-                       },
-                       
-                       close : function( proxy ){
-                               return getWebAudioWrapper( proxy ).close();
-                       },
-                       
-                       play : function( proxy, startTime, endTime, loop, loopStartTime ){
-                               return getWebAudioWrapper( proxy ).play( startTime, endTime, loop, loopStartTime );
-                       },
-                       
-                       pause : function( proxy ){
-                               return getWebAudioWrapper( proxy ).pause();
-                       },
-       
-                       state : function( proxy, obj ){
-                               return getWebAudioWrapper( proxy ).state( obj );
-                       }
-               };
-       
-       X_Audio_BACKENDS.push( X_Audio_WebAudio );
-       
        X_Audio_WebAudioWrapper = X.EventDispatcher.inherits(
                'X.AV.WebAudioWrapper',
                X.Class.POOL_OBJECT,
                {
                        
+                       url             : '',
                        proxy           : null,
                        
                        startTime       : 0,
-                       endTime         : 0,
-                       loopStartTime   : 0,
-                       seekTime        : 0,
+                       endTime         : -1,
+                       loopStartTime   : -1,
+                       loopEndTime     : -1,
+                       seekTime        : -1,
                        duration        : 0,
                        
                        playing         : false,
                        error           : 0,                    
                        loop            : false,
+                       looped          : false,
                        volume          : 0.5,
                                                
                        _startTime      : 0,
+                       _endTime        : 0,
                        _playTime       : 0,
             _timerID        : 0,
             _interval       : 0,
                buffer          : null,
+               source          : null,
             gainNode        : null,
             _onended        : null,
             
@@ -78,13 +48,26 @@ if( X_Audio_WebAudio_context ){
             onDecodeSuccess : null,
             onDecodeError   : null,
             
-                       Constructor : function( proxy, source, option ){
+                       Constructor : function( proxy, url, option ){
+                               var audio = X_Audio_WebAudio_getBuffer( url );
+                               
+                               this.url = url;
                                this.closed = false;
                                this.proxy  = proxy;
-                               this.xhr    = X.Net.xhrGet( source, 'arraybuffer' )
-                                                               .listen( X.Event.PROGRESS, this )
-                                                               .listenOnce( [ X.Event.SUCCESS, X.Event.COMPLETE, X.Event.CANCELED ], this );
+                               
                                X_AudioWrapper_updateStates( this, option );
+                               
+                               if( audio && audio.buffer ){
+                                       this._onDecodeSuccess( audio.buffer );
+                               } else
+                               if( audio ){
+                                       // TODO 当てにしていたaudioがclose 等した場合
+                                       audio.proxy.listenOnce( 'canplaythrough', this, this._onBufferReady );
+                               } else {
+                                       this.xhr = X.Net.xhrGet( url, 'arraybuffer' )
+                                                                       .listen( X.Event.PROGRESS, this )
+                                                                       .listenOnce( [ X.Event.SUCCESS, X.Event.COMPLETE, X.Event.CANCELED ], this );                                   
+                               };
                        },
                        
                        handleEvent : function( e ){
@@ -96,9 +79,15 @@ if( X_Audio_WebAudio_context ){
                                                return;
                                        
                                        case X.Event.SUCCESS :
-                                               X_Audio_WebAudio_context.decodeAudioData( e.data,
-                                                       this.callbackDecodeSuccess = X_Callback_create( this, this._onDecodeSuccess ),
-                                                       this.callbackDecodeError   = X_Callback_create( this, this._onDecodeError ) );
+                                       // TODO 旧api
+                                       // https://developer.mozilla.org/en-US/docs/Web/API/Web_Audio_API/Porting_webkitAudioContext_code_to_standards_based_AudioContext
+                                               if( X_Audio_WebAudio_context.decodeAudioData ){
+                                                       X_Audio_WebAudio_context.decodeAudioData( e.data,
+                                                               this.onDecodeSuccess = X_Callback_create( this, this._onDecodeSuccess ),
+                                                               this.onDecodeError   = X_Callback_create( this, this._onDecodeError ) );
+                                               } else {
+                                                       this._onDecodeSuccess( X_Audio_WebAudio_context.createBuffer( e.data, false ) );
+                                               };
                                                break;
 
                                        case X.Event.CANCELED :
@@ -116,7 +105,7 @@ if( X_Audio_WebAudio_context ){
                        },
                        
                                _onDecodeSuccess : function( buffer ){
-                                       this._onDecodeComplete();
+                                       this.onDecodeSuccess && this._onDecodeComplete();
                                        
                        if ( !buffer ) {
                            this.proxy.asyncDispatch( { type : 'error', message : 'buffer is ' + buffer } );
@@ -125,7 +114,6 @@ if( X_Audio_WebAudio_context ){
        
                        this.buffer   = buffer;
                        this.duration = buffer.duration * 1000;
-                       this.endTime  = this.endTime || this.duration;
                        
                        this.proxy.asyncDispatch( 'loadedmetadata' );
                        this.proxy.asyncDispatch( 'loadeddata' );
@@ -140,15 +128,26 @@ if( X_Audio_WebAudio_context ){
                                },
                                
                                _onDecodeComplete : function(){
-                                       X_Callback_correct( this.callbackDecodeSuccess );
-                                       delete this.callbackDecodeSuccess;
-                                       X_Callback_correct( this.callbackDecodeError );
-                                       delete this.callbackDecodeError;
+                                       X_Callback_correct( this.onDecodeSuccess );
+                                       delete this.onDecodeSuccess;
+                                       X_Callback_correct( this.onDecodeError );
+                                       delete this.onDecodeError;
+                               },
+                               
+                               _onBufferReady : function( e ){
+                                       var audio = X_Audio_WebAudio_getBuffer( this.url );
+                                       this._onDecodeSuccess( audio.buffer );
                                },
                        
                        close : function(){     
                    delete this.buffer;
        
+                               if( this.xhr ) this.xhr.close();
+                               
+                               if( this.onDecodeSuccess ){
+                                       // 回収はあきらめる、、、
+                               };
+       
                                this.playing  && this.pause();
                    this.source   && this._sourceDispose();
        
@@ -158,48 +157,52 @@ if( X_Audio_WebAudio_context ){
                        },
                        
                                _sourceDispose : function(){
-                           this.source && this.source.disconnect();
+                           this.source.disconnect();
                            delete this.source.onended;
                            delete this.source;
                        },
                        
-                       play : function( seekTime ){
-                               var begin;
+                       play : function(){
+                               var begin, end;
                                
                    if( !this.buffer ) return this;
                                
-                               begin = ( seekTime || seekTime === 0 ) ? seekTime : this.playing ? this.loopStartTime : this.startTime;
+                               end   = X_AudioWrapper_getEndTime( this );
+                               begin = X_AudioWrapper_getStartTime( this, end, true );
                                
-                               console.log( '[WebAudio] play' );
+                               console.log( '[WebAudio] play ' + begin + ' -> ' + end );
                                
                                if( this.source ) this._sourceDispose();
-                               if( !this.gainNode ) this.gainNode = X_Audio_WebAudio_context.createGain();
-                               
+                               if( !this.gainNode ){
+                                       this.gainNode = X_Audio_WebAudio_context.createGain ? X_Audio_WebAudio_context.createGain() : X_Audio_WebAudio_context.createGainNode();
+                       this.gainNode.connect( X_Audio_WebAudio_context.destination );
+                               };
                    this.source        = X_Audio_WebAudio_context.createBufferSource();
                    this.source.buffer = this.buffer;
                    this.source.connect( this.gainNode );
                    
-                   this.gainNode.connect( X_Audio_WebAudio_context.destination );
                    this.gainNode.gain.value = this.volume;
                    
                    this._timerID && X.Timer.remove( this._timerID );
                    
-                   // おかしい、stop 前に外していても呼ばれる、、、@Firefox
-                if( this.source.onended !== undefined ){
+                   // おかしい、stop 前に外していても呼ばれる、、、@Firefox33.1
+                   // 破棄された X.Callback が呼ばれて、obj._() でエラーになる。Firefox では、onended は使わない
+                if( false && this.source.onended !== undefined ){
                        //console.log( '> use onended' );
                        this.source.onended = this._onended || ( this._onended = X_Callback_create( this, this._onEnded ) );
                 } else {
-                                       this._timerID = X.Timer.once( this.endTime - begin, this, this._onEnded );
+                                       this._timerID = X.Timer.once( end - begin, this, this._onEnded );
                 };
        
                    if( this.source.start ){
-                       this.source.start( 0, begin / 1000, this.endTime / 1000 );
+                       this.source.start( 0, begin / 1000, end / 1000 );
                    } else {
-                       this.source.noteGrainOn( 0, begin / 1000, this.endTime / 1000 );
+                       this.source.noteGrainOn( 0, begin / 1000, end / 1000 );
                    };
                    
                    this.playing    = true;
                    this._startTime = begin;
+                   this._endTime   = end;
                    this._playTime  = X_Audio_WebAudio_context.currentTime * 1000;
                    this._interval  = this._interval || X.Timer.add( 1000, 0, this, this._onInterval );
                        },
@@ -213,14 +216,27 @@ if( X_Audio_WebAudio_context ){
                                },
                                                
                                _onEnded : function(){
+                                       var time;
                                        delete this._timerID;
+                                       
                            if( this.playing ){
-                               console.log( '> onEnd ' + ( this.playing && ( X_Audio_WebAudio_context.currentTime * 1000 - this._playTime ) ) + ' < ' + ( this.endTime - this._startTime ) );
-                               // Firefox 用の対策,,,
-                               if( X_Audio_WebAudio_context.currentTime * 1000 - this._playTime < this.endTime - this._startTime ) return;
+                               time = X_Audio_WebAudio_context.currentTime * 1000 - this._playTime - this._endTime + this._startTime | 0;
+                               //console.log( '> onEnd ' + ( this.playing && ( X_Audio_WebAudio_context.currentTime * 1000 - this._playTime ) ) + ' < ' + ( this._endTime - this._startTime ) );
+                               if( this._onended ){
+                                       // Firefox 用の対策,,,
+                                       if( time < 0 ) return;
+                               } else {
+                                       if( time < -16 ){
+                                               console.log( '> onEnd ' + time );
+                                               this._timerID = X.Timer.once( -time, this, this._onEnded );
+                                               return;
+                                       };
+                               };
                                
                                if( this.loop ){
+                                       this.looped = true;
                                        this.play();
+                                       this.proxy.dispatch( 'looped' );
                                } else {
                                        this.pause();
                                        this.proxy.dispatch( 'ended' );
@@ -247,27 +263,29 @@ if( X_Audio_WebAudio_context ){
        
                        state : function( obj ){
                                var time = this.playing ? ( X_Audio_WebAudio_context.currentTime * 1000 - this._playTime ) : 0,
-                                       result, halfway;
+                                       result;
                                
                                if( obj === undefined ){
                                    return {
                                        startTime     : this.startTime,
-                                       endTime       : this.endTime,
-                                       loopStartTime : this.loopStartTime,
-                                       currentTime   : time + this._startTime,
+                                       endTime       : this.endTime < 0 ? this.duration : this.endTime,
+                                       loopStartTime : this.loopStartTime < 0 ? this.startTime : this.loopStartTime,
+                                       loopEndTime   : this.loopEndTime < 0 ? ( this.endTime || this.duration ) : this.loopEndTime,
                                        loop          : this.loop,
+                                       looped        : this.looped,
                                        volume        : this.volume,
-                                       error         : this.error,
                                        playing       : this.playing,                           
-                                       duration      : this.duration
-                                   };                                  
+                                       duration      : this.duration,
+                                       
+                                       currentTime   : time + this._startTime,
+                                       error         : this.error
+                                   };
                                };
                        
                                result = X_AudioWrapper_updateStates( this, obj );
                                
                                if( result & 2 ){ // seek
-                       this.play( this.seekTime );
-                       delete this.seekTime;
+                       this.play();
                                } else
                                if( result & 1 ){
                                        this.play();
@@ -279,5 +297,19 @@ if( X_Audio_WebAudio_context ){
 
                }
        );
+       
+       X_Audio_BACKENDS.push(
+               {
+                       backendName : 'Web Audio',
+
+                       detect : function( proxy, source, ext ){
+                               var ok = ext === 'mp3' || ext === 'ogg';
+                               
+                               proxy.asyncDispatch( ok ? 'support' : 'nosupport' );
+                       },
+                       
+                       klass : X_Audio_WebAudioWrapper
+               }
+       );
 
 };
index c88e514..6b77937 100644 (file)
  * https://code.google.com/p/uupaa-js/source/browse/trunk/0.8/src/Audio/HTML5Audio.js?r=568\r
  */\r
 \r
-var X_Audio_HTML5Audio, X_Audio_HTML5AudioWrapper, X_Audio_rawAudio,\r
-       X_Audio_HTML5Audio_LIVE_LIST = [],\r
-       X_Audio_HTML5Audio_POOL_LIST = [];\r
+var X_Audio_HTML5AudioWrapper, X_Audio_rawAudio;\r
        \r
 \r
 if( window.HTMLAudioElement ){\r
-       function getHTML5AudioWrapper( proxy ){\r
-               var i = X_Audio_HTML5Audio_LIVE_LIST.length;\r
-               for( ; i; ){\r
-                       if( X_Audio_HTML5Audio_LIVE_LIST[ --i ].proxy === proxy ) return X_Audio_HTML5Audio_LIVE_LIST[ i ];\r
-               };\r
-       };\r
-       \r
-       X_Audio_HTML5Audio = \r
-               {\r
-                       backendName : 'HTML5 Audio',\r
-               /*\r
-                * HTML5 の audio 要素と video 要素でサポートされているメディアフォーマット\r
-                * https://developer.mozilla.org/ja/docs/Web/HTML/Supported_media_formats\r
-                * \r
-                * 主要ブラウザのHTML5 audioタグで使えるファイル形式の再生対応状況を調べてみた\r
-                * http://sothis.blog.so-net.ne.jp/2010-10-27\r
-                * ダメ元で仕様に含まれていない SHOUTcast もテストしてみました。\r
-                * \r
-                * IE9 の HTML5 Audio について\r
-                * http://kentablog.cluscore.com/2011/05/ie9-html5-audio.html\r
-                * 1.Audioオブジェクトを作ることができないので、Audioタグを使う\r
-                * 2.クロスドメインアクセスには、「clientaccesspolicy.xml」か「crossdomain.xml」が必要\r
-                * 3.wav が不可\r
-                * \r
-                * IE9でHTML5 autio タグが無効になる\r
-                * http://bbs.wankuma.com/index.cgi?mode=al2&namber=64886&KLOG=109\r
-                *  IEのバージョン9.0.8112.16421では、Audioオブジェクトのnewも対応してました。\r
-                *  createElement等で動的生成すると、よろしくない\r
-                * \r
-                * media-can-play-wav-audio.html\r
-                * https://github.com/adobe/webkit/blob/master/LayoutTests/media/media-can-play-wav-audio.html\r
-                * testExpected("audio.canPlayType('audio/wav; codecs=1')", "probably");\r
-                * \r
-                * HTML5 audioタグ ブラウザ間の違い\r
-                * http://wiki.bit-hive.com/tomizoo/pg/HTML5%20audio%A5%BF%A5%B0%20%A5%D6%A5%E9%A5%A6%A5%B6%B4%D6%A4%CE%B0%E3%A4%A4\r
-                *  - volume, muted iPhone(iOS4-6)、Android(2.3.6)では動作せず。\r
-                *  - FireFox3.6, Android 2.3.6については、src変更後、load()を呼び出さないと切り替わらなかった。iPhoneはload()が不要。\r
-                */     \r
-                       detect : function( proxy, source, ext ){\r
-                               var ok, mineType = 'audio/' + ext;\r
-                               switch( ext ){\r
-                                       case 'mp3' :\r
-                                               ok = X_UA.IE || X_UA.Chrome || ( X_UA.Windows && X_UA.Safari );\r
-                                               mineType = 'audio/mpeg';\r
-                                               break;\r
-                                       case 'ogg' :\r
-                                               ok = 15 <= X_UA.Gecko || X_UA.Chrome || X_UA.Opera;\r
-                                               break;\r
-                                       case 'm4a' :\r
-                                               ok = X_UA.IE || X_UA.WebKit;\r
-                                               mineType = 'audio/mp4';\r
-                                               break;\r
-                                       case 'webm' :\r
-                                               ok = 2 <= X_UA.Gecko || 10.6 <= X_UA.Opera; // firefox4+(Gecko2+)\r
-                                               break;\r
-                                       case 'wav' :\r
-                                               ok = X_UA.Gecko || X_UA.Opera || ( X_UA.Windows && X_UA.Safari );\r
-                                               //mineType = 'audio/wav'; // audio/x-wav ?\r
-                                               break;\r
-                                       default :\r
-                                               mineType = '';\r
-                               };\r
-                               \r
-                               if( !ok && mineType ){\r
-                                       if( !X_Audio_rawAudio ) X_Audio_rawAudio = new Audio;\r
-                                       ok = X_Audio_rawAudio.canPlayType( mineType );\r
-                               };\r
-                               \r
-                               proxy.asyncDispatch( ok ? 'support' : 'nosupport' );\r
-                       },\r
-                       \r
-                       register : function( proxy, source, option ){\r
-                               X_Audio_HTML5Audio_LIVE_LIST.push( new X_Audio_HTML5AudioWrapper( proxy, source, option ) );\r
-                       },\r
-                       \r
-                       close : function( proxy ){\r
-                               getHTML5AudioWrapper( proxy ).close();\r
-                       },\r
-                       \r
-                       play : function( proxy ){\r
-                               getHTML5AudioWrapper( proxy ).play();\r
-                       },\r
-                       \r
-                       pause : function( proxy ){\r
-                               getHTML5AudioWrapper( proxy ).pause();\r
-                       },\r
-       \r
-                       state : function( proxy, obj ){\r
-                               return getHTML5AudioWrapper( proxy ).state( obj );\r
-                       }\r
-               };\r
-       \r
-       X_Audio_BACKENDS.push( X_Audio_HTML5Audio );\r
        \r
        X_Audio_HTML5AudioWrapper = X.EventDispatcher.inherits(\r
                'X.AV.HTML5AudioWrapper',\r
@@ -112,14 +17,16 @@ if( window.HTMLAudioElement ){
                        proxy           : null,\r
                        \r
                        startTime       : 0,\r
-                       endTime         : 1 / 0,\r
-                       loopStartTime   : 0,\r
-                       seekTime        : 0,\r
-                       duration        : 1 / 0,\r
+                       endTime         : -1,\r
+                       loopStartTime   : -1,\r
+                       loopEndTime     : -1,\r
+                       seekTime        : -1,\r
+                       duration        : 0,\r
                        \r
                        playing         : false,\r
                        error           : 0,                    \r
                        loop            : false,\r
+                       looped          : false,\r
                        volume          : 0.5,\r
 \r
             _timerID        : 0,\r
@@ -132,6 +39,7 @@ if( window.HTMLAudioElement ){
                                \r
                                X_AudioWrapper_updateStates( this, option );\r
                                \r
+                               // TODO use video document.createElement('video')\r
                                this._rawObject = X_Audio_rawAudio || new Audio( source );// X_Doc_create( 'audio', { src : source } ).appendToRoot();//( X.X_Node_systemNode );\r
                                \r
                                this.listen( [\r
@@ -139,7 +47,7 @@ if( window.HTMLAudioElement ){
                                                'loadeddata', 'waiting', 'playing', 'canplay', 'canplaythrough', 'seeking', 'seeked', 'timeupdate', 'ended',\r
                                                'ratechange', 'durationchange', 'volumechange' ], this.handleEventProxy );                              \r
                                \r
-                               if( X_Audio_rawAudio ){\r
+                               if( X_Audio_rawAudio === this._rawObject ){\r
                                        X_Audio_rawAudio.src = source;\r
                                        X_Audio_rawAudio.load(); // 要る?\r
                                        X_Audio_rawAudio = null;\r
@@ -178,7 +86,6 @@ if( window.HTMLAudioElement ){
                                        case 'canplay' :        //      今すぐに再生を再開できるが、バッファリングが不十分でコンテンツを最後まで表示できないと予測している場合に発生\r
                                        case 'canplaythrough' : //      今すぐに再生を開始してもバッファリングで停止することなく最後まで表示できると予測している場合に発生\r
                                                this.duration = this._rawObject.duration * 1000;\r
-                                               this.endTime  = this.duration < this.endTime ? this.duration : this.endTime;\r
                                                //console.log( this.duration );\r
                                                break;\r
        \r
@@ -200,7 +107,9 @@ if( window.HTMLAudioElement ){
                                        \r
                                        case 'ended' :\r
                                                if( !this._closed && this.loop ){\r
+                                                       this.looped = true;\r
                                                        this.play();\r
+                                                       this.proxy.dispatch( 'looped' );\r
                                                } else {\r
                                                        this._timerID && X.Timer.remove( this._timerID );\r
                                                        delete this._timerID;\r
@@ -228,14 +137,17 @@ if( window.HTMLAudioElement ){
                                this._rawObject.load();\r
                        },\r
                        \r
-                       play : function( seekTime ){\r
-                               var begin, halfway;\r
+                       play : function(){\r
+                               var begin, end, halfway;\r
                                \r
                                // もし kill 後に autoplayTimer で呼ばれても、_closed==true なので平気\r
                                if( this._closed ) return;\r
 \r
-                           begin = ( seekTime || seekTime === 0 ) ? seekTime : this.playing ? this.loopStartTime : this.startTime;\r
-                           this._rawObject.currentTime = begin / 1000;\r
+                               end   = X_AudioWrapper_getEndTime( this );\r
+                               begin = X_AudioWrapper_getStartTime( this, end, true );\r
+                               this._rawObject.currentTime = begin / 1000;\r
+                           \r
+                           console.log( '[HTMLAudio] play ' + begin + ' -> ' + end );\r
                            \r
                            if( !this.playing ){\r
                                    if( X_UA.Chrome ){ // [CHROME][FIX] volume TODO どの version で 修正される?\r
@@ -249,40 +161,39 @@ if( window.HTMLAudioElement ){
                                this.playing = true;\r
                            };\r
 \r
-                   halfway = this.endTime < this.duration;\r
+                   halfway = end < this.duration;\r
                    this._timerID && X.Timer.remove( this._timerID );\r
                    \r
                 if( halfway ){\r
-                                       this._timerID = X.Timer.once( this.endTime - begin, this, this._onEnded );\r
+                                       this._timerID = X.Timer.once( end - begin, this, this._onEnded );\r
                 } else {\r
                        delete this._timerID;\r
                 };\r
-                \r
-                               if( !this._interval ){\r
-                                       this._interval = X.Timer.add( 1000, 0, this, this._onInterval );\r
-                               };\r
                        },\r
                                \r
                                // [CHROME][FIX] volume\r
                                _fixForChrome : X_UA.Chrome && function(){\r
                                        !this._closed && ( this._rawObject.volume = this.volume );\r
                                },\r
-\r
-                               _onInterval : function(){\r
-                                       if( !this.playing ){\r
-                                               delete this._interval;\r
-                                               return X_Callback_UN_LISTEN;\r
-                                       };\r
-                                       this.proxy.dispatch( 'timeupdate' );\r
-                               },\r
                                \r
                                _onEnded : function(){\r
+                                       var time;\r
                                        delete this._timerID;\r
+                                       \r
                            if( this.playing ){\r
+                               \r
+                               time = this._rawObject.currentTime * 1000 - X_AudioWrapper_getEndTime( this ) | 0;\r
+                               if( time < -16 ){\r
+                                       console.log( '> onEnd ' + time + ' ' + ( this._rawObject.currentTime * 1000 | 0 ) + '/' + X_AudioWrapper_getEndTime( this ) );\r
+                                       this._timerID = X.Timer.once( -time, this, this._onEnded );\r
+                                       return;\r
+                               };\r
+                               \r
                                if( this.loop ){\r
+                                       this.looped = true;\r
                                        this.play();\r
+                                       this.proxy.dispatch( 'looped' );\r
                                } else {\r
-                                       console.log( '中断:' + this._rawObject.currentTime + ' ' + this.endTime );\r
                                        this.pause();\r
                                        this.dispatch( 'ended' );\r
                                };\r
@@ -293,8 +204,8 @@ if( window.HTMLAudioElement ){
                                this._timerID && X.Timer.remove( this._timerID );\r
                                delete this._timerID;\r
                                \r
-                           if( this.palying && !this._rawObject.error ){\r
-                               this._rawObject.pause();\r
+                           if( this.playing ){\r
+                               !this._rawObject.error && this._rawObject.pause();\r
                                delete this.playing;\r
                            };\r
                        },\r
@@ -305,11 +216,17 @@ if( window.HTMLAudioElement ){
                                if( obj === undefined ){\r
                                    return {\r
                                        startTime     : this.startTime,\r
-                                       endTime       : this.endTime,\r
-                                       loopStartTime : this.loopStartTime,\r
-                                       currentTime   : this._rawObject.currentTime * 1000,\r
+                                       endTime       : this.endTime < 0 ? this.duration : this.endTime,\r
+                                       loopStartTime : this.loopStartTime < 0 ? this.startTime : this.loopStartTime,\r
+                                       loopEndTime   : this.loopEndTime < 0 ? ( this.endTime || this.duration ) : this.loopEndTime,\r
+                                       \r
                                        loop          : this.loop,\r
+                                       looped        : this.looped,\r
                                        volume        : this.volume,\r
+                                       playing       : this.playing, // && !this._rawObject.error && !this._rawObject.paused && !this._rawObject.ended,                                \r
+                                       duration      : this.duration,\r
+                                       \r
+                                       currentTime   : this._rawObject.currentTime * 1000,\r
                                        /*\r
        http://www.w3schools.com/tags/av_prop_error.asp\r
        1 = MEDIA_ERR_ABORTED - fetching process aborted by user\r
@@ -317,24 +234,22 @@ if( window.HTMLAudioElement ){
     3 = MEDIA_ERR_DECODE - error occurred when decoding\r
     4 = MEDIA_ERR_SRC_NOT_SUPPORTED - audio/video not supported\r
     */\r
-                                       error         : this._rawObject.error || 0,   // 0, 1 ~ 4\r
-                                       playing       : this.palying && !this._rawObject.error && !this._rawObject.paused && !this._rawObject.ended,                            \r
-                                       duration      : this.duration || 0\r
+                                       error         : this._rawObject.error || 0   // 0, 1 ~ 4 \r
                                    };                                  \r
                                };\r
                        \r
                                result = X_AudioWrapper_updateStates( this, obj );\r
                            \r
                                if( result & 2 ){ // seek\r
-                       this.play( this.seekTime );\r
-                       delete this.seekTime;\r
+                       this.play();\r
                                } else {\r
                                        if( result & 1 ){\r
-                                               halfway = this.endTime < this.duration;\r
+                                               end     = X_AudioWrapper_getEndTime( this );\r
+                                               halfway = end < this.duration;\r
                                                this._timerID && X.Timer.remove( this._timerID );\r
                                                \r
                                                if( halfway ){\r
-                                                       this._timerID = X.Timer.once( this.endTime - this._rawObject.currentTime * 1000, this, this._onEnded );                                                 \r
+                                                       this._timerID = X.Timer.once( end - this._rawObject.currentTime * 1000, this, this._onEnded );                                                  \r
                                                } else {\r
                                                        delete this._timerID;\r
                                                };\r
@@ -349,6 +264,89 @@ if( window.HTMLAudioElement ){
                }\r
        );\r
        \r
+       X_Audio_BACKENDS.push(\r
+               {\r
+                       backendName : 'HTML5 Audio',\r
+               /*\r
+                * HTML5 の audio 要素と video 要素でサポートされているメディアフォーマット\r
+                * https://developer.mozilla.org/ja/docs/Web/HTML/Supported_media_formats\r
+                * \r
+                * 主要ブラウザのHTML5 audioタグで使えるファイル形式の再生対応状況を調べてみた\r
+                * http://sothis.blog.so-net.ne.jp/2010-10-27\r
+                * ダメ元で仕様に含まれていない SHOUTcast もテストしてみました。\r
+                * \r
+                * IE9 の HTML5 Audio について\r
+                * http://kentablog.cluscore.com/2011/05/ie9-html5-audio.html\r
+                * 1.Audioオブジェクトを作ることができないので、Audioタグを使う\r
+                * 2.クロスドメインアクセスには、「clientaccesspolicy.xml」か「crossdomain.xml」が必要\r
+                * 3.wav が不可\r
+                * \r
+                * IE9でHTML5 autio タグが無効になる\r
+                * http://bbs.wankuma.com/index.cgi?mode=al2&namber=64886&KLOG=109\r
+                *  IEのバージョン9.0.8112.16421では、Audioオブジェクトのnewも対応してました。\r
+                *  createElement等で動的生成すると、よろしくない\r
+                * \r
+                * media-can-play-wav-audio.html\r
+                * https://github.com/adobe/webkit/blob/master/LayoutTests/media/media-can-play-wav-audio.html\r
+                * testExpected("audio.canPlayType('audio/wav; codecs=1')", "probably");\r
+                * \r
+                * HTML5 audioタグ ブラウザ間の違い\r
+                * http://wiki.bit-hive.com/tomizoo/pg/HTML5%20audio%A5%BF%A5%B0%20%A5%D6%A5%E9%A5%A6%A5%B6%B4%D6%A4%CE%B0%E3%A4%A4\r
+                *  - volume, muted iPhone(iOS4-6)、Android(2.3.6)では動作せず。\r
+                *  - FireFox3.6, Android 2.3.6については、src変更後、load()を呼び出さないと切り替わらなかった。iPhoneはload()が不要。\r
+                */     \r
+                       detect : function( proxy, source, ext ){\r
+                               var ok, mineType = 'audio/' + ext;\r
+                               switch( ext ){\r
+                                       case 'mp3' :\r
+                                               ok = X_UA.IE || X_UA.Chrome || ( X_UA.Windows && X_UA.Safari );\r
+                                               mineType = 'audio/mpeg';\r
+                                               break;\r
+                                       case 'ogg' :\r
+                                               ok = 15 <= X_UA.Gecko || X_UA.Chrome || X_UA.Opera;\r
+                                               break;\r
+                                       case 'm4a' :\r
+                                               ok = X_UA.IE || X_UA.WebKit;\r
+                                               mineType = 'audio/mp4';\r
+                                               break;\r
+                                       case 'webm' :\r
+                                               ok = 2 <= X_UA.Gecko || 10.6 <= X_UA.Opera; // firefox4+(Gecko2+)\r
+                                               break;\r
+                                       case 'wav' :\r
+                                               ok = X_UA.Gecko || X_UA.Opera || ( X_UA.Windows && X_UA.Safari );\r
+                                               //mineType = 'audio/wav'; // audio/x-wav ?\r
+                                               break;\r
+                                       default :\r
+                                               mineType = '';\r
+                               };\r
+                               \r
+                               if( !ok && mineType ){\r
+                                       if( !X_Audio_rawAudio ) X_Audio_rawAudio = new Audio;\r
+                                       ok = X_Audio_rawAudio.canPlayType( mineType );\r
+                               };\r
+                               \r
+                               proxy.asyncDispatch( ok ? 'support' : 'nosupport' );\r
+                       },\r
+                       \r
+                       klass : X_Audio_HTML5AudioWrapper\r
+                       \r
+               } );\r
+\r
+/*\r
+ * \r
+ * howler.js\r
+ *     codecs = {\r
+      mp3: !!audioTest.canPlayType('audio/mpeg;').replace(/^no$/, ''),\r
+      opus: !!audioTest.canPlayType('audio/ogg; codecs="opus"').replace(/^no$/, ''),\r
+      ogg: !!audioTest.canPlayType('audio/ogg; codecs="vorbis"').replace(/^no$/, ''),\r
+      wav: !!audioTest.canPlayType('audio/wav; codecs="1"').replace(/^no$/, ''),\r
+      aac: !!audioTest.canPlayType('audio/aac;').replace(/^no$/, ''),\r
+      m4a: !!(audioTest.canPlayType('audio/x-m4a;') || audioTest.canPlayType('audio/m4a;') || audioTest.canPlayType('audio/aac;')).replace(/^no$/, ''),\r
+      mp4: !!(audioTest.canPlayType('audio/x-mp4;') || audioTest.canPlayType('audio/mp4;') || audioTest.canPlayType('audio/aac;')).replace(/^no$/, ''),\r
+      weba: !!audioTest.canPlayType('audio/webm; codecs="vorbis"').replace(/^no$/, '')\r
+    };\r
+ */\r
+       \r
 };\r
 \r
 \r
index c02ad7f..2e16da2 100644 (file)
  * SilverlLight5 ie6&7(ietester,winxp), ie8(winxp) で動作確認。firefox32 では動作しない。(4以下の方がよい?)\r
  */\r
 \r
-var X_Audio_SLAudio, X_Audio_SLAudioWrapper,\r
-       X_Audio_SLAudio_uid = 0,\r
-       X_Audio_SLAudio_LIVE_LIST = [],\r
-       X_Audio_SLAudio_POOL_LIST = [];\r
+var X_Audio_SLAudioWrapper,\r
+       X_Audio_SLAudio_uid = 0;\r
 \r
 if( X.Pulgin.SilverlightEnabled ){\r
        \r
-       function getSLAudioWrapper( proxy ){\r
-               var i = X_Audio_SLAudio_LIVE_LIST.length;\r
-               for( ; i; ){\r
-                       if( X_Audio_SLAudio_LIVE_LIST[ --i ].proxy === proxy ) return X_Audio_SLAudio_LIVE_LIST[ i ];\r
-               };\r
-       };\r
-       \r
-       X_Audio_SLAudio = \r
-               {\r
-                       backendName : 'Silverlight Audio',\r
-\r
-                       detect : function( proxy, source, ext ){\r
-                               var ok = ext === 'mp3' || ext === 'wma';\r
-                               proxy.asyncDispatch( ok ? 'support' : 'nosupport' );                            \r
-                       },\r
-                       \r
-                       register : function( proxy, source, option ){\r
-                               X_Audio_SLAudio_LIVE_LIST.push( new X_Audio_SLAudioWrapper( proxy, source, option ) );\r
-                       },\r
-                       \r
-                       close : function( proxy ){\r
-                               return getSLAudioWrapper( proxy ).close();\r
-                       },\r
-                       \r
-                       play : function( proxy ){\r
-                               return getSLAudioWrapper( proxy ).play();\r
-                       },\r
-                       \r
-                       pause : function( proxy ){\r
-                               return getSLAudioWrapper( proxy ).pause();\r
-                       },\r
-       \r
-                       state : function( proxy, obj ){\r
-                               return getSLAudioWrapper( proxy ).state( obj );\r
-                       }\r
-               };\r
-       \r
-       X_Audio_BACKENDS.push( X_Audio_SLAudio );\r
-       \r
-       function slerror(){\r
-               alert( 'slerror' );\r
-       };\r
-       \r
+       // TODO X.Node.inherits\r
        X_Audio_SLAudioWrapper = X.EventDispatcher.inherits(\r
                'X.AV.SilverlightAudioWrapper',\r
                X.Class.POOL_OBJECT,\r
@@ -70,14 +26,16 @@ if( X.Pulgin.SilverlightEnabled ){
                proxy           : null,\r
                \r
                        startTime       : 0,\r
-                       endTime         : 0,\r
-                       loopStartTime   : 0,\r
-                       seekTime        : 0,\r
+                       endTime         : -1,\r
+                       loopStartTime   : -1,\r
+                       loopEndTime     : -1,\r
+                       seekTime        : -1,\r
                        duration        : 0,\r
                        \r
                        playing         : false,\r
                        error           : 0,                    \r
                        loop            : false,\r
+                       looped          : false,\r
                        volume          : 0.5,\r
                \r
                _onload         : '',\r
@@ -172,7 +130,6 @@ if( X.Pulgin.SilverlightEnabled ){
                                        case 'MediaOpened' :\r
                                                // http://msdn.microsoft.com/ja-jp/library/bb979710(VS.95).aspx\r
                                                this.duration = this._rawObject.NaturalDuration.Seconds * 1000;\r
-                                               this.endTime  = this.endTime || this.duration;\r
                                                // TODO 'canplaythrough'\r
                                                this.proxy.asyncDispatch( 'loadstart' );\r
                                this.proxy.asyncDispatch( 'loadedmetadata' );\r
@@ -285,17 +242,21 @@ if( X.Pulgin.SilverlightEnabled ){
                        },\r
                        \r
                        // SilverlightAudio.play\r
-                       play : function( seekTime ){\r
-                               var begin, halfway;\r
+                       play : function(){\r
+                               var begin, end, halfway;\r
                                \r
                                // もし kill 後に autoplayTimer で呼ばれても、_closed==true なので平気\r
                                if( this.error ) return;\r
-\r
-                               begin = ( seekTime || seekTime === 0 ) ? seekTime : this.playing ? this.loopStartTime : this.startTime;\r
-                               this._lastUserAction = this.playing ? 'seek' : 'play';\r
                                \r
-                           this._currentTime( begin );\r
+                               this._lastUserAction = 0 <= this.seekTime ? 'seek' : 'play';\r
+                               \r
+                               end   = X_AudioWrapper_getEndTime( this );\r
+                               begin = X_AudioWrapper_getStartTime( this, end, true );\r
+                               \r
+                               console.log( '[SLAudio] play ' + begin + ' -> ' + end );\r
+                               \r
                            this._rawObject.Volume = this.volume;\r
+                           this._currentTime( begin );\r
                            \r
                            if( !this.playing ){\r
                                    this._rawObject.play();\r
@@ -304,11 +265,11 @@ if( X.Pulgin.SilverlightEnabled ){
                            this.playing = true;\r
                            };\r
                    \r
-                   halfway = this.endTime < this.duration;\r
+                   halfway = end < this.duration;\r
                    this._timerID && X.Timer.remove( this._timerID );\r
                    \r
                 if( halfway ){\r
-                                       this._timerID = X.Timer.once( this.endTime - begin, this, this._onEnded );\r
+                                       this._timerID = X.Timer.once( end - begin, this, this._onEnded );\r
                 } else {\r
                        delete this._timerID;\r
                 };\r
@@ -327,13 +288,25 @@ if( X.Pulgin.SilverlightEnabled ){
                                },\r
                                \r
                                _onEnded : function(){\r
+                                       var time;\r
                                        delete this._timerID;\r
+                                       \r
                            if( this.playing ){\r
+                               \r
+                               time = this._rawObject.Position.Seconds * 1000 - X_AudioWrapper_getEndTime( this ) | 0;\r
+                               if( time < -16 ){\r
+                                       console.log( '> onEnd ' + time );\r
+                                       this._timerID = X.Timer.once( -time, this, this._onEnded );\r
+                                       return;\r
+                               };\r
+                               \r
                                if( this.loop ){\r
+                                       this.looped = true;\r
                                        this.play();\r
+                                       this.proxy.dispatch( 'looped' );\r
                                } else {\r
                                        this.pause();\r
-                                       this.dispatch( 'ended' );                               \r
+                                       this.proxy.dispatch( 'ended' );                         \r
                                };\r
                            };\r
                                },\r
@@ -352,34 +325,39 @@ if( X.Pulgin.SilverlightEnabled ){
                        \r
                        // SilverlightAudio.state\r
                        state : function( obj ){ // @return Hash: { loop, error, paused, ended, source, duration }\r
-                               var result;\r
+                               var result, end;\r
                                \r
                                if( obj === undefined ){\r
                                    return {\r
                                        startTime     : this.startTime,\r
-                                       endTime       : this.endTime,\r
-                                       loopStartTime : this.loopStartTime,\r
+                                       endTime       : this.endTime < 0 ? this.duration : this.endTime,\r
+                                       loopStartTime : this.loopStartTime < 0 ? this.startTime : this.loopStartTime,\r
+                                       loopEndTime   : this.loopEndTime < 0 ? ( this.endTime || this.duration ) : this.loopEndTime,\r
+                                       \r
                                        currentTime   : this._rawObject.Position.Seconds * 1000,\r
+                                       \r
+                                       \r
                                        loop          : this.loop,\r
+                                       looped        : this.looped,\r
                                        volume        : this.volume,\r
                                        error         : this.error,\r
                                        playing       : this.playing,\r
-                                       duration      : this.duration || 0 // this._rawObject.NaturalDuration.Seconds;\r
+                                       duration      : this.duration // this._rawObject.NaturalDuration.Seconds;\r
                                    };\r
                                };\r
                        \r
                                result = X_AudioWrapper_updateStates( this, obj );\r
                            \r
                                if( result & 2 ){ // seek\r
-                       this.play( this.seekTime );\r
-                       delete this.seekTime;\r
+                       this.play();\r
                                } else {\r
                                        if( result & 1 ){\r
-                                               halfway = this.endTime < this.duration;\r
+                                               end     = X_AudioWrapper_getEndTime( this );\r
+                                               halfway = end < this.duration;\r
                                                this._timerID && X.Timer.remove( this._timerID );\r
                                                \r
                                                if( halfway ){\r
-                                                       this._timerID = X.Timer.once( this.endTime - this._rawObject.Position.Seconds * 1000, this, this._onEnded );\r
+                                                       this._timerID = X.Timer.once( end - this._rawObject.Position.Seconds * 1000, this, this._onEnded );\r
                                                } else {\r
                                                        delete this._timerID;\r
                                                };\r
@@ -395,15 +373,28 @@ if( X.Pulgin.SilverlightEnabled ){
                                _currentTime : function( time ){ // @param Number: time\r
                                        var position = this._rawObject.Position; // [!] create instance\r
        \r
-                                       position.Seconds = time / 1000; // set current time\r
+                                       position.Seconds = time / 1000 | 0; // set current time\r
                                \r
                                        this._rawObject.Position = position; // [!] reattach instance\r
                                }\r
 \r
                }\r
        );\r
-       \r
-};\r
 \r
+       function slerror(){\r
+               alert( 'slerror' );\r
+       };\r
+\r
+       X_Audio_BACKENDS.push( {\r
+               backendName : 'Silverlight Audio',\r
 \r
+               detect : function( proxy, source, ext ){\r
+                       var ok = ext === 'mp3' || ext === 'wma' || ext === 'wav';\r
+                       proxy.asyncDispatch( ok ? 'support' : 'nosupport' );                            \r
+               },\r
+               \r
+               klass : X_Audio_SLAudioWrapper\r
+               \r
+       } );\r
 \r
+};
\ No newline at end of file
diff --git a/0.6.x/js/07_audio/10_XAudioSprite.js b/0.6.x/js/07_audio/10_XAudioSprite.js
new file mode 100644 (file)
index 0000000..4681b61
--- /dev/null
@@ -0,0 +1,298 @@
+\r
+/*\r
+ * http://uupaa.hatenablog.com/entry/2011/12/12/213233\r
+ * Mobile Opera11 は Audio をサポートするがイベントが取れない\r
+ * iframe 内で生成して、Audio Sprite の preset で再生できないか?\r
+ */\r
+var X_Audio_Sprite_shouldUse        = window.HTMLAudioElement && ( X_UA.iOS || X_UA.AndroidBrowser || X_UA.OperaMobile || X_UA.OperaTablet ),\r
+       X_Audio_Sprite_needTouchFirst   = !!X_UA.iOS,\r
+       X_Audio_Sprite_enableMultiTrack = !X_UA.iOS,\r
+       X_Audio_Sprite_enableVolume     = window.HTMLAudioElement && ( !X_UA.iOS && !X_UA.AndroidBrowser && !X_UA.OperaMobile && !X_UA.OperaTablet ),\r
+       X_Audio_Sprite_useVideoForMulti = 4 <= X_UA.AndroidBrowser,\r
+       X_Audio_Sprite_maxTracks        = X_UA.iOS < 6 ? 1 : X_Audio_Sprite_useVideoForMulti ? 2 : 9,\r
+       X_Audio_Sprite_lengthSilence    = 10000, // 一番最初の無音部分の長さ\r
+       X_Audio_Sprite_lengthDistance   = 5000,  // 音間の無音の長さ\r
+       X_Audio_Sprite_uid              = 0,\r
+       X_Audio_Sprite_members          = {},\r
+       X_Audio_Sprite_TEMP             = {\r
+               presets     : {},\r
+               BGMs        : {},\r
+               tracks      : [],\r
+               volume      : 1,\r
+               bgmTrack    : null,\r
+               bgmPosition : 0,\r
+               bgmName     : '',\r
+               bgmLooped   : false,\r
+               bgmPlaying  : false\r
+       },\r
+       X_Audio_Sprite_instance;\r
+\r
+X.Audio.Sprite = {\r
+       \r
+       shouldUse        : X_Audio_Sprite_shouldUse,\r
+       \r
+       needTouchFirst   : X_Audio_Sprite_needTouchFirst,\r
+       \r
+       enableMultiTrack : X_Audio_Sprite_enableMultiTrack,\r
+       \r
+       create : function( setting ){\r
+               // close()\r
+               if( X_Audio_Sprite_instance ){\r
+                       X_Audio_Sprite_instance.close();\r
+               } else {\r
+                       X_Audio_Sprite_instance = X_Class_override( new X.EventDispatcher(), X_Audio_Sprite_members );\r
+               };\r
+               X_Audio_Sprite_instance.setup( setting );\r
+               return X_Audio_Sprite_instance;\r
+               \r
+       }\r
+};\r
+\r
+// 再生が終わっているもの、終わりかけのものを探す\r
+function X_Audio_Sprite_getTrackEnded(){\r
+       var tracks  = X_Audio_Sprite_TEMP.tracks,\r
+               l = tracks.length,\r
+               i = 0, track, state, last = 1 / 0, _last, index;\r
+       \r
+       for( ; i < l; ++i ){\r
+               track = tracks[ i ];\r
+               state = track.state();\r
+               if( !state.playing ) return track;\r
+               if( track === X_Audio_Sprite_TEMP.bgmTrack ) continue;\r
+               if( state.currentTime <= X_Audio_Sprite_lengthSilence + X_Audio_Sprite_lengthDistance ) return track;\r
+               _last = state.endTime - state.currentTime;\r
+               if( _last < last ){\r
+                       last  = _last;\r
+                       index = i;\r
+               };\r
+       };\r
+       return tracks[ index ];\r
+};\r
+\r
+/*\r
+ * {\r
+ *      urls      : [ 'xx.ogg', 'xx.mp3' ],\r
+ *      numTracks : 3,\r
+ *   useVideo  : false,\r
+ *   volume    : 1,\r
+ *      BGM_01 : [ '15.00', '45.500', true, '17.666', '50.999' ],\r
+ *   BGM_02 : [ '56.00', '1:15.230', true ]\r
+ * }\r
+ */\r
+\r
+X_Audio_Sprite_members = {\r
+               \r
+               setup : function( setting ){\r
+                       \r
+                       var tracks  = X_Audio_Sprite_TEMP.tracks,\r
+                               bgms    = X_Audio_Sprite_TEMP.BGMs,\r
+                               presets = X_Audio_Sprite_TEMP.presets,\r
+                               urls    = setting[ 'urls' ],\r
+                               n       = setting[ 'numTracks' ] || 1,\r
+                               video   = setting[ 'useVideo' ],\r
+                               option  = {\r
+                                       volume    : setting[ 'volume' ] || 0.5,\r
+                                       autoplay  : false,\r
+                                       startTime : 0,\r
+                                       endTime   : X_Audio_Sprite_lengthSilence,\r
+                                       loop      : true\r
+                               },\r
+                               k, i;\r
+                       \r
+                       n = n <= X_Audio_Sprite_maxTracks ? n : X_Audio_Sprite_maxTracks;\r
+                       \r
+                       video = video || ( 1 < n && X_Audio_Sprite_useVideoForMulti );\r
+                       \r
+                       for( k in setting ){\r
+                               v = setting[ k ];\r
+                               if( X.Type.isArray( v ) && v !== urls){\r
+                                       v = X.Object.cloneArray( v );\r
+                                       for( i = v.length; i; ){\r
+                                               --i;\r
+                                               if( i !== 2 ) v[ i ] = X_AudioWrapper_timeStringToNumber( v[ i ] );\r
+                                       };                                      \r
+                                       if( v[ 2 ] ) bgms[ k ] = v;\r
+                                       presets[ k ] = v;\r
+                               };\r
+                       };\r
+                       \r
+                       for( i = 0; i < n; ++i ){\r
+                               if( i === 1 && X_Audio_Sprite_useVideoForMulti ){\r
+                                       // use <Video>\r
+                               } else {\r
+                                       tracks.push( X.Audio.create( urls, option ) );\r
+                               };\r
+                       };\r
+                       \r
+                       tracks[ n - 1 ].listenOnce( [ 'backendfound', 'nobackend' ], this, X_Audio_Sprite_handleEvent );\r
+               },\r
+               \r
+               close : function(){\r
+                       var tracks  = X_Audio_Sprite_TEMP.tracks,\r
+                               bgms    = X_Audio_Sprite_TEMP.BGMs,\r
+                               presets = X_Audio_Sprite_TEMP.presets,\r
+                               k;\r
+                       \r
+                       while( tracks.length ){\r
+                               tracks.pop().kill();\r
+                       };\r
+                       \r
+                       for( k in bgms ){\r
+                               delete bgms[ k ];\r
+                       };\r
+                       for( k in presets ){\r
+                               delete presets[ k ];\r
+                       };\r
+                       \r
+                       X_Audio_Sprite_TEMP.bgmTrack    = null;\r
+                       X_Audio_Sprite_TEMP.bgmPosition = 0;\r
+                       X_Audio_Sprite_TEMP.bgmName     = '';\r
+                       X_Audio_Sprite_TEMP.bgmLooped   = false;\r
+                       X_Audio_Sprite_TEMP.bgmPlaying  = false;\r
+               },\r
+               \r
+               load : function(){\r
+                       tracks[ 0 ].play( 0, X_Audio_Sprite_lengthSilence, true );\r
+               },\r
+               \r
+               /*\r
+                * @return uid Number\r
+                */\r
+               play : function( name ){\r
+                       var bgm     = X_Audio_Sprite_TEMP.bgmTrack,\r
+                               tracks  = X_Audio_Sprite_TEMP.tracks,\r
+                               bgms    = X_Audio_Sprite_TEMP.BGMs,\r
+                               presets = X_Audio_Sprite_TEMP.presets,\r
+                               preset  = presets[ name ],\r
+                               i, k;\r
+                       \r
+                       if( preset ){\r
+                               if( bgms[ name ] ){\r
+                                       if( name !== X_Audio_Sprite_TEMP.bgmName ){\r
+                                               // bgm変更\r
+                                               X_Audio_Sprite_TEMP.bgmName     = name;\r
+                                               X_Audio_Sprite_TEMP.bgmPosition = preset[ 0 ];\r
+                                               X_Audio_Sprite_TEMP.bgmPlaying  = true;\r
+                                               X_Audio_Sprite_TEMP.bgmLooped   = false;\r
+                                       };\r
+                                       if( bgm ){\r
+                                               track = bgm;\r
+                                       } else\r
+                                       if( 1 < tracks.length ){\r
+                                               track = X_Audio_Sprite_TEMP.bgmTrack = X_Audio_Sprite_getTrackEnded();\r
+                                       } else {\r
+                                               track = X_Audio_Sprite_TEMP.bgmTrack = tracks[ 0 ];\r
+                                       };\r
+                                       track\r
+                                               .state( { looped : X_Audio_Sprite_TEMP.bgmLooped } )\r
+                                               .play( preset[ 0 ], preset[ 1 ], true, preset[ 3 ], preset[ 4 ] )\r
+                                               .seek( X_Audio_Sprite_TEMP.bgmPosition )\r
+                                               .listen( 'looped', this, X_Audio_Sprite_handleEvent );\r
+                               } else {\r
+                                       if( 1 < tracks.length ){\r
+                                               track = X_Audio_Sprite_getTrackEnded( X_Audio_Sprite_TEMP.bgmPlaying );\r
+                                               track\r
+                                                       .listen( 'looped', this, X_Audio_Sprite_handleEvent )\r
+                                                       .state( { looped : false } )\r
+                                                       .play( preset[ 0 ], preset[ 1 ], true, 0, X_Audio_Sprite_lengthSilence );\r
+                                       } else {\r
+                                               // single track, iOS\r
+                                               if( bgm ){\r
+                                                       X_Audio_Sprite_TEMP.bgmPosition = bgm.currentTime();\r
+                                                       X_Audio_Sprite_TEMP.bgmTrack    = null;\r
+                                               };\r
+                                               track = tracks[ 0 ];\r
+                                               track\r
+                                                       .listen( 'looped', this, X_Audio_Sprite_handleEvent )\r
+                                                       .state( { looped : false } )\r
+                                                       .play( preset[ 0 ], preset[ 1 ], true, 0, X_Audio_Sprite_lengthSilence );\r
+                                       };\r
+                               };\r
+                               return tracks.indexOf( track );\r
+                       };\r
+                       return -1;\r
+               },\r
+               \r
+               pause : function( uid ){\r
+                       var track = X_Audio_Sprite_TEMP.tracks[ uid ];\r
+                       if( X_Audio_Sprite_TEMP.bgmTrack === track ){\r
+                               X_Audio_Sprite_TEMP.bgmPosition = track.currentTime();\r
+                               X_Audio_Sprite_TEMP.bgmPlaying  = false;\r
+                               X_Audio_Sprite_TEMP.bgmTrack    = null;\r
+                       };\r
+                       console.log( 'pause' );\r
+                       track && track.play( 0, X_Audio_Sprite_lengthSilence, true, 0, X_Audio_Sprite_lengthSilence ).seek( 0 );\r
+                       return this;\r
+               },\r
+               \r
+               seek : function( uid, position ){\r
+                       var track = X_Audio_Sprite_TEMP.tracks[ uid ],\r
+                               end;\r
+                       if( track ){\r
+                               delete track.seekTime;\r
+                               end = X_AudioWrapper_getEndTime( track );\r
+                               position <= end && X_AudioWrapper_getStartTime( track, end ) <= position && track.seek( postion );\r
+                       };\r
+                       return this;\r
+               },\r
+               \r
+               volume : function( uid, opt_volume ){\r
+                       var track, i;\r
+                       // TODO uid = 0\r
+                       if( uid === 0 ){\r
+                               if( opt_volume === undefined ){\r
+                                       return X_Audio_Sprite_TEMP.volume;\r
+                               };\r
+                               for( i = X_Audio_Sprite_TEMP.tracks.length; i; ){\r
+                                       X_Audio_Sprite_TEMP.tracks[ --i ].volume( opt_volume );\r
+                               };\r
+                               return this;\r
+                       };\r
+                       track = X_Audio_Sprite_TEMP.tracks[ uid ];\r
+                       if( opt_volume === undefined ){\r
+                               return track ? track.volume() : -1;\r
+                       };\r
+                       track && track.volume( opt_volume );\r
+                       return this;\r
+               },\r
+               \r
+               state : function( uid, opt_obj ){\r
+                       var track = X_Audio_Sprite_TEMP.tracks[ uid ];\r
+                       // TODO uid = 0\r
+                       if( opt_obj === undefined ){\r
+                               return track ? track.state() : { volume : X_Audio_Sprite_TEMP.volume };\r
+                       };\r
+                       track && track.state( opt_obj );\r
+                       return this;\r
+               }\r
+};\r
+\r
+function X_Audio_Sprite_handleEvent( e ){\r
+       switch( e.type ){\r
+               case 'backendfound' :\r
+                       this.asyncDispatch( e );\r
+                       e.target.unlisten( 'nobackend', this, X_Audio_Sprite_handleEvent );\r
+                       break;\r
+\r
+               case 'nobackend' :\r
+                       this.asyncDispatch( e );\r
+                       e.target.unlisten( 'backendfound', this, X_Audio_Sprite_handleEvent );\r
+                       break;\r
+               \r
+               case 'looped' :\r
+                       if( e.target === X_Audio_Sprite_TEMP.bgmTrack ){\r
+                               X_Audio_Sprite_TEMP.bgmLooped = true;\r
+                       } else {\r
+                               // single track | iOS\r
+                               if( X_Audio_Sprite_TEMP.bgmPlaying && !X_Audio_Sprite_TEMP.bgmTrack ){\r
+                                       X_Audio_Sprite_TEMP.bgmTrack = e.target;\r
+                                       this.play( X_Audio_Sprite_TEMP.bgmName );\r
+                               };\r
+                       };\r
+                       break;\r
+               \r
+               case X.Event.KILL_INSTANCE :\r
+                       this.close();\r
+                       break;\r
+       };\r
+};\r
index f13d9df..4089730 100644 (file)
@@ -7,7 +7,7 @@ X.UI._ChromeBox = X.UI._Box.inherits(
                \r
                Constructor : function( layout, args ){\r
                        \r
-                       this.SuperConstructor( layout, args );\r
+                       this.Super( layout, args );\r
                        \r
                        // xnode の追加が可能\r
                        \r
index 14f8bbd..b108e48 100644 (file)
@@ -920,7 +920,7 @@ X.UI._ScrollBox = X.UI._ChromeBox.inherits(
                scrollManager  : null,\r
                \r
                Constructor : function( layout, args ){\r
-                       this.SuperConstructor( layout, args );\r
+                       this.Super( layout, args );\r
                        this._containerNode = _X_Class_getPrivate( this.containerNode );\r
                },\r
                \r
index eae3e90..fd84be3 100644 (file)
@@ -83,7 +83,7 @@ X.UI._PageRoot = X.UI._Box.inherits(
                _eventBusy            : false,
                
                Constructor : function( layout, args ){
-                       this.SuperConstructor( layout, args );
+                       this.Super( layout, args );
                        
                        if( X_ViewPort_readyState === X.Event.XDOM_READY ){
                                X.Timer.once( 0, this, this.start );
index 9dcc19f..4b34d64 100644 (file)
@@ -57,7 +57,8 @@ document.write( [
                'js/07_audio/00_XAudio.js',\r
                'js/07_audio/01_XWebAudio.js',\r
                'js/07_audio/02_XHTMLAudio.js',\r
-               'js/07_audio/03_XSilverlightAudio.js'\r
+               'js/07_audio/03_XSilverlightAudio.js',\r
+               'js/07_audio/10_XAudioSprite.js'\r
 \r
        + '"></script>'\r
 ].join( '"></script><script src="' + basePath ));\r