jm.audio.AudioObject Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jmusic Show documentation
Show all versions of jmusic Show documentation
JMusic - Java Music Library
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;
import jm.music.data.Note;
/**
* Audio Object is the super class of all audio reading, writing, processing
* and generating units. An AudioObject in the jMusic audio architecture
* is any class which is used to form part of an audio chain, be that a
* generator object (such as a wavetable), a reader object (such as an audio
* file reader), a processor object (such as a filter), or a writer object (
* such as a file writer).
* Audio chains are created by linking together AudioObjects into lists
* where every AudioObject knows which AudioObjects come before and after it.
* This link is achieved by passing an AudioObjects immediate predicesors in
* to its constructor as an array of AudioObjects. The number of inputs
* accepted by an AudioObject is a direct relation to the size of the
* AudioObject array passed to an AudioObject's constructor. AudioObjects also
* know who their successor is so that information (such as sample rate)
* can be deceminated from the top to the bottom of the audio chain.
*
* The chain works using a pull mechanism where the final AudioObject
* (defined in an Instrument object as the finalAO object) requests a
* number of samples from it's previous AudioObject(s). This request is then
* passed on up the chain until the requested number of samples is retrieved
* from each chains first AudioObject (defined in an Instrument as an array of
* primaryAO objects). These requests for samples are made by passing
* a float[] to each AudioObjects work() method and requesting that it fill the
* float[] with sample data (if it is a primary AudioObject) or process that
* float[] in some manner.
*
* @author Andrew Sorensen
* @version 1.0, Sun Feb 25 18:42:44 2001
*/
public abstract class AudioObject implements jm.JMC {
//----------------------------------------------
// Attributes
//----------------------------------------------
/**
* the AudioObject previous to this one
*/
protected AudioObject[] previous;
/**
* the AudioObject following to this one
*/
protected AudioObject[] next;
/**
* The name of this Audio Object.
*/
protected String name;
/**
* This audio objects sampling rate
*/
protected int sampleRate;
/**
* The number of audio channels for this audio object.
*/
protected int channels;
/**
* how many inputs are attached to this object
*/
protected int inputs = 0;
/**
* the note currently being rendered
*/
protected Note currentNote = null;
/**
* the currentNotes startTime
*/
protected double currentNoteStartTime;
/**
* the number of samples which need to be processed for this note
* to be rendered (in mono, for stereo multiply by 2 etc.)
*/
protected int numOfSamples = 0;
/**
* The Instrument which currently implements this AudioObject
*/
protected Instrument inst = null;
/* Is this audio object finished */
protected boolean finished = true;
/* Local buffer counter */
private int returned;
//----------------------------------------------
// Constructors
//----------------------------------------------
/**
* This constructor is used for all audio processors and writers
* that need to accept input from a single stream (ie Audio Object).
*
* @param previous The AudioObject previous to this one
* @param name A name to associate with this Audio Object
*/
protected AudioObject(AudioObject previous, String name) {
AudioObject[] tmp = {previous};
this.name = name;
this.previous = tmp;
this.previous[0].setNext(this);
this.inputs = 1;
}
/**
* This constructor is used for all audio processors and writers
* that need to accept input from multiple streams (ie Audio Objects).
*
* @param previous The AudioObjects previous to this one
* @param name A name to associate with this Audio Object.
*/
protected AudioObject(AudioObject[] previous, String name) {
this.name = name;
this.previous = previous;
for (int i = 0; i < previous.length; i++) {
previous[i].setNext(this);
}
inputs = previous.length;
}
/**
* This constructor is used for generator and reader audio
* units where no previous audio objects exist in the stream.
* This constructor sets the sampleRate which
* will then propogate through to all following Audio Objects
* when their build methods are called. Any AudioObjects that
* make use of this constructor should be defined as primaryAO
* objects in the Instrument createChain() method.
*
* @param sampleRate the sample rate to use for all objects
* @param name A name to associate with this Audio Object
*/
protected AudioObject(Instrument inst, int sampleRate, String name) {
this.inst = inst;
this.name = name;
this.sampleRate = sampleRate;
this.inst.addPrimaryAO(this);
}
//----------------------------------------------
// Abstract Methods
//----------------------------------------------
/**
* The work method is responsible for handling the processing done
* by an AudioObject. This processing maybe as trivial as reading
* samples from an audio file or as complex as performing real-time
* fft transformations. The work method accepts an empty float[] as
* input and is responsible for filling and/or processing the samples
* contained in the array. The size of the array is defined in the
* Instrument class and is generally set to 4096.
*
* @throws AOException
*/
public abstract int work(float[] buffer) throws AOException;
//----------------------------------------------
// Private Methods
//----------------------------------------------
/**
* The setNext method is called from the constructor
* to set the next variable for the previous object
* in the object chain (essentially this creates a
* double linked list so every object in the chain
* knows which objects came before and which are
* to follow.
*
* @param next The audio object which follows this Audio Object.
*/
private void setNext(AudioObject next) {
if (this.next == null) {
this.next = new AudioObject[1];
this.next[0] = next;
} else {
AudioObject[] tmp = new AudioObject[this.next.length + 1];
for (int i = 0; i < this.next.length; i++) tmp[i] = this.next[i];
tmp[this.next.length] = next;
this.next = tmp;
}
}
//----------------------------------------------
// Protected Methods
//----------------------------------------------
/**
*
*/
public int nextWork(float[] buffer) throws AOException {
returned = 0;
returned = this.work(buffer);
//if(!this.finished)System.out.println(this.name);
this.inst.setFinished(this.finished);
return returned;
}
/**
* The buildNext method decimates information down
* through the audio chain passing data such as
* sampleRate, number channels, number of samples
* required etc.
* The buildNext method is also responsible for
* calling each audio objects build method which
* provides any additional initialization that the
* object may require.
* The buildNext method should be called by the
* first audio object in the audio chain to initialise
* all following audio objects.
*
* @param Note The note this chain is currently processing.
* @param startTime The startTime of the note.
* @param int The number of samples which need to be processed.
*/
protected void buildNext(final Note note, final double startTime, final int numOfSamples) {
if (next != null) {
for (int i = 0; i < next.length; i++) {
next[i].numOfSamples = numOfSamples;
next[i].inst = this.inst;
next[i].channels = this.channels;
next[i].sampleRate = this.sampleRate;
next[i].newNote(note, startTime, numOfSamples);
}
} else {
try {
this.inst.setFinalAO(this);
} catch (AOException aoe) {
System.out.println(aoe);
System.exit(1);
}
}
}
/**
* The build method can be overriden by Audio Objects
* to provide any extra initialization that may be
* required before the Audio Object can be used for
* each new note that needs rendering. The AudioObject parameters
* currentNote, currentNoteStartTime and numOfSamples will provide
* any note specific information that the build method may need to
* utilise.
*/
protected void build() {
//default build method does nothing.
}
//----------------------------------------------
// Public Methods
//----------------------------------------------
/**
* The newNote method is called everytime a new note is passed to the
* AudioObject. newNote sets a number of AudioObject parameters which
* are produced based on the new note information.
*
* @param note sets the parameter currentNote
* @param startTime sets the parameter currentNoteStartTime
* @param numOfSamples sets the parameter numOfSamples
*/
public void newNote(Note note, double startTime, int numOfSamples) {
this.currentNote = note;
this.currentNoteStartTime = startTime;
this.numOfSamples = numOfSamples;
this.build();
this.buildNext(this.currentNote, this.currentNoteStartTime,
this.numOfSamples);
}
/**
* getSampleRate returns an Audio Objects samples rate
*
* @return An audio objects sampleRate.
*/
public int getSampleRate() {
return this.sampleRate;
}
/**
* Returns the number of channels in this Audio Object
*
* @return An audio object's channels.
*/
public int getChannels() {
return this.channels;
}
}