
jm.audio.io.SampleIn 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.io;
import jm.audio.AOException;
import jm.audio.AudioObject;
import jm.audio.Instrument;
import javax.sound.sampled.AudioFileFormat;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.UnsupportedAudioFileException;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
/**
* Audio file reading audio object for jMusic.
* The class utilises the JavaSound file reading classes.
* It can be used as the primary audio object in a chain to generate
* audio sample data for playabck and or later processing.
*
* @author Andrew Sorensen and Andrew Brown (at the same time ;)
* clipping error fixed by Tim Opie
*/
public class SampleIn extends AudioObject implements jm.JMC {
private File file;
private AudioFileFormat fileFormat;
private AudioFormat format;
/**
* The numnber of bits that represent one sample, e.g. 1 = 8 bits, 2 = 16 bits etc.
*/
private int sampleSize;
/* The file format name, e.g. WAV, AIFF, AU */
private String fileType;
/**
* Should we be cacheing the files audio data
*/
private boolean cache;
/**
* Duration of the sound file in samples
*/
private long duration;
/**
* Input Stream
*/
private InputStream is;
/**
* Play a whole file, or only note length?
*/
private boolean wholeFile = false;
/**
* Loop this audio file how many times ?
*/
private int loop;
/**
* number of times to loop
*/
private int loopCount;
/**
* The sample locations between which to repeat and the current position in the stream.
* This number is independent of channels - i.e. 44100 = 1 sec audio regarless of channels
*/
private int loopStart, loopEnd, streamPosition;
/**
* Endianess
*/
private boolean bigEndian;
/**
* Read in the data from the specified file as input to
* an audio ren dering process.
*
* @param fileName - The name of the file to be used.
* @param fileName - The name of the file to be used.
*/
public SampleIn(Instrument inst, String fileName) {
this(inst, fileName, false); // should be false - hack!!!
}
/**
* Read in the data from the specified file as input to
* an audio ren dering process.
*
* @param inst - The instrument for which this audio object is a part.
* @param fileName - The name of the file to be used.
* @param cache - A flag to say weather or not to hold sample data in memory.
*/
public SampleIn(Instrument inst, String fileName, boolean cache) {
this(inst, fileName, cache, false);
}
/**
* Read in the data from the specified file as input to
* an audio ren dering process.
*
* @param inst - The instrument for which this audio object is a part.
* @param fileName - The name of the file to be used.
* @param cache - A flag to say weather or not to hold sample data in memory.
* @param wholeFile - A flag to indicate weather the file should be played
* all the way through, regardless of the note duration.
*/
public SampleIn(Instrument inst, String fileName, boolean cache, boolean wholeFile) {
this(inst, fileName, cache, wholeFile, 0);
}
/**
* Read in the data from the specified file as input to
* an audio ren dering process.
*
* @param inst - The instrument for which this audio object is a part.
* @param fileName - The name of the file to be used.
* @param cache - A flag to say weather or not to hold sample data in memory.
* @param wholeFile - A flag to indicate weather the file should be played
* all the way through, regardless of the note duration.
* @param loop - The number of time to reapeatedly playback the file
* (0 is no loop, -1 is infinite).
*/
public SampleIn(Instrument inst, String fileName, boolean cache,
boolean wholeFile, int loop) {
this(inst, fileName, cache, wholeFile, 0, 0, 0);
}
/**
* Read in the data from the specified file as input to
* an audio ren dering process.
*
* @param inst - The instrument for which this audio object is a part.
* @param fileName - The name of the file to be used.
* @param cache - A flag to say weather or not to hold sample data in memory.
* @param wholeFile - A flag to indicate weather the file should be played
* all the way through, regardless of the note duration.
* @param loop - The number of time to reapeatedly playback the file
* (0 is no loop, -1 is infinite).
* @param loopStart - The sample from which to start looping.
* @param loopEnd - The sample at which to end the loop.
*/
public SampleIn(Instrument inst, String fileName, boolean cache,
boolean wholeFile, int loop, int loopStart, int loopEnd) {
super(inst, 0, "[SampleIn]");
try {
this.file = new File(fileName);
this.cache = cache;
this.wholeFile = wholeFile;
this.loop = loop;
this.loopStart = loopStart;
this.loopEnd = loopEnd;
if (this.loop == -1) this.loop = Integer.MAX_VALUE;
this.fileFormat = AudioSystem.getAudioFileFormat(this.file);
this.format = this.fileFormat.getFormat();
bigEndian = this.format.isBigEndian();
channels = format.getChannels();
sampleRate = (int) format.getSampleRate();
this.duration = (long) this.fileFormat.getFrameLength() * this.channels;
//System.out.println("duration = " + duration + " sampleSize = " + sampleSize + " channels = " + channels);
//if(wholeFile) this.duration = Long.MAX_VALUE;
this.sampleSize = (format.getSampleSizeInBits()) / 8;
fileType = fileFormat.toString();
this.is = AudioSystem.getAudioInputStream(this.file);
if (this.cache) {
byte[] tmp = new byte[(int) this.duration * this.sampleSize];
this.is.read(tmp);
this.is.close();
this.is = new ByteArrayInputStream(tmp);
}
} catch (UnsupportedAudioFileException uafe) {
//??
} catch (IOException ioe) {
ioe.printStackTrace();
}
}
public void finalize() {
try {
this.is.close();
} catch (IOException ioe) {
ioe.printStackTrace();
}
}
/**
* Set up for the next note rendering.
*/
public void build() {
//System.out.println("Entered sampleIn build() method.");
//this.finished = false;
//if(wholeFile)this.finished = false;
if (!wholeFile) this.duration = (long) (currentNote.getDuration() *
(double) this.sampleRate * (double) this.channels);
this.loopCount = this.loop;
reset(0);
}
/**
* Set the sample read location back to the beginning of the file.
*/
public void reset(int spot) {
this.streamPosition = 0;
try {
if (cache) {
this.is.reset();
} else {
this.is = AudioSystem.getAudioInputStream(this.file);
if (spot > 0) this.is.read(new byte[spot * this.sampleSize * this.channels]);
}
} catch (UnsupportedAudioFileException uafe) {
System.out.println("jMusic SampleIn error: This file format is not supported.");
System.exit(0);
} catch (IOException ioe) {
ioe.printStackTrace();
}
}
/**
* Read in samples from the file and pass it down the audio chain.
* The input to this method is bogus as it is always the first in the
* audio chain and therefore receives no input.
*
* @param input bogus input here, necessarily included to fit in with the general audio object design.
*/
public int work(float[] buffer) throws AOException {
//System.out.println("SampleIn is working ...");
this.finished = false;
byte[] tmp = new byte[sampleSize * this.channels];
byte[] sampleTmp = new byte[sampleSize];
for (int i = 0; i < buffer.length - channels; i += channels) {
//System.out.println("i = " +i + " " + channels + " Buffer = " + buffer.length);
try { // javaSound reads an entire sample frame
if (is.read(tmp) == -1) { // end of file reached
this.finished = true;
} else {
// treat each channel in the frame separately
for (int j = 0; j < channels; j++) {
// split the frame into channels
for (int k = 0; k < sampleSize; k++) {
sampleTmp[k] = tmp[k + j * sampleSize];
}
//System.out.println(i+j);
buffer[i + j] = this.getFloat(sampleTmp);
//System.out.println(i+"- SampleIn value - " + buffer[i]);
if (++this.streamPosition == loopStart && loop > 0) {
this.is.mark(loopStart);
} else if (this.streamPosition == loopEnd && loop > 0) {
if (--loopCount >= 1) {
this.reset(loopStart);
this.streamPosition = loopStart;
}
}
if (this.streamPosition >= this.duration) {
this.finished = true;
}
}
}
} catch (IOException ioe) {
ioe.printStackTrace();
}
}
return buffer.length;
}
/**
* Specify weather or not to read the whole file before
* finishing. If not, then the note length will determine the
* amount of data read.
*
* @param val - The new boolean value.
*/
public void setWholeFile(boolean val) {
this.wholeFile = val;
}
/**
* Returns the number of samples in one track of the file.
* i.e., the wave length, or size.
*/
public int getWaveSize() {
return (int) (duration / channels);
}
/**
* Return the length of the sample in Bytes.
*/
public int getNumOfBytes() {
return (int) (this.duration * this.sampleSize);
}
/**
* Provide the sampleSize value of this file as the number of bytes per sample.
* Deprictaed in favour of getSampleSize.
*
* @return The number of bytes per sample, 1 = 8 bit, 2 = 16 bit, etc.
*/
public int getBits() {
return this.sampleSize;
}
/**
* Provide the sampleSize value of this file as the number of bytes per sample.
*
* @return The number of bytes per sample, 1 = 8 bit, 2 = 16 bit, etc.
*/
public int getSampleSize() {
return this.sampleSize;
}
/**
* Provide the bit size of the current audio file.
*
* @return The bit depth, 8, 16, 24, or 32.
*/
public int getBitResolution() {
int depth = -1;
switch (this.sampleSize) {
case 1:
depth = 8;
break;
case 2:
depth = 16;
break;
case 3:
depth = 24;
break;
case 4:
depth = 32;
break;
}
return depth;
}
/**
* BigEndian conversion
*/
private float getFloat(byte[] b) {
float sample = 0.0f;
int ret = 0;
int length = b.length;
for (int i = 0; i < b.length; i++, length--) {
ret |= ((int) (b[i] & 0xFF) << ((((bigEndian) ? length : (i + 1)) * 8) - 8));
}
switch (sampleSize) {
case 1:
if (ret > 0x7F) {
ret = ~ret;
ret &= 0x7F;
ret = ~ret + 1;
}
sample = (float) ((float) ret / (float) Byte.MAX_VALUE);
break;
case 2:
if (ret > 0x7FFF) {
ret = ~ret;
ret &= 0x7FFF;
ret = ~ret + 1;
}
sample = (float) ((float) ret / (float) Short.MAX_VALUE);
break;
case 3:
if (ret > 0x7FFFFF) {
ret = ~ret;
ret &= 0x7FFFFF;
ret = ~ret + 1;
}
sample = (float) ((float) ret / 8388608f);
break;
case 4:
sample = (float) ((double) ret / (double) Integer.MAX_VALUE);
break;
default:
System.err.println("Format not accepted");
}
return sample;
}
/**
* Specify the starting point for the audio loop.
* The number of loops will need to be set to be greater
* than 0 for the loop to go. Use setLoop() to specify the number.
*
* @param newPos The loop start location in samples
*/
public void setLoopStart(int newPos) {
this.loopStart = newPos;
}
/**
* Specify the ending point for the audio loop.
* The number of loops will need to be set to be greater
* than 0 for the loop to go. Use setLoop() to specify the number.
*
* @param newPos The loop start location in samples
*/
public void setLoopEnd(int newPos) {
this.loopEnd = newPos;
}
/**
* Specify the number of times the looped section should repeat.
* The number of loops will need to be set to be greater
* than 0 for the loop to go, and 0 is no loop, -1 is infinite loops until
* the note ends.
*
* @param times The number of times the looped section should play.
*/
public void setLoop(int times) {
this.loop = times;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy