/* $Id$
 *
 * Copyright (c) 1999 Xenonsoft Limited. All Rights Reserved.
 *
 * This software is protected by copyright. You are hereby notified from
 * now by reading this message. This software is also the confidential 
 * and proprietary information of Xenonsoft Limited.  ("Confidential
 * Information"). 
 *
 * This software is distributed under the Xenonsoft Public end user 
 * License ("XPeL"), where the machine-readable source code is provided 
 * under the "Open Source" model.
 * For more information, please read the file "LICENSE-XPL.txt" 
 */

// Envelope.java

//
// Description:
//	  Sound Envelope - A D S R
//	  
// Author:
//	  Peter Pilgrim
//	  
// RCS HEADER 
// 
// $Author$
// $Date$
// $Source$
// $Revision$    $State$    $Locker$
//
// ================================================================================
// History
//	  $Log$
// 
// 
//


package xenon.soundkit;

/**
 * A object that captures the envelope data for sound synthesis
 *
 * The envelope class works int conjunction with the
 * <b>SoundEngine</b> to produce the sound.
 *
 *
 * The envelope class has 3 points to modulate the frequency during
 * synthesis and it has the usual suspects to manipulate the amplitude
 * during synthesis <b>attack</b>, <b>decay</b>, <b>sustain</b>, and
 * <b>release</b>.
 *
 *
 * Those of you who are old enough to remember the home computer boom
 * of the mid 1980's may have pleasent memories of the <b>BBC
 * Microcomputer</b>, which manufactured by British company
 * <b>Acorn</b> based Cambridge, England. This popular home computer
 * had to extended basic command SOUND and ENVELOPE. These reserved
 * words generated some fantastic sounds at the time. The SoundEngine
 * sort of emulates the SOUND statement and the corresponding Envelope
 * class emulates the ENVELOPE statement. Note it was never my
 * intention to complete emulate the BBC Sound Chip, however I
 * remembered the beloved simplicity and elegance of the clever
 * design. I thought wouldn't just be great it Java had such applied
 * sound generating facility. 
 *
 * More docu required.
 *
 *
 * @author Peter Pilgrim Thu Jun 17 23:37:02 BST 1999
 * @version $Id$ 
 *
 * 
 */
public class Envelope {

    /** minimum pitch step unit */
    public final static int MIN_PSU=1;
    /** maximum pitch step unit */
    public final static int MAX_PSU=256;
    /** minimum amplitude step unit */
    public final static int MIN_ASU=1;
    /** maximum amplitude step unit */
    public final static int MAX_ASU=256;

    /** minimum pitch delta */
    public final static int PITCH_MIN_DELTA=-256;
    /** maximum pitch delta*/
    public final static int PITCH_MAX_DELTA=256;
    /** minimum pitch step unit */
    public final static int PITCH_MIN_STEP=0;
    /** maximum pitch step unit */
    public final static int PITCH_MAX_STEP=256;

    /** minimum attack delta */
    public final static int ATTACK_MIN_DELTA=0;
    /** maximum attack delta */
    public final static int ATTACK_MAX_DELTA=128;
    /** minimum attack step */
    public final static int ATTACK_MIN_STEP=0;
    /** maximum attack step */
    public final static int ATTACK_MAX_STEP=256;
    
    /** minimum decay delta */
    public final static int DECAY_MIN_DELTA=-128;
    /** maximum decay delta */
    public final static int DECAY_MAX_DELTA=128;
    /** minimum decay step */
    public final static int DECAY_MIN_STEP=0;
    /** maximum decay step */
    public final static int DECAY_MAX_STEP=256;
    
    /** minimum sustain delta */
    public final static int SUSTAIN_MIN_DELTA=-128;
    /** maximum sustain delta */
    public final static int SUSTAIN_MAX_DELTA=128;
    /** minimum sustain step */
    public final static int SUSTAIN_MIN_STEP=0;
    /** maximum sustain step */
    public final static int SUSTAIN_MAX_STEP=256;
    
    /** minimum release delta */
    public final static int RELEASE_MIN_DELTA=-128;
    /** maximum release delta */
    public final static int RELEASE_MAX_DELTA=0;
    /** minimum release step */
    public final static int RELEASE_MIN_STEP=0;
    /** maximum release step */
    public final static int RELEASE_MAX_STEP=256;
    

    protected int	pitch_step_unit = 1;
    protected int []	pitch_delta;
    protected int []	pitch_step;
    protected int	amplitude_step_unit = 1;
    protected int	attack_delta, attack_step;
    protected int	decay_delta, decay_step;
    protected int	sustain_delta, sustain_step;
    protected int	release_delta, release_step;
    
    /**
     * 
     * Creates a default envelope which is functionally equivalent to
     * the following code:
     *
     * <pre>
     * new Envelope( 1,  0,256, 0,256, 0, 256,   
     *		     1,  128,1, 0,128, 0,128, -128,1 );
     * </pre> 
     *
     *
     */
    public Envelope()
    {
	this( 1,  0,256, 0,256, 0, 256,   
	      1,  128,1, 0,128, 0,128, -128,1 );
    }
    
    /**
     * creates an envelope for sound synthesis
     *
     * @param pitch_step_unit
     *
     * @param amplitude_step_unit
     *
     */
    public Envelope( int pitch_step_unit, 
		     int pi1, int pn1, int pi2, int pn2, int pi3, int pn3,
		     int amplitude_step_unit , 
		     int ad, int an, int dd, int dn, int sd, int sn, int rd, int rn ) 
    {
	pitch_delta = new int[3];
	pitch_step  = new int[3];

	// pitch envelope change, and step
	this.pitch_step_unit = pitch_step_unit;	
	pitch_delta[0] = pi1;
	pitch_step[0]  = pn1;
	pitch_delta[1] = pi2;
	pitch_step[1]  = pn2;
	pitch_delta[2] = pi3;
	pitch_step[2]  = pn3;
	
	this.amplitude_step_unit = amplitude_step_unit;
	attack_delta = ad;
	attack_step  = an;
	decay_delta = dd;
	decay_step  = dn;
	sustain_delta = sd;
	sustain_step  = sn;
	release_delta = rd;
	release_step  = rn;

	checkParameters();
    }

    /** checks the parameters
     * @return <code>IllegalArgumentException</code>
     * if any of the parameters are not within limit
     */
    protected void checkParameters()
    {
	if ( pitch_step_unit < MIN_PSU ||
	     pitch_step_unit > MAX_PSU )
	    throw new IllegalArgumentException( 
		"pitch step unit "+pitch_step_unit+
		" out of range ["+MIN_ASU+","+MAX_ASU+"]" );

	for ( int j=0; j<3; ++j ) {
	    if ( pitch_delta[j] < PITCH_MIN_DELTA ||
		 pitch_delta[j] > PITCH_MAX_DELTA )
		throw new IllegalArgumentException( 
		    "pitch delta["+j+"] :"+pitch_delta[j]+
		    " out of range ["+PITCH_MIN_DELTA+","+PITCH_MAX_DELTA+"]");
	    if ( pitch_step[j] < PITCH_MIN_STEP ||
		 pitch_step[j] > PITCH_MAX_STEP )
		throw new IllegalArgumentException( 
		    "pitch step["+j+"] :"+pitch_step[j]+
		    " out of range ["+PITCH_MIN_STEP+","+PITCH_MAX_STEP+"]");
	}
	
	if ( amplitude_step_unit < MIN_ASU ||
	     amplitude_step_unit > MAX_ASU )
		throw new IllegalArgumentException( 
		    "amplitude step unit "+amplitude_step_unit+
		    " out of range ["+MIN_ASU+","+MAX_ASU+"]" );


	if ( attack_delta < ATTACK_MIN_DELTA ||
	     attack_delta > ATTACK_MAX_DELTA )
		throw new IllegalArgumentException( 
		    "attack delta "+attack_delta+
		    " out of range ["+ATTACK_MIN_DELTA+","+ATTACK_MAX_DELTA+"]" );
	if ( attack_step < ATTACK_MIN_STEP ||
	     attack_step > ATTACK_MAX_STEP )
		throw new IllegalArgumentException( 
		    "attack step "+attack_step+
		    " out of range ["+ATTACK_MIN_STEP+","+ATTACK_MAX_STEP+"]" );



	if ( decay_delta < DECAY_MIN_DELTA ||
	     decay_delta > DECAY_MAX_DELTA )
		throw new IllegalArgumentException( 
		    "decay delta "+decay_delta+
		    " out of range ["+DECAY_MIN_DELTA+","+DECAY_MAX_DELTA+"]" );
	if ( decay_step < DECAY_MIN_STEP ||
	     decay_step > DECAY_MAX_STEP )
		throw new IllegalArgumentException( 
		    "decay step "+decay_step+
		    " out of range ["+DECAY_MIN_STEP+","+DECAY_MAX_STEP+"]" );


	if ( sustain_delta < SUSTAIN_MIN_DELTA ||
	     sustain_delta > SUSTAIN_MAX_DELTA )
		throw new IllegalArgumentException( 
		    "sustain delta "+sustain_delta+
		    " out of range ["+SUSTAIN_MIN_DELTA+","+SUSTAIN_MAX_DELTA+"]" );
	if ( sustain_step < SUSTAIN_MIN_STEP ||
	     sustain_step > SUSTAIN_MAX_STEP )
		throw new IllegalArgumentException( 
		    "sustain step "+sustain_step+
		    " out of range ["+SUSTAIN_MIN_STEP+","+SUSTAIN_MAX_STEP+"]" );


	if ( release_delta < RELEASE_MIN_DELTA ||
	     release_delta > RELEASE_MAX_DELTA )
		throw new IllegalArgumentException( 
		    "release delta "+release_delta+
		    " out of range ["+RELEASE_MIN_DELTA+","+RELEASE_MAX_DELTA+"]" );
	if ( release_step < RELEASE_MIN_STEP ||
	     release_step > RELEASE_MAX_STEP )
		throw new IllegalArgumentException( 
		    "release step "+release_step+
		    " out of range ["+RELEASE_MIN_STEP+","+RELEASE_MAX_STEP+"]" );


    }
    
}

// fini
