jm.music.rt.RTLine 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 Licens
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
package jm.music.rt;
import jm.audio.AOException;
import jm.audio.AudioChainListener;
import jm.audio.Instrument;
import jm.audio.RTMixer;
import jm.music.data.Note;
/**
* This class frovides a framework for real time audio playback.
* It renders a Part using the provided instrument(s).
* If there are more than one instrument it is assumed they are
* simply multiple instances of the one instrument. These are used
* to play notes that overlap in the score or as a result of effects
* such as delays or reverb.
* There is an assumption that all instruments have the same sample rate
* number of channels.
*
* @author Andrew Sorensen
* @version 1.0, Sun Feb 25 18:43:31 2001
*/
public abstract class RTLine implements AudioChainListener {
//--------------------------------------
//Attributes
//--------------------------------------
/**
* The instrument associated with this real time line
*/
protected Instrument[] inst;
/**
* if clear is true the threads wait call will be skipped
*/
protected boolean clear = false;
/**
* Note object to reuse
*/
Note note = null;
double scorePos = 0.0;
double temp = 1.0;
/**
* counter for how far we have gone between notes player
*/
private double localCounter = 0.0;
/**
* are we after a new note ?
*/
private boolean newNote = true;
/**
* tempo value
*/
private double tempo = 60.0;
/**
* test position ????
*/
private double testPos;
/**
* This value is equal to (sampleRate * channels)
*/
private double size;
//--------------------------------------
//Constructors
//--------------------------------------
/**
* The RTLine constructor is primarily responsible for initialising its
* associated instrument and the instruments audio chain.
*/
public RTLine(Instrument[] inst) {
this.inst = inst;
for (int i = 0; i < inst.length; i++) {
inst[i].addRTLine(this);
}
// check that all inst sample rates are the same
int sr = inst[0].getSampleRate();
int ch = inst[0].getChannels();
for (int i = 0; i < inst.length; i++) {
if (inst[i].getSampleRate() != sr) {
System.err.println("jMusic RTLine error: All instruments" +
" must have the same sample rate.");
System.exit(0);
}
if (inst[i].getChannels() != ch) {
System.err.println("jMusic RTLine error: All instruments" +
" must have the same number of channels.");
System.exit(0);
}
}
this.size = sr * ch;
}
//--------------------------------------
//Public Methods
//--------------------------------------
/**
* Returns the instrument associated with this RTLine
*
* @return Instrument the instrument associated with this RTLine
*/
public Instrument[] getInstrument() {
return inst;
}
/**
* Return the number of lines (note polyphony for this RTLine
*/
public int getNumLines() {
return inst.length;
}
/**
* sets the tempo of this RTLine
*/
public void setTempo(double tempo) {
this.tempo = tempo;
}
/**
* Specify the buffer size for each instrument.
* Called by RTMixer.
*/
public void setBufferSize(int buf) {
for (int i = 0; i < inst.length; i++) {
inst[i].setBufSize(buf);
}
}
/**
* Return the current samplerate, based on the sample rate of the instruments.
* All instrument sample rates in real time audio must be the same.
*/
public int getSampleRate() {
return inst[0].getSampleRate();
}
/**
* Return the current number of channels, based on the channels of the instruments.
* All instruments in real time audio must have the same number of channels.
*/
public int getChannels() {
return inst[0].getChannels();
}
/**
* External action is called by RTMixer whenever an external event is sent
* to trigger a real time audio event. The event will commonly be
* triggered by a GUI widget such as a button or slider.
*
* @param obj and undetermined Object which will need to be cast locally to
* whatever type is expected.
* @param actionNumber is an serial index value for the source of the
* event.
*/
public void externalAction(Object obj, int actionNumber) {
//Is there anything we want done by default ??
}
/**
* controlChange is called by RTLine's instrument everytime it completes
* filling its current buffer. The regularity at which controlChange is
* called is what determines the control rate. The control rate is used
* therefore to set the buffer sizes of the instrument sample buffers.
*
* @param buffer a buffer of samples passed from an instrument
* @param returned the number of samples in the buffer
* @param finished this boolean indicates whether the instrument has
* finished processing its current note.
*/
public synchronized void controlChange(float[] buffer, int returned, boolean finished) {
//do nothing here unless overriden
}
/**
* This method is called from Instrument and in return calls that
* instrument's renderNote method. When this method returns, the instruments
* iterateChain method is called and the note is processed. This method
* is responsible for either fetching a "playable" note from the getNextNote()
* method or else for inserting a rest of an appropriate amount of time.
*/
public void instNote(Instrument inst, long samplesProcessed) {
//Note note = null;
scorePos = ((double) samplesProcessed) / size;
temp = 60.0 / this.tempo;
//System.out.println("RTLine instNote. scorePos = " + scorePos + " testPos = " + testPos);
if (scorePos > testPos) { //(scorePos > (testPos - 0.00001)) { // && scorePos < (testPos + 0.0001)){
note = getNextNote().copy();
note.setRhythmValue(note.getRhythmValue() * temp);
note.setDuration(note.getDuration() * temp);
testPos += note.getRhythmValue();
//System.out.println("RTLine: processing a note. Pitch = " + note.getPitch() + " Length = " + (testPos-scorePos) + " Duration = " + note.getDuration());
} else {
note = new Note(jm.JMC.REST, (testPos - scorePos));
note.setRhythmValue(note.getRhythmValue() * temp);
note.setDuration(note.getRhythmValue());
//System.out.println("RTLine: adding a rest. Length = " + (testPos-scorePos) + " Sampled processed = " + samplesProcessed);
}
inst.renderNote(note, scorePos);
}
/**
* start this RTLine's instrument call for the setting of the first note
*/
public void start(RTMixer rta) { // double scorePosition,
for (int i = 0; i < inst.length; i++) {
try {
if (inst[i].getInitialised() == false) {
inst[i].createChain();
inst[i].setInitialised(true);
}
//inst[i].setBufSize(bufferSize);
inst[i].addAudioChainListener(rta);
inst[i].start();
} catch (AOException aoe) {
System.err.println("jMusic RTLine start error: Perhpas a jMusic instrument was being reused.");
aoe.printStackTrace();
}
}
}
/*
* Halt the playback.
*/
public void pause() {
for (int i = 0; i < inst.length; i++) {
inst[i].pause();
}
}
/*
* Continue the playback.
*/
public void unPause() {
for (int i = 0; i < inst.length; i++) {
inst[i].unPause();
}
}
/*
* Stop the playback.
*/
public void stop() {
for (int i = 0; i < inst.length; i++) {
inst[i].stop(); // calls the stop() method in the Thread class
}
}
/**
* Override this method to set the next method to be called.
*/
public abstract Note getNextNote();
}