+ case 'loop' :\r
+ if( X.Type.isBoolean( v ) && audioWrapper[ k ] !== v ){\r
+ audioWrapper[ k ] = v;\r
+ };\r
+ break;\r
+\r
+ case 'volume' :\r
+ if( X.Type.isNumber( v ) ){\r
+ v = v < 0 ? 0 : 1 < v ? 1 : v;\r
+ if( audioWrapper[ k ] !== v ){\r
+ audioWrapper[ k ] = v;\r
+ // if playing -> update\r
+ if( playing ) volume = 4;\r
+ };\r
+ };\r
+ break;\r
+ };\r
+ };\r
+ \r
+ if( audioWrapper.endTime <= audioWrapper.startTime ||\r
+ audioWrapper.endTime <= audioWrapper.loopStartTime ||\r
+ audioWrapper.endTime < 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
+ };\r
+ \r
+ return end + seek + volume;\r
+};\r
+\r
+function X_AudioWrapper_timeStringToNumber( time ){\r
+ var ary, ms, s = 0, m = 0, h = 0;\r
+ if( X.Type.isNumber( time ) ) return time;\r
+ if( !X.Type.isString( time ) || !time.length ) return;\r
+\r
+ ary = time.split( '.' );\r
+ ms = parseInt( ( ary[ 1 ] + '000' ).substr( 0, 3 ) ) || 0;\r
+ \r
+ ary = ary[ 0 ].split( ':' );\r
+ if( 3 < ary.length ) return;\r
+ \r
+ switch( ary.length ){\r
+ case 0 :\r
+ break;\r
+ case 1 :\r
+ s = parseInt( ary[ 0 ] ) || 0;\r
+ break;\r
+ case 2 :\r
+ m = parseInt( ary[ 0 ] ) || 0;\r
+ s = parseInt( ary[ 1 ] ) || 0;\r
+ if( 60 <= s ) alert( 'invalid time string ' + time );\r
+ break;\r
+ case 3 :\r
+ h = parseInt( ary[ 0 ] ) || 0;\r
+ m = parseInt( ary[ 1 ] ) || 0;\r
+ s = parseInt( ary[ 2 ] ) || 0;\r
+ if( 60 <= s ) alert( 'invalid time string ' + time );\r
+ if( 60 <= m ) alert( 'invalid time string ' + time );\r
+ break;\r
+ default :\r
+ alert( 'invalid time string ' + time );\r
+ };\r
+ ms = ( h * 3600 + m * 60 + s ) * 1000 + ms;\r
+ return ms < 0 ? 0 : ms;\r
+};\r