X-Git-Url: http://source.jalview.org/gitweb/?a=blobdiff_plain;f=unused%2Fjavajs%2Futil%2FJSAudioThread.java;fp=unused%2Fjavajs%2Futil%2FJSAudioThread.java;h=3bcb0069c654b18ccaacc3e752ace0094d9a7240;hb=5152dafd5d71c877156621def8463d437c9c5453;hp=0000000000000000000000000000000000000000;hpb=c4cf7aa546ede43930f9a17fec5060119984da41;p=jalview.git diff --git a/unused/javajs/util/JSAudioThread.java b/unused/javajs/util/JSAudioThread.java new file mode 100644 index 0000000..3bcb006 --- /dev/null +++ b/unused/javajs/util/JSAudioThread.java @@ -0,0 +1,258 @@ +package javajs.util; + +import javax.sound.sampled.AudioFormat; +import javax.sound.sampled.AudioSystem; +import javax.sound.sampled.DataLine; +import javax.sound.sampled.SourceDataLine; + +import sun.audio.AudioData; +import sun.audio.AudioDataStream; +import sun.audio.AudioPlayer; + + +/** + * The JSAudioThread adds a layer to JSThread that is specific for audio. + * This class utilizes JSAudioLine, which is not fully fleshed out. + * + * Two very simple interfaces, + * + * (new JSAudioThread()).playULawData(byte[] b); + * + * and + * + * (new JSAudioThread(audioFormat)).playOnce(byte[] b, offset, length); + * + * allow straightforward audio production without having to work with + * SourceDataLine directly. + * + * As a JSThread, this class implements myInit(), isLooping(), myLoop(), + * whenDone(), onException(), and doFinally(). + * + * If the constructor JSAudioThread(JSAudioThreadUser, AudioFormat, byte[]) is + * used, then the JSAudioThreadUser must simply implement fillAudioBuffer(), + * checkSoundStatus(), and audioThreadExiting() for very simple streaming audio. + * JSAudioThread will then take care of all the timing issues. + * + * But the implementer is welcome to override any of the JSThread overrides + * themselves in order to customize this further. + * + * The standard streaming case, then is: + * + * audioThread = new JSAudioThread(audioUser, audioFormat, audioByteBuffer); + * audioThread.start(); + * + * where audioUser provides + * + * checkSoundStatus() (called in isLooping()), + * + * fillAudioBuffer() (called in myLoop()), + * + * and + * + * audioThreadExiting() (called in doFinally()). + * + * @author Bob Hanson + * + */ +public class JSAudioThread extends JSThread { + + protected Owner owner; + protected boolean done; + protected int myBufferLength; + protected SourceDataLine line; + protected int rate, nChannels, bitsPerSample; + + protected byte[] audioByteBuffer; + protected int audioBufferByteLength; + + private AudioFormat audioFormat; + private int myBufferOffset; + private int playCount; + + public JSAudioThread(Owner owner, AudioFormat audioFormat, byte[] audioByteBuffer) { + this.owner = owner; + setFormat(audioFormat); + setBuffer(audioByteBuffer); + } + + /** + * A convenience constructor requiring standard settings of + * signed (for 8-bit) and littleEndian (for 16-bit) + * + * @param owner + * @param rate + * @param bitsPerSample + * @param nChannels + * @param audioByteBuffer + */ + public JSAudioThread(Owner owner, int rate, int bitsPerSample, int nChannels, byte[] audioByteBuffer) { + this.owner = owner; + setFormat(new AudioFormat(rate, bitsPerSample, nChannels, true, false)); + setBuffer(audioByteBuffer); + } + + /** + * primarily available for (new JSAudioThread()).playULawData + * + */ + public JSAudioThread() { + } + + /** + * primarily available for (new JSAudioThread()).playOnce + * + */ + public JSAudioThread(AudioFormat audioFormat) { + setFormat(audioFormat); + } + + /** + * + * A simple 8-bit uLaw data player + * + * @param data + */ + public void playULawData(byte[] data) { + // this constructor uses default new AudioFormat(ULAW,8000,8,1,1,8000,true) + // threading is taken care of by the browser in JavaScript + AudioPlayer.player.start(new AudioDataStream(new AudioData(data))); + } + + + /** + * Just play once through; no additions + * + * @param data + */ + public void playOnce(byte[] data, int offset, int length) { + setBuffer(data); + myBufferOffset = offset; + myBufferLength = length; + playCount = 1; + start(); + } + + public void setBuffer(byte[] audioByteBuffer) { + this.audioByteBuffer = audioByteBuffer; + audioBufferByteLength = audioByteBuffer.length; + } + + public SourceDataLine getLine() { + return line; + } + + public AudioFormat getFormat() { + return audioFormat; + } + + public void setFormat(AudioFormat audioFormat) { + this.audioFormat = audioFormat; + rate = (int) audioFormat.getSampleRate(); + bitsPerSample = audioFormat.getSampleSizeInBits(); + nChannels = audioFormat.getChannels(); + } + + public void resetAudio() { + if (line == null) + return; + line.flush(); + line.close(); + line = null; + } + + /** + * Standard initialization of a SourceDataLine + * + */ + @Override + protected boolean myInit() { + try { + DataLine.Info info = new DataLine.Info(SourceDataLine.class, audioFormat); + if (line != null) + line.close(); + line = (SourceDataLine) AudioSystem.getLine(info); + line.open(audioFormat, audioBufferByteLength); + line.start(); + } catch (Exception e) { + e.printStackTrace(); + return false; + } + return true; + } + + @Override + protected boolean isLooping() { + return !done && (--playCount >= 0 || owner != null && owner.checkSoundStatus()); + } + + @Override + protected boolean myLoop() { + if (!done) { + if ((myBufferLength = (owner == null ? myBufferLength : owner.fillAudioBuffer())) <= 0) + return !(done = true); + try { + if (line == null) + myInit(); + line.write(audioByteBuffer, myBufferOffset, myBufferLength); + } catch (Exception e) { + e.printStackTrace(); + done = true; + } + } + return !done; + } + + @Override + protected void whenDone() { + done = true; + resetAudio(); + } + + @Override + protected int getDelayMillis() { + // about 25% of the actual play time + return 1000 // ms/sec + * (myBufferLength * 8 / bitsPerSample) // * samples + / rate // * seconds/sample) + / nChannels // / number of channels + / 4; // * 25% + } + + @Override + protected void onException(Exception e) { + e.printStackTrace(); + } + + @Override + protected void doFinally() { + if (owner != null) + owner.audioThreadExiting(); + } + + public interface Owner { + + /** + * + * @return true if thread should continue; false if not + * + */ + boolean checkSoundStatus(); + + /** fill audio buffer + * + * @return number of bytes to write to audio line + * + */ + int fillAudioBuffer(); + + /** + * called from the finally clause when complete + * + */ + void audioThreadExiting(); + + + } + +} +