All Downloads are FREE. Search and download functionalities are using the official Maven repository.

jm.audio.synth.WaveTable Maven / Gradle / Ivy

The newest version!
/*







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.
*

* 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.
*

* 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).
*

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

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

* setting.
*

* 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.
* * @author Andrew Sorensen * @version 1.0, Sun Feb 25 18:42:52 2001 */ public class WaveTable extends AudioObject { //---------------------------------------------- // Attributes //---------------------------------------------- /** * 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; /** * 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; //---------------------------------------------- // 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 * @throws 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.
*

* 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; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy