Package jm.audio.synth

Source Code of jm.audio.synth.WaveTable

/*



<This Java Class is part of the jMusic API version 1.5, March 2004.>



Copyright (C) 2000 Andrew Sorensen & Andrew Brown



This program is free software; you can redistribute it and/or modify

it under the terms of the GNU General Public License as published by

the Free Software Foundation; either version 2 of the License, or any

later version.



This program is distributed in the hope that it will be useful, but

WITHOUT ANY WARRANTY; without even the implied warranty of

MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the

GNU General Public License for more details.



You should have received a copy of the GNU General Public License

along with this program; if not, write to the Free Software

Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.



*/



package jm.audio.synth;



import jm.audio.AOException;

import jm.audio.AudioObject;

import jm.audio.Instrument;



/**

* Wavetable lookup creates an efficient means for resampling data

* into any frequency. It is particularly useful for holding simple

* wave information such as sinewaves and is often used as an

* oscillator.<br>

* This WaveTable implementation can accept either one or two inputs.  Two

* inputs expects that amplitude is the left input and frequency is the right

* input. One input allows the user to specify whether the input is for

* amplitude or frequency by setting the aoDestination variable((0)amplitude

* (1)frequency.<br>

* A WaveTable can use fixed variables for both amplitude and frequency.  The

* default is to use a default amplitude of 1.0 and a frequency based upon the

* value of the build methods Note.pitch(). These fixed variables are

* amp(amplitude) and frq(frequency) and both have set methods. NOTE (please do

* not add more constructors to set amp and frq but leave them as set

* methods).<br>

* The frqRatio variable is used to produce a frequency which is a ratio

* against the current notesFrq (the build methods note.getFrequency()) variable

* setting.<br>

* It is common to use WaveTables as oscillators and even more common for these

* oscillators to based on simple wave forms.  Simple wave forms in jMusic can

* be retrieved using static method calls to the Oscillator class.<br>

*

* @author Andrew Sorensen

* @version 1.0,Sun Feb 25 18:42:52  2001

*/

public class WaveTable extends AudioObject{

  //----------------------------------------------

  // Attributes

  //----------------------------------------------

  /** this contains the wavetable data as samples */

  private float[] waveTable;

  /** how many samples to we skip while passing through the wavetable */

  private float si;

  /** what is the phase of the wavetable to start at */

  private float phase;

  /** If we have one audio object input is at amp(0) or freq(1) ? */

  private int aoDestination;

  /** Value to use as a fixed amplitude for the waveTable.*/

  private float amp = (float) 1.0;

  /** Value to use as a fixed frequency for the waveTable.*/

  private float frq = (float)-1.0;

  /** Frequency ratio allows an incoming note's pitch to be adjusted to a

    * fixed ratio amount*/

  private float frqRatio = (float)1.0;

        /** constant for use with aoDestination */

        public static final int AMPLITUDE = 0;

        /** constant for use with aoDestination */

        public static final int FREQUENCY = 1;

        /** constant for use with channels */

        public static final int MONO = 1;

        /** constant for use with channels */

        public static final int STEREO = 2;

  //----------------------------------------------

  // Constructors

  //----------------------------------------------

  /**

   * This constructor sets the WaveTable to act as

   * a processor object taking in two inputs. Input

    * one is defined as amplitude and input two is

    * defined as frequency.

   * @param ao AudioObject as input

   * @param waveTable the lookup table data

   * @exception AOException thrown when two many inputs are attached

   */

  public WaveTable(AudioObject[] ao, float[] waveTable)throws AOException{

    super(ao, "[WaveTable]");

    if(ao.length > 2) throw new AOException(this.name,1);

    this.waveTable = waveTable;

  }



  /**

    * This constructor sets the WaveTable to act as

   * a processor object taking in one input. That

   * input can be either amplitude(0) or frequency(1)

   * and is defined by the aoDestination variable (int).

         * @param ao the one input audio object

   * @param wavetable the wave table data

    * @param aoDestination Is this input amplitude(0) or frequency(1)

   */

  public WaveTable(AudioObject ao, float[] waveTable, int aoDestination){

    super(ao, "[WaveTable]");

    this.waveTable = waveTable;

    this.aoDestination = aoDestination;

  }



  /**

    * This constructor sets the WaveTable to act as

   * a generator object taking in one input. That

   * input can be either amplitude(0) or frequency(1)

   * and is defined by the aoDestination variable (int).

   * @param inst the parent instrument (usually "this")

   * @param wavetable the wave table data

    * @param aoDestination Is this input amplitude(0) or frequency(1)

   * @param val is used to set a fixed frequency or amplitude based on the

   * result of aoDestination (aoDestination=1 for example will set a fixed frequency)

   */

  public WaveTable(Instrument inst, int sampleRate, float[] waveTable,

            int channels, int aoDestination, float val){

    super(inst, sampleRate, "[WaveTable]");

    this.waveTable = waveTable;

                this.channels = channels;

    this.aoDestination = aoDestination;

    if(aoDestination == 1){

      this.frq=val;

    }else{

      this.amp=val;

    }

  }



