Coverage report

  %line %branch
tsukuba_bunko.peko.canvas.stage.audio.SampledAudioClip
0% 
0% 

 1  
 /*
 2  
  * All Rights Reserved.
 3  
  * Copyright (C) 1999-2005 Tsukuba Bunko.
 4  
  *
 5  
  * Licensed under the BSD License ("the License"); you may not use
 6  
  * this file except in compliance with the License.
 7  
  * You may obtain a copy of the License at
 8  
  *
 9  
  *       http://www.tsukuba-bunko.org/licenses/LICENSE.txt
 10  
  *
 11  
  * Unless required by applicable law or agreed to in writing, software
 12  
  * distributed under the License is distributed on an "AS IS" BASIS,
 13  
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 14  
  * See the License for the specific language governing permissions and
 15  
  * limitations under the License.
 16  
  *
 17  
  * $Id: SampledAudioClip.java,v 1.3 2005/08/19 03:18:11 ppoi Exp $
 18  
  */
 19  
 package tsukuba_bunko.peko.canvas.stage.audio;
 20  
 
 21  
 import java.io.IOException;
 22  
 
 23  
 import java.net.URL;
 24  
 
 25  
 import javax.sound.sampled.AudioFormat;
 26  
 import javax.sound.sampled.AudioInputStream;
 27  
 import javax.sound.sampled.AudioSystem;
 28  
 import javax.sound.sampled.DataLine;
 29  
 import javax.sound.sampled.FloatControl;
 30  
 import javax.sound.sampled.LineUnavailableException;
 31  
 import javax.sound.sampled.SourceDataLine;
 32  
 import javax.sound.sampled.UnsupportedAudioFileException;
 33  
 
 34  
 import tsukuba_bunko.peko.Logger;
 35  
 import tsukuba_bunko.peko.canvas.stage.AudioClip;
 36  
 import tsukuba_bunko.peko.canvas.stage.AudioPlayer;
 37  
 
 38  
 
 39  
 /**
 40  
  * サウンドファイルを再生する機能を提供します。
 41  
  * @author	$Author: ppoi $
 42  
  * @version	$Revision: 1.3 $ $Date: 2005/08/19 03:18:11 $
 43  
  */
 44  0
 public class SampledAudioClip	extends AudioClip	{
 45  
 
 46  
 	/**
 47  
 	 * 出力フォーマット
 48  
 	 */
 49  0
 	private AudioFormat	_outputFormat = null;
 50  
 
 51  
 	/**
 52  
 	 * デコード済み再生データ取得用オーディオ入力ストリーム
 53  
 	 */
 54  0
 	private AudioInputStream	_inputStream = null;
 55  
 
 56  
 	/**
 57  
 	 * デコード前再生データ取得用オーディオ入力ストリーム
 58  
 	 */
 59  0
 	private AudioInputStream	_baseInputStream = null;
 60  
 
 61  
 	/**
 62  
 	 * 再生出力ライン
 63  
 	 */
 64  0
 	private SourceDataLine	_line = null;
 65  
 
 66  
 	/**
 67  
 	 * マスターゲインコントロール
 68  
 	 */
 69  0
 	private FloatControl	_masterGainControl = null;
 70  
 
 71  
 	/**
 72  
 	 * 再生用ワークスレッド
 73  
 	 */
 74  0
 	private Thread	_workThread = null;
 75  
 
 76  
 	/**
 77  
 	 * 再生フラグ
 78  
 	 */
 79  0
 	private boolean	_running = false;
 80  
 
 81  
 
 82  
 	/**
 83  
 	 * <code>Player</code> のインスタンスを生成します。
 84  
 	 * このコンストラクタで作成された Player インスタンスはループ再生しません。
 85  
 	 * @param	id	クリップ ID
 86  
 	 * @param	clipURL	サウンドファイルの URL
 87  
 	 */
 88  
 	public SampledAudioClip( String id, URL clipURL )
 89  
 	{
 90  0
 		super( id, clipURL );
 91  0
 	}
 92  
 
 93  
 
 94  
 	/**
 95  
 	 * サウンドファイルを再生します。
 96  
 	 * <p>サウンドファイルの再生は非同期に行われ,本メソッドの呼び出しはすぐに返ります。</p>
 97  
 	 * @throws	UnsupportedAudioFileException	サウンドファイルが未サポートのオーディオ形式の場合
 98  
 	 * @throws	IOException	再生中に I/O エラーが発生した場合
 99  
 	 */
 100  
 	public void play()
 101  
 	{
 102  0
 		if( _inputStream != null )	{
 103  0
 			return;
 104  
 		}
 105  
 
 106  
 		try {
 107  0
 			setSoundFile( getClipURL() );
 108  
 		}
 109  0
 		catch( UnsupportedAudioFileException uafe ) {
 110  
 			//TODO: ログメッセージ
 111  0
 			Logger.warn( "unsupported sound format.", uafe );
 112  
 		}
 113  0
 		catch( LineUnavailableException lue )	{
 114  
 			//TODO: ログメッセージ
 115  0
 			Logger.warn( "source dataLine is not available.", lue );
 116  
 		}
 117  0
 		catch( IOException ioe ) {
 118  
 			//TODO: ログメッセージ
 119  0
 			Logger.warn( "fail to load sound file.", ioe );
 120  0
 		}
 121  
 
 122  0
 		_workThread = new Thread()	{
 123  
 			public void run()
 124  
 			{
 125  
 				try	{
 126  
 					AudioInputStream	is = _inputStream;
 127  
 					SourceDataLine	line = _line;
 128  
 					byte[]	buffer = new byte[ 8192 ];
 129  
 					line.start();
 130  
 					int	readSize = 0;
 131  
 					while( _running )	{
 132  
 						readSize = is.read( buffer, 0, buffer.length );
 133  
 						if( _running )	{
 134  
 							if( readSize != -1 )	{
 135  
 								line.write( buffer, 0, readSize );
 136  
 							}
 137  
 							else if( isLoop() )	{
 138  
 								closeInput();
 139  
 								prepareInput();
 140  
 								is = _inputStream;
 141  
 							}
 142  
 							else	{
 143  
 								line.drain();
 144  
 								if( _running )	{
 145  
 									synchronized( SampledAudioClip.this )	{
 146  
 										if( _running )	{
 147  
 											playingFinished();
 148  
 										}
 149  
 									}
 150  
 								}
 151  
 								break;
 152  
 							}
 153  
 						}
 154  
 					}
 155  
 				}
 156  
 				catch( UnsupportedAudioFileException uafe ) {
 157  
 					//TODO: ログメッセージ
 158  
 					Logger.warn( "unsupported sound format.", uafe );
 159  
 				}
 160  
 				catch( IOException ioe ) {
 161  
 					//TODO: ログメッセージ
 162  
 					Logger.warn( "fail to load sound file.", ioe );
 163  
 				}
 164  
 				finally	{
 165  
 					closeInput();
 166  
 				}
 167  
 
 168  
 				synchronized( SampledAudioClip.this )	{
 169  
 					_workThread = null;
 170  
 					SampledAudioClip.this.notify();
 171  
 				}
 172  
 			}
 173  
 		};
 174  0
 		_running = true;
 175  0
 		_workThread.start();
 176  0
 	}
 177  
 
 178  
 	/**
 179  
 	 * サウンドファイルの再生を停止します。
 180  
 	 * <p>サウンドファイルが再生されていない場合,何も実行されません。</p>
 181  
 	 * @param	mode	停止モード
 182  
 	 */
 183  
 	public void stop( int mode )
 184  
 	{
 185  0
 		if( _workThread != null )	{
 186  0
 			synchronized( this )	{
 187  0
 				if( _workThread != null )	{
 188  0
 					playingFinished();
 189  0
 					if( mode == AudioPlayer.STOP_WITH_ASYNC_FADEOUT )	{
 190  0
 						new Thread()	{
 191  
 							public void run() {
 192  
 								fadeout();
 193  
 								_running = false;
 194  
 							}
 195  
 						}.start();
 196  0
 					}
 197  
 					else	{
 198  0
 						if( mode == AudioPlayer.STOP_WITH_SYNC_FADEOUT )	{
 199  0
 							fadeout();
 200  
 						}
 201  
 
 202  
 						try {
 203  0
 							_running = false;
 204  0
 							SampledAudioClip.this.wait();
 205  
 						}
 206  0
 						catch( InterruptedException e ) {
 207  
 							//ignore
 208  0
 						}
 209  
 					}
 210  
 				}
 211  0
 				_workThread = null;
 212  0
 			}
 213  
 		}
 214  0
 	}
 215  
 
 216  
 	/**
 217  
 	 * このプレイヤーを破棄します。
 218  
 	 */
 219  
 	public void dispose()
 220  
 	{
 221  0
 		stop( AudioPlayer.STOP_IMMEDIATELY );
 222  0
 		if( _line != null )	{
 223  0
 			_line.stop();
 224  0
 			_line.close();
 225  
 		}
 226  0
 		_line = null;
 227  0
 		_masterGainControl = null;
 228  0
 	}
 229  
 
 230  
 	/**
 231  
 	 * 再生音量を変更します。
 232  
 	 * <p>マスターゲインコントロールが有効でない場合,何も行われません。</p>
 233  
 	 */
 234  
 	public void setVolume( float level )
 235  
 	{
 236  0
 		if( _masterGainControl != null )	{
 237  
 			float	decibel;
 238  0
 			if( level < 0.02f )	{
 239  0
 				decibel = _masterGainControl.getMinimum();
 240  0
 			}
 241  
 			else	{
 242  0
 				decibel = (float)Math.log( (double)level ) * 20.0f;
 243  
 			}
 244  0
 			_masterGainControl.setValue( decibel );
 245  
 		}
 246  0
 	}
 247  
 
 248  
 	/**
 249  
 	 * 再生音量を取得します。
 250  
 	 * <p>マスターゲインコントロールが有効でない場合,-1f を返します。
 251  
 	 */
 252  
 	public float getVolume()
 253  
 	{
 254  0
 		if( _masterGainControl == null )	{
 255  0
 			return -1f;
 256  
 		}
 257  
 		else	{
 258  0
 			float	decibel = _masterGainControl.getValue();
 259  0
 			return (float)Math.pow( 10, (decibel / 20.0f) );
 260  
 		}
 261  
 	}
 262  
 
 263  
 	/**
 264  
 	 * 再生するサウンドファイルを設定し,オーディオシステムの初期化を行います。
 265  
 	 * @param	clipURL	サウンドファイルの URL
 266  
 	 * @throws	UnsupportedAudioFileException	サウンドファイルが未サポートのオーディオ形式の場合
 267  
 	 * @throws	LineUnavailableException	再生出力ラインが使用不能の場合
 268  
 	 * @throws	IOException	ファイルの解析中に I/O エラーが発生した場合
 269  
 	 */
 270  
 	private void setSoundFile( URL clipURL )
 271  
 		throws UnsupportedAudioFileException, LineUnavailableException, IOException
 272  
 	{
 273  0
 		prepareInput();
 274  
 
 275  0
 		DataLine.Info	info = new DataLine.Info( SourceDataLine.class, _outputFormat );
 276  0
 		SourceDataLine	line = (SourceDataLine)AudioSystem.getLine( info );
 277  0
 		line.open( _outputFormat );
 278  0
 		_line = line;
 279  
 
 280  
 		try	{
 281  0
 			_masterGainControl = (FloatControl)line.getControl( FloatControl.Type.MASTER_GAIN );
 282  
 		}
 283  0
 		catch( IllegalArgumentException iae )	{
 284  
 			//TODO: ログメッセージ
 285  0
 			Logger.warn( "Master Gain Control is not supported.", iae );
 286  0
 		}
 287  0
 	}
 288  
 
 289  
 	/**
 290  
 	 * 再生するサウンドファイルを初期化します。
 291  
 	 * @throws	UnsupportedAudioFileException	サウンドファイルが未サポートのオーディオ形式の場合
 292  
 	 * @throws	IOException	解析中に I/O エラーが発生した場合
 293  
 	 */
 294  
 	private void prepareInput()
 295  
 		throws UnsupportedAudioFileException, IOException
 296  
 	{
 297  0
 		AudioInputStream	baseInputStream = AudioSystem.getAudioInputStream( getClipURL() );
 298  0
 		AudioFormat	baseFormat = baseInputStream.getFormat();
 299  0
 		AudioFormat.Encoding	baseEncoding = baseFormat.getEncoding();
 300  0
 		Logger.debug( "file=" + getClipURL() + " fomart=" + baseFormat + " encoding=" + baseEncoding + "[" + baseEncoding.getClass() + "]" );
 301  
 
 302  0
 		if( AudioFormat.Encoding.class.equals(baseEncoding.getClass()) )	{
 303  0
 			_outputFormat = baseFormat;
 304  0
 			_inputStream = baseInputStream;
 305  0
 			_baseInputStream = null;
 306  0
 		}
 307  
 		else	{
 308  0
 			_outputFormat = new AudioFormat( AudioFormat.Encoding.PCM_SIGNED, baseFormat.getSampleRate(), 16, baseFormat.getChannels(),
 309  
 					baseFormat.getChannels() * 2, baseFormat.getSampleRate(), false );
 310  0
 			Logger.debug( "decoded: " + _outputFormat );
 311  0
 			_inputStream = AudioSystem.getAudioInputStream( _outputFormat, baseInputStream );
 312  0
 			_baseInputStream = baseInputStream;
 313  
 		}
 314  0
 	}
 315  
 
 316  
 	/**
 317  
 	 * サウンドファイルをクローズします。
 318  
 	 */
 319  
 	private void closeInput()
 320  
 	{
 321  0
 		if( _inputStream != null )	{
 322  
 			try	{
 323  0
 				_inputStream.close();
 324  
 			}
 325  0
 			catch( IOException ioe )	{
 326  
 				//ignore
 327  0
 			}
 328  
 		}
 329  0
 		if( _baseInputStream != null )	{
 330  
 			try	{
 331  0
 				_baseInputStream.close();
 332  
 			}
 333  0
 			catch( IOException ioe )	{
 334  
 				//ignore
 335  0
 			}
 336  
 		}
 337  0
 		_inputStream = null;
 338  0
 		_baseInputStream = null;
 339  0
 		_outputFormat = null;
 340  0
 	}
 341  
 
 342  
 	/**
 343  
 	 * フェードアウトします。
 344  
 	 */
 345  
 	private void fadeout()
 346  
 	{
 347  0
 		synchronized( SampledAudioClip.this )	{
 348  0
 			if( _masterGainControl != null )	{
 349  0
 				float	level = getVolume();
 350  0
 				for( ;  level > 0.03f; level = level * 0.97f )	{//桁をそろえるにはどうすればよい?
 351  
 					try	{
 352  0
 						SampledAudioClip.this.wait( 2L );
 353  
 					}
 354  0
 					catch( InterruptedException ie 	)	{
 355  0
 					}
 356  0
 					setVolume( level );
 357  
 				}
 358  0
 				_masterGainControl.setValue( _masterGainControl.getMinimum() );
 359  
 			}
 360  0
 		}
 361  0
 	}
 362  
 }

This report is generated by jcoverage, Maven and Maven JCoverage Plugin.