OSDN Git Service

Version 0.6.114, add AudioSprite, etc.
[pettanr/clientJs.git] / 0.6.x / js / 07_audio / 10_XAudioSprite.js
1 \r
2 /*\r
3  * http://uupaa.hatenablog.com/entry/2011/12/12/213233\r
4  * Mobile Opera11 は Audio をサポートするがイベントが取れない\r
5  * iframe 内で生成して、Audio Sprite の preset で再生できないか?\r
6  */\r
7 var X_Audio_Sprite_shouldUse        = window.HTMLAudioElement && ( X_UA.iOS || X_UA.AndroidBrowser || X_UA.OperaMobile || X_UA.OperaTablet ),\r
8         X_Audio_Sprite_needTouchFirst   = !!X_UA.iOS,\r
9         X_Audio_Sprite_enableMultiTrack = !X_UA.iOS,\r
10         X_Audio_Sprite_enableVolume     = window.HTMLAudioElement && ( !X_UA.iOS && !X_UA.AndroidBrowser && !X_UA.OperaMobile && !X_UA.OperaTablet ),\r
11         X_Audio_Sprite_useVideoForMulti = 4 <= X_UA.AndroidBrowser,\r
12         X_Audio_Sprite_maxTracks        = X_UA.iOS < 6 ? 1 : X_Audio_Sprite_useVideoForMulti ? 2 : 9,\r
13         X_Audio_Sprite_lengthSilence    = 10000, // 一番最初の無音部分の長さ\r
14         X_Audio_Sprite_lengthDistance   = 5000,  // 音間の無音の長さ\r
15         X_Audio_Sprite_uid              = 0,\r
16         X_Audio_Sprite_members          = {},\r
17         X_Audio_Sprite_TEMP             = {\r
18                 presets     : {},\r
19                 BGMs        : {},\r
20                 tracks      : [],\r
21                 volume      : 1,\r
22                 bgmTrack    : null,\r
23                 bgmPosition : 0,\r
24                 bgmName     : '',\r
25                 bgmLooped   : false,\r
26                 bgmPlaying  : false\r
27         },\r
28         X_Audio_Sprite_instance;\r
29 \r
30 X.Audio.Sprite = {\r
31         \r
32         shouldUse        : X_Audio_Sprite_shouldUse,\r
33         \r
34         needTouchFirst   : X_Audio_Sprite_needTouchFirst,\r
35         \r
36         enableMultiTrack : X_Audio_Sprite_enableMultiTrack,\r
37         \r
38         create : function( setting ){\r
39                 // close()\r
40                 if( X_Audio_Sprite_instance ){\r
41                         X_Audio_Sprite_instance.close();\r
42                 } else {\r
43                         X_Audio_Sprite_instance = X_Class_override( new X.EventDispatcher(), X_Audio_Sprite_members );\r
44                 };\r
45                 X_Audio_Sprite_instance.setup( setting );\r
46                 return X_Audio_Sprite_instance;\r
47                 \r
48         }\r
49 };\r
50 \r
51 // 再生が終わっているもの、終わりかけのものを探す\r
52 function X_Audio_Sprite_getTrackEnded(){\r
53         var tracks  = X_Audio_Sprite_TEMP.tracks,\r
54                 l = tracks.length,\r
55                 i = 0, track, state, last = 1 / 0, _last, index;\r
56         \r
57         for( ; i < l; ++i ){\r
58                 track = tracks[ i ];\r
59                 state = track.state();\r
60                 if( !state.playing ) return track;\r
61                 if( track === X_Audio_Sprite_TEMP.bgmTrack ) continue;\r
62                 if( state.currentTime <= X_Audio_Sprite_lengthSilence + X_Audio_Sprite_lengthDistance ) return track;\r
63                 _last = state.endTime - state.currentTime;\r
64                 if( _last < last ){\r
65                         last  = _last;\r
66                         index = i;\r
67                 };\r
68         };\r
69         return tracks[ index ];\r
70 };\r
71 \r
72 /*\r
73  * {\r
74  *       urls      : [ 'xx.ogg', 'xx.mp3' ],\r
75  *       numTracks : 3,\r
76  *   useVideo  : false,\r
77  *   volume    : 1,\r
78  *       BGM_01 : [ '15.00', '45.500', true, '17.666', '50.999' ],\r
79  *   BGM_02 : [ '56.00', '1:15.230', true ]\r
80  * }\r
81  */\r
82 \r
83 X_Audio_Sprite_members = {\r
84                 \r
85                 setup : function( setting ){\r
86                         \r
87                         var tracks  = X_Audio_Sprite_TEMP.tracks,\r
88                                 bgms    = X_Audio_Sprite_TEMP.BGMs,\r
89                                 presets = X_Audio_Sprite_TEMP.presets,\r
90                                 urls    = setting[ 'urls' ],\r
91                                 n       = setting[ 'numTracks' ] || 1,\r
92                                 video   = setting[ 'useVideo' ],\r
93                                 option  = {\r
94                                         volume    : setting[ 'volume' ] || 0.5,\r
95                                         autoplay  : false,\r
96                                         startTime : 0,\r
97                                         endTime   : X_Audio_Sprite_lengthSilence,\r
98                                         loop      : true\r
99                                 },\r
100                                 k, i;\r
101                         \r
102                         n = n <= X_Audio_Sprite_maxTracks ? n : X_Audio_Sprite_maxTracks;\r
103                         \r
104                         video = video || ( 1 < n && X_Audio_Sprite_useVideoForMulti );\r
105                         \r
106                         for( k in setting ){\r
107                                 v = setting[ k ];\r
108                                 if( X.Type.isArray( v ) && v !== urls){\r
109                                         v = X.Object.cloneArray( v );\r
110                                         for( i = v.length; i; ){\r
111                                                 --i;\r
112                                                 if( i !== 2 ) v[ i ] = X_AudioWrapper_timeStringToNumber( v[ i ] );\r
113                                         };                                      \r
114                                         if( v[ 2 ] ) bgms[ k ] = v;\r
115                                         presets[ k ] = v;\r
116                                 };\r
117                         };\r
118                         \r
119                         for( i = 0; i < n; ++i ){\r
120                                 if( i === 1 && X_Audio_Sprite_useVideoForMulti ){\r
121                                         // use <Video>\r
122                                 } else {\r
123                                         tracks.push( X.Audio.create( urls, option ) );\r
124                                 };\r
125                         };\r
126                         \r
127                         tracks[ n - 1 ].listenOnce( [ 'backendfound', 'nobackend' ], this, X_Audio_Sprite_handleEvent );\r
128                 },\r
129                 \r
130                 close : function(){\r
131                         var tracks  = X_Audio_Sprite_TEMP.tracks,\r
132                                 bgms    = X_Audio_Sprite_TEMP.BGMs,\r
133                                 presets = X_Audio_Sprite_TEMP.presets,\r
134                                 k;\r
135                         \r
136                         while( tracks.length ){\r
137                                 tracks.pop().kill();\r
138                         };\r
139                         \r
140                         for( k in bgms ){\r
141                                 delete bgms[ k ];\r
142                         };\r
143                         for( k in presets ){\r
144                                 delete presets[ k ];\r
145                         };\r
146                         \r
147                         X_Audio_Sprite_TEMP.bgmTrack    = null;\r
148                         X_Audio_Sprite_TEMP.bgmPosition = 0;\r
149                         X_Audio_Sprite_TEMP.bgmName     = '';\r
150                         X_Audio_Sprite_TEMP.bgmLooped   = false;\r
151                         X_Audio_Sprite_TEMP.bgmPlaying  = false;\r
152                 },\r
153                 \r
154                 load : function(){\r
155                         tracks[ 0 ].play( 0, X_Audio_Sprite_lengthSilence, true );\r
156                 },\r
157                 \r
158                 /*\r
159                  * @return uid Number\r
160                  */\r
161                 play : function( name ){\r
162                         var bgm     = X_Audio_Sprite_TEMP.bgmTrack,\r
163                                 tracks  = X_Audio_Sprite_TEMP.tracks,\r
164                                 bgms    = X_Audio_Sprite_TEMP.BGMs,\r
165                                 presets = X_Audio_Sprite_TEMP.presets,\r
166                                 preset  = presets[ name ],\r
167                                 i, k;\r
168                         \r
169                         if( preset ){\r
170                                 if( bgms[ name ] ){\r
171                                         if( name !== X_Audio_Sprite_TEMP.bgmName ){\r
172                                                 // bgm変更\r
173                                                 X_Audio_Sprite_TEMP.bgmName     = name;\r
174                                                 X_Audio_Sprite_TEMP.bgmPosition = preset[ 0 ];\r
175                                                 X_Audio_Sprite_TEMP.bgmPlaying  = true;\r
176                                                 X_Audio_Sprite_TEMP.bgmLooped   = false;\r
177                                         };\r
178                                         if( bgm ){\r
179                                                 track = bgm;\r
180                                         } else\r
181                                         if( 1 < tracks.length ){\r
182                                                 track = X_Audio_Sprite_TEMP.bgmTrack = X_Audio_Sprite_getTrackEnded();\r
183                                         } else {\r
184                                                 track = X_Audio_Sprite_TEMP.bgmTrack = tracks[ 0 ];\r
185                                         };\r
186                                         track\r
187                                                 .state( { looped : X_Audio_Sprite_TEMP.bgmLooped } )\r
188                                                 .play( preset[ 0 ], preset[ 1 ], true, preset[ 3 ], preset[ 4 ] )\r
189                                                 .seek( X_Audio_Sprite_TEMP.bgmPosition )\r
190                                                 .listen( 'looped', this, X_Audio_Sprite_handleEvent );\r
191                                 } else {\r
192                                         if( 1 < tracks.length ){\r
193                                                 track = X_Audio_Sprite_getTrackEnded( X_Audio_Sprite_TEMP.bgmPlaying );\r
194                                                 track\r
195                                                         .listen( 'looped', this, X_Audio_Sprite_handleEvent )\r
196                                                         .state( { looped : false } )\r
197                                                         .play( preset[ 0 ], preset[ 1 ], true, 0, X_Audio_Sprite_lengthSilence );\r
198                                         } else {\r
199                                                 // single track, iOS\r
200                                                 if( bgm ){\r
201                                                         X_Audio_Sprite_TEMP.bgmPosition = bgm.currentTime();\r
202                                                         X_Audio_Sprite_TEMP.bgmTrack    = null;\r
203                                                 };\r
204                                                 track = tracks[ 0 ];\r
205                                                 track\r
206                                                         .listen( 'looped', this, X_Audio_Sprite_handleEvent )\r
207                                                         .state( { looped : false } )\r
208                                                         .play( preset[ 0 ], preset[ 1 ], true, 0, X_Audio_Sprite_lengthSilence );\r
209                                         };\r
210                                 };\r
211                                 return tracks.indexOf( track );\r
212                         };\r
213                         return -1;\r
214                 },\r
215                 \r
216                 pause : function( uid ){\r
217                         var track = X_Audio_Sprite_TEMP.tracks[ uid ];\r
218                         if( X_Audio_Sprite_TEMP.bgmTrack === track ){\r
219                                 X_Audio_Sprite_TEMP.bgmPosition = track.currentTime();\r
220                                 X_Audio_Sprite_TEMP.bgmPlaying  = false;\r
221                                 X_Audio_Sprite_TEMP.bgmTrack    = null;\r
222                         };\r
223                         console.log( 'pause' );\r
224                         track && track.play( 0, X_Audio_Sprite_lengthSilence, true, 0, X_Audio_Sprite_lengthSilence ).seek( 0 );\r
225                         return this;\r
226                 },\r
227                 \r
228                 seek : function( uid, position ){\r
229                         var track = X_Audio_Sprite_TEMP.tracks[ uid ],\r
230                                 end;\r
231                         if( track ){\r
232                                 delete track.seekTime;\r
233                                 end = X_AudioWrapper_getEndTime( track );\r
234                                 position <= end && X_AudioWrapper_getStartTime( track, end ) <= position && track.seek( postion );\r
235                         };\r
236                         return this;\r
237                 },\r
238                 \r
239                 volume : function( uid, opt_volume ){\r
240                         var track, i;\r
241                         // TODO uid = 0\r
242                         if( uid === 0 ){\r
243                                 if( opt_volume === undefined ){\r
244                                         return X_Audio_Sprite_TEMP.volume;\r
245                                 };\r
246                                 for( i = X_Audio_Sprite_TEMP.tracks.length; i; ){\r
247                                         X_Audio_Sprite_TEMP.tracks[ --i ].volume( opt_volume );\r
248                                 };\r
249                                 return this;\r
250                         };\r
251                         track = X_Audio_Sprite_TEMP.tracks[ uid ];\r
252                         if( opt_volume === undefined ){\r
253                                 return track ? track.volume() : -1;\r
254                         };\r
255                         track && track.volume( opt_volume );\r
256                         return this;\r
257                 },\r
258                 \r
259                 state : function( uid, opt_obj ){\r
260                         var track = X_Audio_Sprite_TEMP.tracks[ uid ];\r
261                         // TODO uid = 0\r
262                         if( opt_obj === undefined ){\r
263                                 return track ? track.state() : { volume : X_Audio_Sprite_TEMP.volume };\r
264                         };\r
265                         track && track.state( opt_obj );\r
266                         return this;\r
267                 }\r
268 };\r
269 \r
270 function X_Audio_Sprite_handleEvent( e ){\r
271         switch( e.type ){\r
272                 case 'backendfound' :\r
273                         this.asyncDispatch( e );\r
274                         e.target.unlisten( 'nobackend', this, X_Audio_Sprite_handleEvent );\r
275                         break;\r
276 \r
277                 case 'nobackend' :\r
278                         this.asyncDispatch( e );\r
279                         e.target.unlisten( 'backendfound', this, X_Audio_Sprite_handleEvent );\r
280                         break;\r
281                 \r
282                 case 'looped' :\r
283                         if( e.target === X_Audio_Sprite_TEMP.bgmTrack ){\r
284                                 X_Audio_Sprite_TEMP.bgmLooped = true;\r
285                         } else {\r
286                                 // single track | iOS\r
287                                 if( X_Audio_Sprite_TEMP.bgmPlaying && !X_Audio_Sprite_TEMP.bgmTrack ){\r
288                                         X_Audio_Sprite_TEMP.bgmTrack = e.target;\r
289                                         this.play( X_Audio_Sprite_TEMP.bgmName );\r
290                                 };\r
291                         };\r
292                         break;\r
293                 \r
294                 case X.Event.KILL_INSTANCE :\r
295                         this.close();\r
296                         break;\r
297         };\r
298 };\r