  /**

   * This constructor sets this wavetable up as a generator

   * object meaning that it will pass sample information

   * down the chain based on its wave table data.<br>

   * Set WaveTable with some initial values including

   * the sampling rate and the samples to use for this

   * wave table

   * @param inst the parent instrument (usually "this")

   * @param sampleRate the sampling rate

   * @param waveTable the wave table data

   * @param channels the number of channels to use

   */

  public WaveTable(Instrument inst, int sampleRate, float[] waveTable,

        int channels){

    super(inst, sampleRate, "[WaveTable]");

    this.waveTable = waveTable;

    this.channels = channels;

  }   



  //----------------------------------------------

  // Methods

  //----------------------------------------------

  /**

   * Moves through the WaveTable array (noramally forwards but sometimes

   * backwards) by increments set by si (sample increment value).  This nextWork

   * method can take one or two inputs which are either amplitude, frequency

   * or both (a single input can be assigned to either frequency or amplitude

   * by assigning the aoDestination value to either (0)Amp or (1)Frq in the

   * appropriate constructor.  A WaveTable that takes two inputs expects the

   * first input to be amplitude and the second input to be frequency.

   * @param buffer The sample buffer.

   */

  public int work(float[] buffer)throws AOException{

    //because wavetable contains mono sample data we need to pass the same

    //sample information to as many channels as are present.

    int buffneed=buffer.length/channels;

    int ret=0; //the number of samples to return



    if(inputs==2){ //Amp and Freq

      float[] ampbuf = new float[buffneed];

      int returned = this.previous[0].nextWork(ampbuf);

      float[] freqbuf = new float[returned];

      if(returned != this.previous[1].work(freqbuf)){

        throw new AOException(this.name,0);

      }

      for(int i=0;ret<buffer.length;i++){

        setSI((int)freqbuf[i]);

        if(phase < 0){

          phase = this.waveTable.length+phase;

        } // amplitude values assumed to be between -1 and 1

        float sample = waveTable[(int)phase]*(this.amp * ampbuf[i]);

        this.phase += si;

        if(phase >= this.waveTable.length){

          phase -= this.waveTable.length;

        }

        for(int j=0;j<channels;j++){

          buffer[ret++] = sample;

        }

      }

    }else if(inputs==1 && aoDestination==0){ //Amp only

      float[] ampbuf = new float[buffneed];

      int returned = this.previous[0].nextWork(ampbuf);

      for(int i=0;ret<buffer.length;i++){

        float sample = waveTable[(int)phase]*(this.amp * ampbuf[i]);

        this.phase += si;

        if(phase >= this.waveTable.length){

          phase -= this.waveTable.length;

        }

        for(int j=0;j<channels;j++){

          buffer[ret++] = sample;

        }

      }

    }else if(inputs==1 && aoDestination==1){ //Frq only

      float[] frqbuf = new float[buffneed];

      int returned = this.previous[0].work(frqbuf);

      for(int i=0;i<buffneed;i++){

        setSI((int)frqbuf[i]);

        if(phase < 0){

          phase = this.waveTable.length+phase;

        }

        float sample = waveTable[(int)phase]*this.amp;

        this.phase += si;

        if(phase >= this.waveTable.length){

          phase -= this.waveTable.length;

        }

        for(int j=0;j<channels;j++){

          buffer[ret++] = sample;

        }

      }

    }else{ //no inputs

      for(;ret<buffer.length;){

        float sample = waveTable[(int)phase]*this.amp;     

        this.phase += si;

        if(phase >= this.waveTable.length){

          phase -= this.waveTable.length;

        }

        for(int j=0;j<channels;j++){

          try{

            buffer[ret++] = sample;

          }catch(ArrayIndexOutOfBoundsException e){

            //This can happen if a non mono signal chain wants

            //to access the wavetable as a mono signal

            //Ignore and skip over

            //

            //We do need to remove one back off ret though to return

            //the right number of samples to return

            ret--;

          }

        }

      }

    }

    return ret;

  }



  /**

   */

  public void build(){

    float notesFrq = (float)currentNote.getFrequency() * frqRatio;

    if(this.frq<(float)0.0){

      this.setSI(notesFrq);  

    }else{

      this.setSI(this.frq);

   

  }



  /**

   * Set the fixed amp of this wavetable

   * @param amp Fixed value amplitude

   */

  public void setAmp(float amp){

    this.amp = amp;

  }



  /**

   * Set the fixed Frequecy of this wavetable

   * @param frq Fixed value frequency

   */

  public void setFrq(float frq){

    this.frq = frq;

  }



  /**

   * Sets the frequency ratio to alter a notes pitch by

   * @param frqRatio Fixed ratio value to change frequency by

   */

  public void setFrqRatio(float frqRatio){

    this.frqRatio = frqRatio;

  }



  //------------------------------------------

  // Protected Methods

  //------------------------------------------

  /**

   * Returns the sampling increment which is used

   * to nextWork out how many samples in the wavetable

   * skip on each pass.

   * @param frequency the frequency used to find si

   */

  protected void setSI(float frequency){

      this.si = (frequency / (float)this.sampleRate) * (float)this.waveTable.length;

  }

}
 
TOP

Related Classes of jm.audio.synth.WaveTable

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.