org.monte.media.eightsvx.JDK13ShortAudioClip Maven / Gradle / Ivy
/*
* @(#)Main.java
* Copyright © 2023 Werner Randelshofer, Switzerland. MIT License.
*/
package org.monte.media.eightsvx;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.Clip;
import javax.sound.sampled.DataLine;
import javax.sound.sampled.FloatControl;
import javax.sound.sampled.Line;
import javax.sound.sampled.LineUnavailableException;
/**
* JDK13ShortAudioClip.
*
* @author Werner Randelshofer, Hausmatt 10, CH-6405 Goldau, Switzerland
*/
public class JDK13ShortAudioClip implements LoopableAudioClip {
private Clip clip;
/**
* This buffer holds the audio samples of the clip.
*/
private byte[] samples;
/**
* The sample rate of the audio data.
*/
private int sampleRate;
/**
* Represents a control for the volume on a line. 64 is the maximal
* volume, 0 mutes the line.
*/
private int volume;
/**
* The relative pan of a stereo signal between two stereo
* speakers. The valid range of values is -1.0 (left channel only) to 1.0
* (right channel only). The default is 0.0 (centered).
*/
private float pan;
private AudioFormat audioFormat;
/**
* Creates a new instance.
*
* @param samples Array of signed linear 8-bit encoded audio samples.
* @param sampleRate sampleRate of the audio samples.
* @param volume The volume setting controls the loudness of the sound.
* range 0 (mute) to 64 (maximal volume).
* @param pan The relative pan of a stereo signal between two stereo
* speakers. The valid range of values is -1.0 (left channel only) to 1.0
* (right channel only). The default is 0.0 (centered).
*/
public JDK13ShortAudioClip(byte[] samples, int sampleRate, int volume, float pan) {
this.samples = samples;
this.sampleRate = sampleRate;
this.volume = volume;
this.pan = pan;
}
public synchronized void loop() {
loop(LOOP_CONTINUOUSLY);
}
public synchronized void play() {
stop();
if (clip == null) {
try {
clip = createClip();
clip.open(getAudioFormat(), samples.clone(), 0, samples.length);
if (clip.isControlSupported(FloatControl.Type.PAN)) {
FloatControl control = (FloatControl) clip.getControl(FloatControl.Type.PAN);
control.setValue(pan);
}
if (clip.isControlSupported(FloatControl.Type.VOLUME)) {
FloatControl control = (FloatControl) clip.getControl(FloatControl.Type.VOLUME);
control.setValue(volume / 64f);
}
clip.start();
} catch (LineUnavailableException e) {
e.printStackTrace();
throw new InternalError(e.getMessage());
}
}
}
public synchronized void stop() {
if (clip != null) {
clip.stop();
clip.close();
clip = null;
}
}
private AudioFormat getAudioFormat() {
if (audioFormat == null) {
audioFormat = new AudioFormat(
(float) sampleRate,
8, //int�sampleSizeInBits
1, //int�channels
true, //boolean�signed,
true //boolean�bigEndian
);
}
return audioFormat;
}
private Clip createClip() throws LineUnavailableException {
Line.Info lineInfo = new DataLine.Info(Clip.class, getAudioFormat());
Clip c;
/*Mixer m = JDK13LongAudioClip.getMixer();
if (m != null) {
c = (Clip) m.getLine(lineInfo);
} else {*/
c = (Clip) AudioSystem.getLine(lineInfo);
//}
return c;
}
/**
* Starts looping playback from the current position. Playback will
* continue to the loop's end point, then loop back to the loop start point
* count
times, and finally continue playback to the end of
* the clip.
*
* If the current position when this method is invoked is greater than the
* loop end point, playback simply continues to the
* end of the clip without looping.
*
* A count
value of 0 indicates that any current looping should
* cease and playback should continue to the end of the clip. The behavior
* is undefined when this method is invoked with any other value during a
* loop operation.
*
* If playback is stopped during looping, the current loop status is
* cleared; the behavior of subsequent loop and start requests is not
* affected by an interrupted loop operation.
*
* @param count the number of times playback should loop back from the
* loop's end position to the loop's start position, or
* {@link #LOOP_CONTINUOUSLY}
to indicate that looping should
* continue until interrupted
*/
public void loop(int count) {
stop();
try {
clip = createClip();
clip.open(getAudioFormat(), samples.clone(), 0, samples.length);
if (clip.isControlSupported(FloatControl.Type.PAN)) {
FloatControl control = (FloatControl) clip.getControl(FloatControl.Type.PAN);
control.setValue(pan);
}
if (clip.isControlSupported(FloatControl.Type.VOLUME)) {
FloatControl control = (FloatControl) clip.getControl(FloatControl.Type.VOLUME);
control.setValue(volume / 64f);
}
clip.loop(count);
} catch (LineUnavailableException e) {
e.printStackTrace();
throw new InternalError(e.getMessage());
}
}
}