X-Git-Url: http://git.osdn.jp/view?a=blobdiff_plain;f=0.6.x%2Fjs%2F07_audio%2F00_XAudio.js;h=4b48359b5dd9454c2cb85ca428a38b25f4374e58;hb=bafa8683f87b2f909d1301fca80684bf9ff221ed;hp=b12e679e9190911344bcb060a67b8a0ed7c4c5bc;hpb=e28511741c97176b8ffe67bb1ea0660da37f754b;p=pettanr%2FclientJs.git diff --git a/0.6.x/js/07_audio/00_XAudio.js b/0.6.x/js/07_audio/00_XAudio.js index b12e679..4b48359 100644 --- a/0.6.x/js/07_audio/00_XAudio.js +++ b/0.6.x/js/07_audio/00_XAudio.js @@ -1,7 +1,7 @@  /* WebAudio : 1, - HTML5 : 2, + HTMLAudio : 2, Flash : 3, Silverlight : 4, Unity : 5, @@ -15,35 +15,39 @@ var X_Audio_BACKENDS = []; // Array. X_TEMP.onSystemReady.push( function(){ var canPlay = X[ 'Audio' ][ 'canPlay' ] = {}, - i = X_Audio_BACKENDS.length; + i = X_Audio_BACKENDS.length, + be; for( ; i; ){ - X_Object_override( canPlay, X_Audio_BACKENDS[ --i ].canPlay ); + be = X_Audio_BACKENDS[ --i ]; + X_Object_override( canPlay, be.canPlay ); + X[ 'Audio' ][ be.backendName ] = be.backendID; }; }); /** - *

複数のバックエンドから、与えられた音声を再生可能なものを見つけ、音声を再生します。 + *

複数のオーディオ・バックエンドから、与えられた音声を再生可能なものを見つけ、音声を再生します。 *

HTMLAudio の動作・機能がブラウザ毎にバラバラなのに業を煮やし、メソッドやイベントは独自に定義しています。 *

バックエンドの種類

- *

HTMLAudio, WebAudio, Silverlight + *

HTMLAudio, WebAudio, Silverlight, WMP *

イベント

*
- *
X.Event.BACKEND_READY
音声(src リスト)を再生可能なバックエンドが見つかった。 - *
X.Event.BACKEND_NONE
音声を再生可能なバックエンドが見つからなかった。 - *
X.Event.READY
再生可能、実際の状態は canplay から loadeddata まで様々、、、 - *
X.Event.ERROR
    + *
    X.Event.BACKEND_READY
    音声(src リスト)を再生可能なバックエンドが見つかった。 + *
    X.Event.BACKEND_NONE
    音声を再生可能なバックエンドが見つからなかった。Audio は kill されます。 + *
    X.Event.MEDIA_CAN_TOUCH
    モバイル端末の制約で音声の再生またはロードに、タッチを必要とする場合、タッチイベント内で play を呼び出す準備が出来たことを通知する。 + *
    X.Event.READY
    再生可能、実際の状態は canplay から loadeddata まで様々、、、 + *
    X.Event.ERROR
      *
    • 1 : ユーザーによってメディアの取得が中断された *
    • 2 : ネットワークエラー *
    • 3 : メディアのデコードエラー *
    • 4 : メディアがサポートされていない *
    - *
    X.Event.MEDIA_PLAYING
    再生中に1秒以下のタイミングで発生.currentTime が取れる? - *
    X.Event.MEDIA_LOOP
    ループ直前に発生、キャンセル可能 - *
    X.Event.MEDIA_LOOPED
    ループ時に発生 - *
    X.Event.MEDIA_ENDED
    再生位置の(音声の)最後についた - *
    X.Event.MEDIA_PAUSED
    ポーズした - *
    X.Event.MEDIA_WAITING
    再生中に音声が待機状態に。間もなく X.Event.MEDIA_PLAYING に移行。 - *
    X.Event.MEDIA_SEEKING
    シーク中に音声が待機状態に。間もなく X.Event.MEDIA_PLAYING に移行。 + *
    X.Event.MEDIA_PLAYING
    再生中に1秒以下のタイミングで発生.currentTime が取れる? + *
    X.Event.MEDIA_LOOP
    ループ直前に発生、キャンセル可能 + *
    X.Event.MEDIA_LOOPED
    ループ時に発生 + *
    X.Event.MEDIA_ENDED
    再生位置の(音声の)最後についた + *
    X.Event.MEDIA_PAUSED
    ポーズした + *
    X.Event.MEDIA_WAITING
    再生中に音声が待機状態に。 + *
    X.Event.MEDIA_SEEKING
    シーク中に音声が待機状態に。 *
* * @alias X.Audio @@ -53,12 +57,11 @@ X_TEMP.onSystemReady.push( * @param {array|string} sourceList * @param {object=} opt_option * @example // - * var audio = X.Audio( [ 'etc/special.mp3', 'etc/special.ogg', 'etc/special.wav' ] ) - .listenOnce( X.Event.READY, onReady ); + * var audio = X.Audio( [ 'etc/special.mp3', 'etc/special.ogg', 'etc/special.wav' ] ).listenOnce( X.Event.READY, onReady ); */ X[ 'Audio' ] = X_EventDispatcher[ 'inherits' ]( 'X.Audio', - X_Class.POOL_OBJECT, + X_Class.NONE, { /** * 音声の url。X.Event.BACKEND_READY で設定される。 @@ -66,24 +69,32 @@ X[ 'Audio' ] = X_EventDispatcher[ 'inherits' ]( * @type {string} */ 'source' : '', + /** * 音声再生バックエンドの名前。X.Event.BACKEND_READY で設定される。 * @alias Audio.prototype.backendName * @type {string} */ 'backendName' : '', - + 'Constructor' : function( sourceList, opt_option ){ X_Audio_startDetectionBackend( X_Audio_BACKENDS[ 0 ], this, X_Type_isArray( sourceList ) ? X_Array_copy( sourceList ) : [ sourceList ], opt_option || {} ); this[ 'listenOnce' ]( [ X_EVENT_BACKEND_READY, X_EVENT_BACKEND_NONE, X_EVENT_KILL_INSTANCE ], X_Audio_handleEvent ); + X_ViewPort[ 'listenOnce' ]( X_EVENT_UNLOAD, this, X_AudioSprite_handleEvent ); }, /** * 再生。開始位置・終了位置、ループの有無、ループ以降の開始位置、ループ以降の終了位置 * @alias Audio.prototype.play + * @param {number=} startTime 開始時間を ms で + * @param {number=} endTime 終了時間を ms で + * @param {boolean=} loop endTimeに達した際に曲をループさせるか + * @param {number=} loopStartTime ループ以後の開始時間を ms で + * @param {number=} loopEndTime ループ以後の終了時間を ms で + * @return {Audio} メソッドチェーン */ 'play' : function( startTime, endTime, loop, loopStartTime, loopEndTime ){ var pair = X_Pair_get( this ); @@ -91,8 +102,10 @@ X[ 'Audio' ] = X_EventDispatcher[ 'inherits' ]( return this; }, /** - * シーク + * シーク、再生中で無い場合は次回再生開始位置の指定のみ * @alias Audio.prototype.seek + * @param {number} seekTime シーク位置を ms で + * @return {Audio} メソッドチェーン */ 'seek' : function( seekTime ){ var pair = X_Pair_get( this ); @@ -102,6 +115,7 @@ X[ 'Audio' ] = X_EventDispatcher[ 'inherits' ]( /** * ポーズ * @alias Audio.prototype.pause + * @return {Audio} メソッドチェーン */ 'pause' : function(){ var pair = X_Pair_get( this ); @@ -111,6 +125,21 @@ X[ 'Audio' ] = X_EventDispatcher[ 'inherits' ]( /** * 状態の getter と setter * @alias Audio.prototype.state + * @param {object=} obj setter の場合、上書きする値を格納したobject + * @return {Audio|object} + * @example +audio.setState( + { + 'startTime' : 0, + 'endTime' : 80000, + 'loopStartTime' : 120000, + 'loopEndTime' : 200000, + 'currentTime' : 0, + 'loop' : true, + 'looded' : false, + 'volume' : 1, + 'autoplay' : true +}); */ 'state' : function( obj ){ var pair = X_Pair_get( this ); @@ -124,18 +153,22 @@ X[ 'Audio' ] = X_EventDispatcher[ 'inherits' ]( 'currentTime' : -1, 'loop' : false, 'looded' : false, - 'error' : false, + 'error' : 0, + 'autoplay' : false, 'playing' : false, - 'source' : this[ 'source' ] || '', - 'duration' : 0 + 'source' : this[ 'source' ], + 'duration' : 0, + 'volume' : 0.5 }; }; pair && pair.setState( obj ); return this; }, /** - * ループの getter と setter + * ループの setter * @alias Audio.prototype.loop + * @param {boolean} v + * @return {Audio} */ 'loop' : function( v ){ var pair = X_Pair_get( this ); @@ -143,8 +176,10 @@ X[ 'Audio' ] = X_EventDispatcher[ 'inherits' ]( return this; }, /** - * ボリュームの getter と setter 実装不十分! + * ボリュームの setter 実装不十分! * @alias Audio.prototype.volume + * @param {number} v 0~1 + * @return {Audio} */ 'volume' : function( v ){ var pair = X_Pair_get( this ); @@ -152,8 +187,10 @@ X[ 'Audio' ] = X_EventDispatcher[ 'inherits' ]( return this; }, /** - * 再生位置。 + * 再生位置のsetter。 * @alias Audio.prototype.currentTime + * @param {number} v msで + * @return {Audio} */ 'currentTime' : function( v ){ var pair = X_Pair_get( this ); @@ -163,6 +200,7 @@ X[ 'Audio' ] = X_EventDispatcher[ 'inherits' ]( /** * 再生中か? * @alias Audio.prototype.isPlaying + * @return {boolean} */ 'isPlaying' : function(){ var pair = X_Pair_get( this ); @@ -173,7 +211,7 @@ X[ 'Audio' ] = X_EventDispatcher[ 'inherits' ]( ); function X_Audio_handleEvent( e ){ - var backend; + var backend, pair; switch( e.type ){ case X_EVENT_BACKEND_READY : @@ -182,17 +220,28 @@ function X_Audio_handleEvent( e ){ this[ 'unlisten' ]( X_EVENT_BACKEND_NONE, X_Audio_handleEvent ); this[ 'source' ] = e[ 'source' ]; this[ 'backendName' ] = backend.backendName; + X_Pair_create( this, backend.klass( this, e[ 'source' ], e[ 'option' ] ) ); + this[ 'listenOnce' ]( X_EVENT_READY, X_Audio_handleEvent ); + break; + + case X_EVENT_READY : + pair = X_Pair_get( this ); + ( pair.autoplay || pair._playReserved ) && pair.actualPlay(); + delete pair._playReserved; break; case X_EVENT_BACKEND_NONE : + case X_EVENT_UNLOAD : this[ 'kill' ](); break; case X_EVENT_KILL_INSTANCE : - backend = X_Pair_get( this ); - backend && backend[ 'kill' ](); - X_Pair_release( this, backend ); + X_ViewPort[ 'unlisten' ]( X_EVENT_UNLOAD, this, X_AudioSprite_handleEvent ); + if( backend = X_Pair_get( this ) ){ + backend[ 'kill' ](); + X_Pair_release( this, backend ); + }; break; }; }; @@ -246,28 +295,28 @@ function X_Audio_onEndedDetection( e, xaudio, sourceList, option, source, ext, s -var X_Audio_AbstractAudioBackend = X_EventDispatcher[ 'inherits' ]( - 'X.AbstractAudioBackend', +var X_AudioBase = X_EventDispatcher[ 'inherits' ]( + 'X.AudioBase', X_Class.ABSTRACT, { + disatcher : null, - url : '', - target : null, - - startTime : 0, - endTime : -1, + startTime : 0, // state_startTime + endTime : -1, // state_startTime loopStartTime : -1, loopEndTime : -1, seekTime : -1, - duration : 0, + duration : 0, // playing : false, - error : 0, + error : 0, // autoLoop : false, looped : false, - autoplay : false, + autoplay : false,// gain : 0.5, + _playReserved : false, + play : function( startTime, endTime, loop, loopStartTime, loopEndTime ){ if( 0 <= startTime ){ this.setState( { @@ -275,21 +324,26 @@ var X_Audio_AbstractAudioBackend = X_EventDispatcher[ 'inherits' ]( 'startTime' : startTime, 'endTime' : endTime, 'loop' : loop, + 'looped' : false, 'loopStartTime' : loopStartTime, 'loopEndTime' : loopEndTime } ); }; + // canPlay() : autoplay = true this.actualPlay(); }, seek : function( seekTime ){ - if( seekTime < X_AudioWrapper_getEndTime( this ) ){ + if( seekTime < X_Audio_getEndTime( this ) ){ this.setState( { 'currentTime' : seekTime } ); }; }, pause : function(){ + this.seekTime = this.getActualCurrentTime(); this.playing && this.actualPause(); + // delete this.autoplay + // delete this.playing }, loop : function( v ){ @@ -325,6 +379,7 @@ var X_Audio_AbstractAudioBackend = X_EventDispatcher[ 'inherits' ]( 'volume' : this.gain, 'playing' : this.playing, 'duration' : this.duration, + 'autoplay' : this.autoplay, 'currentTime' : this.playing ? this.getActualCurrentTime() : this.seekTime, 'error' : this.getActualError ? this.getActualError() : this.error @@ -339,8 +394,8 @@ var X_Audio_AbstractAudioBackend = X_EventDispatcher[ 'inherits' ]( for( k in obj ){ v = obj[ k ]; switch( k ){ - case 'currentTime' : - v = X_AudioWrapper_timeStringToNumber( v ); + case 'currentTime' : + v = X_Audio_timeStringToNumber( v ); if( X_Type_isNumber( v ) ){ if( playing ){ if( this.getActualCurrentTime() !== v ){ @@ -356,7 +411,7 @@ var X_Audio_AbstractAudioBackend = X_EventDispatcher[ 'inherits' ]( break; case 'startTime' : - v = X_AudioWrapper_timeStringToNumber( v ); + v = X_Audio_timeStringToNumber( v ); if( v || v === 0 ){ if( this.startTime !== v ){ this.startTime = v; @@ -367,7 +422,7 @@ var X_Audio_AbstractAudioBackend = X_EventDispatcher[ 'inherits' ]( break; case 'endTime' : - v = X_AudioWrapper_timeStringToNumber( v ); + v = X_Audio_timeStringToNumber( v ); if( v || v === 0 ){ if( this.endTime !== v ){ this.endTime = v; @@ -380,7 +435,7 @@ var X_Audio_AbstractAudioBackend = X_EventDispatcher[ 'inherits' ]( break; case 'loopStartTime' : - v = X_AudioWrapper_timeStringToNumber( v ); + v = X_Audio_timeStringToNumber( v ); if( v || v === 0 ){ if( this.loopStartTime !== v ){ this.loopStartTime = v; @@ -391,7 +446,7 @@ var X_Audio_AbstractAudioBackend = X_EventDispatcher[ 'inherits' ]( break; case 'loopEndTime' : - v = X_AudioWrapper_timeStringToNumber( v ); + v = X_Audio_timeStringToNumber( v ); if( v || v === 0 ){ if( this.loopEndTime !== v ){ this.loopEndTime = v; @@ -432,35 +487,38 @@ var X_Audio_AbstractAudioBackend = X_EventDispatcher[ 'inherits' ]( }; }; break; + case 'useVideo' : + break; default : - throw 'bad arg'; + alert( 'bad arg! ' + k ); }; }; if( this.endTime < this.startTime || ( this.loopEndTime < 0 ? this.endTime : this.loopEndTime ) < ( this.loopStartTime < 0 ? this.startTime : this.loopStartTime ) || - X_AudioWrapper_getEndTime( this ) < this.seekTime// || + X_Audio_getEndTime( this ) < this.seekTime// || //this.duration < this.endTime ){ - console.log( 'setState 0:' + this.startTime + ' -> ' + this.endTime + ' d:' + this.duration + ' 1:' + this.loopStartTime + ' -> ' + this.loopEndTime ); + console.log( 'setState 0:' + this.startTime + ' -> ' + this.endTime + ' looped:' + this.looped + ' 1:' + this.loopStartTime + ' -> ' + this.loopEndTime ); return; }; v = end + seek + volume; - return v && this.afterUpdateState( v ); + return v && this.playing && this.afterUpdateState( v ); } } ); -function X_AudioWrapper_timeStringToNumber( time ){ +function X_Audio_timeStringToNumber( time ){ var ary, ms, s = 0, m = 0, h = 0; + if( X_Type_isNumber( time ) ) return time; if( !X_Type_isString( time ) || !time.length ) return; ary = time.split( '.' ); - ms = parseInt( ( ary[ 1 ] + '000' ).substr( 0, 3 ) ) || 0; + ms = parseFloat( ( ary[ 1 ] + '000' ).substr( 0, 3 ) ) || 0; ary = ary[ 0 ].split( ':' ); if( 3 < ary.length ) return; @@ -469,17 +527,17 @@ function X_AudioWrapper_timeStringToNumber( time ){ case 0 : break; case 1 : - s = parseInt( ary[ 0 ] ) || 0; + s = parseFloat( ary[ 0 ] ) || 0; break; case 2 : - m = parseInt( ary[ 0 ] ) || 0; - s = parseInt( ary[ 1 ] ) || 0; + m = parseFloat( ary[ 0 ] ) || 0; + s = parseFloat( ary[ 1 ] ) || 0; if( 60 <= s ) alert( 'invalid time string ' + time ); break; case 3 : - h = parseInt( ary[ 0 ] ) || 0; - m = parseInt( ary[ 1 ] ) || 0; - s = parseInt( ary[ 2 ] ) || 0; + h = parseFloat( ary[ 0 ] ) || 0; + m = parseFloat( ary[ 1 ] ) || 0; + s = parseFloat( ary[ 2 ] ) || 0; if( 60 <= s ) alert( 'invalid time string ' + time ); if( 60 <= m ) alert( 'invalid time string ' + time ); break; @@ -490,33 +548,34 @@ function X_AudioWrapper_timeStringToNumber( time ){ return ms < 0 ? 0 : ms; }; -function X_AudioWrapper_getStartTime( audioWrapper, endTime, delSeekTime ){ - var seek = audioWrapper.seekTime; - if( delSeekTime ) delete audioWrapper.seekTime; +function X_Audio_getStartTime( audioBase, endTime, delSeekTime ){ + var seek = audioBase.seekTime; + + if( delSeekTime ) delete audioBase.seekTime; if( 0 <= seek ){ - if( audioWrapper.duration <= seek || endTime < seek ) return 0; + if( audioBase.duration <= seek || endTime < seek ) return 0; return seek; }; - if( audioWrapper.looped && 0 <= audioWrapper.loopStartTime ){ - if( audioWrapper.duration <= audioWrapper.loopStartTime || endTime < audioWrapper.loopStartTime ) return 0; - return audioWrapper.loopStartTime; + if( audioBase.looped && 0 <= audioBase.loopStartTime ){ + if( audioBase.duration <= audioBase.loopStartTime || endTime < audioBase.loopStartTime ) return 0; + return audioBase.loopStartTime; }; - if( audioWrapper.startTime < 0 || audioWrapper.duration <= audioWrapper.startTime ) return 0; - return audioWrapper.startTime; + if( audioBase.startTime < 0 || audioBase.duration <= audioBase.startTime ) return 0; + return audioBase.startTime; }; -function X_AudioWrapper_getEndTime( audioWrapper ){ - var duration = audioWrapper.duration; +function X_Audio_getEndTime( audioBase ){ + var duration = audioBase.duration; - if( audioWrapper.looped && 0 <= audioWrapper.loopEndTime ){ - if( duration <= audioWrapper.loopEndTime ) return duration; - return audioWrapper.loopEndTime; + if( audioBase.looped && 0 <= audioBase.loopEndTime ){ + if( duration <= audioBase.loopEndTime ) return duration; + return audioBase.loopEndTime; }; - if( audioWrapper.endTime < 0 || duration <= audioWrapper.endTime ) return duration; - return audioWrapper.endTime; + if( audioBase.endTime < 0 || duration <= audioBase.endTime ) return duration; + return audioBase.endTime; };