com.sun.j3d.audioengines.javasound.JSClip Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of java3d-core Show documentation
Show all versions of java3d-core Show documentation
Java3D Core And Java3D Util Libraries
The newest version!
/*
* Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistribution of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistribution in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* Neither the name of Sun Microsystems, Inc. or the names of
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* This software is provided "AS IS," without a warranty of any
* kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
* WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
* EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
* NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
* USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
* DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
* ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
* CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
* REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
* INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGES.
*
* You acknowledge that this software is not designed, licensed or
* intended for use in the design, construction, operation or
* maintenance of any nuclear facility.
*
*/
/*
* IMPLEMENTATION NOTE: The JavaSoundMixer is incomplete and really needs
* to be rewritten.
*/
package com.sun.j3d.audioengines.javasound;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.Clip;
import javax.sound.sampled.DataLine;
import javax.sound.sampled.LineEvent;
/**
* The JSClip Class defines an audio output methods that call JavaSound
* Hae mixer methods.
*/
class JSClip extends JSChannel {
Clip line;
// TODO: separate left and right channel required until I write into
// stereo buffer!
Clip otherChannel = null;
// TODO: Reverb channel that is centered and not delayed is maintained separately
// until a way to set stereo reverb send (panned and attenuated to give
// the same affect) is implemented
Clip reverbChannel = null;
/**
* Create data line for outputting audio input stream.
* for a stream that is a sourceDataline
* @return true is successful in initiallizing DataLine
*/
@Override
DataLine initDataLine(AudioInputStream ais) {
if (debugFlag)
debugPrintln("JSClip: initDataLine(" + ais + ")");
try {
if (debugFlag)
debugPrintln("JSClip: loadSample - try getting new line ");
/*
* From the AudioInputStream fetch information about the format
* of the audio data - including sampling frequency, number of
* channels, size of samples,...
*/
audioFormat = ais.getFormat();
/*
* we can't yet open the device for ALAW/ULAW playback,
* convert ALAW/ULAW to PCM
*/
if ((audioFormat.getEncoding() == AudioFormat.Encoding.ULAW) ||
(audioFormat.getEncoding() == AudioFormat.Encoding.ALAW)) {
AudioFormat tmp =
new AudioFormat(
AudioFormat.Encoding.PCM_SIGNED,
audioFormat.getSampleRate(),
audioFormat.getSampleSizeInBits() * 2,
audioFormat.getChannels(),
audioFormat.getFrameSize() * 2,
audioFormat.getFrameRate(),
true);
ais = AudioSystem.getAudioInputStream(tmp, ais);
audioFormat = tmp;
}
/*
* ask JavaSound for outline with a format suitable for our
* AudioInputStream. In order to ask for a line, a Info object
* with the desired properties must be constructed.
* Clip is used for outputing buffered data.
* We have to pass the line the AudioFormat object so it knows
* format will be.
*
* TODO: we could give JavaSound a hint about how big the
* internal buffer for the line should be, rather than use the
* default.
*/
DataLine.Info info = new DataLine.Info(Clip.class,
audioFormat);
line = (Clip)AudioSystem.getLine(info);
/*****
// TODO: JSClip can't be a listener (do we need to do this in the thread?)
if (debugFlag)
debugPrintln("JSClip: addLineListener for clip");
line.addLineListener(this);
******/
if (debugFlag)
debugPrintln("JSClip: open sound Clip");
// Make line ready to receive data.
line.open(ais);
// Line can now receive data but still needs to be
// activated (opened) so it will pass data on to the
// audio device. This is done at "startSample" time.
}
catch (Exception e) {
if (debugFlag) {
debugPrint("JSClip: Internal Error loadSample ");
debugPrintln("get stream failed");
}
e.printStackTrace();
// TODO: clean up vector elements that were set up for
// failed sample
return null;
}
return (DataLine)line;
} // initDataLine
/**
* Start TWO Samples
*
* used when two samples are associated with a single Point or Cone
* sound. This method handles starting both samples, rather than
* forcing the caller to make two calls to startSample, so that the
* actual Java Sound start methods called are as immediate (without
* delay between as possible.
*/
@Override
boolean startSamples(int loopCount, float leftGain, float rightGain,
int leftDelay, int rightDelay) {
// loop count is ignored for Stream and MIDI
// TODO: loop count isn't implemented for MIDI yet
// left and rightDelay parameters are in terms of Samples
if (debugFlag) {
debugPrint("JSClip: startSamples ");
debugPrintln("start stream for Left called with ");
debugPrintln(" gain = " + leftGain +
" delay = " + leftDelay);
debugPrintln("start stream for Right called with ");
debugPrintln(" gain = " + rightGain +
" delay = " + rightDelay);
}
// This is called assuming that the Stream is allocated for a
// Positional sample, but if it is not then fall back to
// starting the single sample associated with this Stream
if (otherChannel == null || reverbChannel == null)
startSample(loopCount, leftGain, leftDelay);
/*
* ais for Left and Right streams should be same so just get ais
* left stream
*/
if (ais == null) {
if (debugFlag) {
debugPrint("JSClip: Internal Error startSamples: ");
debugPrintln("either left or right ais is null");
}
return false;
}
Clip leftLine;
Clip rightLine;
leftLine = line;
rightLine = otherChannel;
// left line only for background sounds...
// TODO:
/***********
for now just care about the left
if (leftLine == null || rightLine == null) {
if (debugFlag) {
debugPrint("JSClip: startSamples Internal Error: ");
debugPrintln("either left or right line null");
}
return false;
}
************/
// we know that were processing TWO channels
double ZERO_EPS = 0.0039; // approx 1/256 - twice MIDI precision
double leftVolume = (double)leftGain;
double rightVolume = (double)rightGain;
// TODO: if not reading/writing done for Clips then I can't do
// stereo trick (reading mono file and write to stereo buffer)
// Save time sound started, only in left
startTime = System.currentTimeMillis();
if (debugFlag)
debugPrintln("*****start Stream with new start time " +
startTime);
try {
// QUESTION: Offset clip is done how???
/*******
// TODO:
offset delayed sound
set volume
set pan??
set reverb
boolean reverbLeft = false; // off; reverb has it own channel
boolean reverbRight = reverbLeft;
if (leftDelay < rightDelay) {
XXXX audioLeftStream.start(leftVolume, panLeft, reverbLeft);
XXXX audioRightStream.start(rightVolume, panRight, reverbRight);
}
else {
XXXX audioRightStream.start(rightVolume, panRight, reverbRight);
XXXX audioLeftStream.start(leftVolume, panLeft, reverbLeft);
}
******/
line.setLoopPoints(0, -1); // Loop the entire sound sample
line.loop(loopCount); // plays clip loopCount + 1 times
line.start(); // start the sound
}
catch (Exception e) {
if (debugFlag) {
debugPrint("JSClip: startSamples ");
debugPrintln("audioInputStream.read failed");
}
e.printStackTrace();
startTime = 0;
return false;
}
if (debugFlag)
debugPrintln("JSClip: startSamples returns");
return true;
} // end of startSamples
/*
* This method is called specifically for BackgroundSounds.
* There is exactly ONE sample (mono or stereo) associated with
* this type of sound. Consequently, delay is not applicable.
* Since the sound has no auralAttributes applied to it reverb
* is not applied to the sample.
*/
@Override
boolean startSample(int loopCount, float gain, int delay) {
/*
if (debugFlag) {
debugPrint("JSClip: startSample ");
debugPrintln("start stream called with ");
debugPrintln(" gain = " + gain + ", delay is zero");
}
// Since only one sample is processed in startSample, just call
// this more general method passing duplicate information
// We don't really want to do this in the long term.
return startSamples(loopCount, gain, gain, 0, 0);
*/
// TODO: The following is temporary until we have fully
// functional startSample and startSamples methods
if (debugFlag)
debugPrintln("JSClip.startSample(): starting sound Clip");
line.setFramePosition(0); // Start playing from the beginning
line.setLoopPoints(0, -1); // Loop the entire sound sample
line.loop(loopCount);
line.start();
return true;
} // end of start (single) Sample
@Override
int stopSample() {
// This will tell thread to stop reading and writing
// reload with old URL - reloadSample()???
if (debugFlag)
debugPrintln("JSClip.stopSample(): stopping sound Clip");
line.stop();
startTime = 0;
return 0;
}
@Override
int stopSamples() {
// This will tell thread to stop reading and writing
// TODO: For muting, stop sound but don't clear startTime...
// QUESTION: what does it mean for replaying that .stop "frees memory"
// reloadSample
// QUESTION: set stop state WHERE??!!
if (debugFlag)
debugPrintln("JSClip.stopSample(): stopping sound Clip");
line.stop();
startTime = 0;
return 0;
}
/*
* called by LineListener class
*/
public void update(LineEvent event) {
if (event.getType().equals(LineEvent.Type.STOP)) {
line.close(); // really a stop??
}
else if (event.getType().equals(LineEvent.Type.CLOSE)) {
// this forces a system exit in example code
// TODO: what should be done to close line
if (debugFlag)
debugPrint("JSClip.update(CLOSE) entered ");
}
}
}