/*
 * "Peko" Visual Novel System
 *
 * All Rights Reserved.
 * Copyright (c) 1999-2003 Tsukuba Bunko.
 *
 * $Id: SampledAudioClip.java,v 1.1.2.1 2003/12/11 10:23:10 ppoi Exp $
 */
package tsukuba_bunko.peko.canvas.stage.audio;

import	java.net.URL;

import	javax.sound.sampled.AudioInputStream;
import	javax.sound.sampled.AudioSystem;
import	javax.sound.sampled.DataLine;
import	javax.sound.sampled.FloatControl;
import	javax.sound.sampled.SourceDataLine;

import	tsukuba_bunko.peko.Logger;

import	tsukuba_bunko.peko.canvas.stage.AudioClip;


/**
 * サンプル形式データの音楽クリップです。
 * @author	$Author: ppoi $
 * @version	$Revision: 1.1.2.1 $
 */
public class SampledAudioClip	extends AudioClip	implements Runnable	{

	/**
	 * buffer size
	 */
	private int	_bufferSize = 65536;

	/**
	 * 再生スレッド
	 */
	private Thread	_thread = null;

	/**
	 * running flag
	 */
	private boolean	_running = false;

	/**
	 * データ入力ストリーム
	 */
	private AudioInputStream	_is = null;

	/**
	 * 音量コントローラ
	 */
	private FloatControl	_gainControl = null;


	/**
	 * <code>SampledAudioClip</code> のインスタンスを作成します。
	 * @param	id	クリップ ID
	 * @param	clipURL	クリップの URL
	 */
	public SampledAudioClip( String id, URL clipURL )
	{
		super( id, clipURL );
	}


//
//	AudioClip の実装
//
	public void play()
	{
		if( _thread != null )	{
			return;
		}

		try	{
			_is = AudioSystem.getAudioInputStream( getClipURL() );
		}
		catch( Exception e )	{
			e.printStackTrace();
		}

		_thread = new Thread( this );
		_thread.start();
	}

	public void stop()
	{
		Logger.debug( "[canvas.audio] stop audio clip :" + getID() );
		if( _gainControl != null )	{
			_gainControl.setValue( _gainControl.getMinimum() );
		}
		_running = false;
		_thread = null;
		_is = null;
	}


//
//	Runnable の実装
//
	public void run()
	{
		if( _is == null )	{
			return;
		}

		SourceDataLine	line = null;
		AudioInputStream	is = _is;
		Logger.debug( "[canvas.audio] clip frame size :" + is.getFrameLength() );

		byte[]	buffer = new byte[_bufferSize];
		int	readed = -1;
		try	{
			line = (SourceDataLine)AudioSystem.getLine( new DataLine.Info(SourceDataLine.class, is.getFormat()) );
			line.open( is.getFormat(), _bufferSize );
			FloatControl	ctl = (FloatControl)line.getControl( FloatControl.Type.MASTER_GAIN );
/*			if( ctl != null )	{
				ctl.setValue( ctl.getMaximum() * 0.3f );
				Logger.debug( "[canvas.audio] gain: " + ctl.getValue() + "/" + ctl.getMaximum() );
			}*/
			_gainControl = ctl;
			line.start();
			_running = true;
			int	avaliable = 0;
honya:		while( (is != null) && _running )	{
				readed = is.read( buffer, 0, _bufferSize );
				if( !_running )	{
					break honya;
				}
				else if( readed == -1 )	{
					is.close();
					if( isLoop() )	{
						is = AudioSystem.getAudioInputStream( getClipURL() );
						continue;
					}
					else	{
						break honya;
					}
				}
				line.write( buffer, 0, readed );
			}
			is.close();
		}
		catch( Exception e )	{
			Logger.error( "[canvas.audio] fatal error occured during play sampled audio clip.", e );
		}
		finally	{
			if( line != null )	{
				if( _running )	{
					line.drain();
				}
				line.stop();
				line.flush();
				line.close();
				line = null;
				buffer = null;
			}
		}
		_running = false;
		_thread = null;
		_is = null;
		Logger.debug( "[canvas.audio] playing data \"" + getClipURL() + "\" was finished." );
		playingFinished();
	}
}
