samer@0: /* samer@0: * LineSink.java samer@0: * samer@0: * Copyright (c) 2000, Samer Abdallah, King's College London. samer@0: * All rights reserved. samer@0: * samer@0: * This software is provided AS iS and WITHOUT ANY WARRANTY; samer@0: * without even the implied warranty of MERCHANTABILITY or samer@0: * FITNESS FOR A PARTICULAR PURPOSE. samer@0: */ samer@0: samer@0: package samer.audio; samer@0: import samer.core.*; samer@0: import samer.core.types.*; samer@0: import samer.tools.*; samer@0: import java.io.*; samer@0: import javax.sound.sampled.*; samer@0: samer@0: /** samer@0: An AudioSink that sends samples to a Java Sound SourceDataLine. samer@0: Audio format can be determined in several ways (see below). samer@0:

Object is a Viewable, and is called "lineout". samer@0: Reads property "scale" from current environment, but scale samer@0: can be adjusted afterwards. samer@0: @see samer.audio.AudioSink samer@0: */ samer@0: samer@0: public class LineSink extends VLine implements AudioSink samer@0: { samer@0: private SourceDataLine line; samer@0: private AudioFormat fmt; samer@0: private int bufsize=0; samer@0: private VDouble scale; samer@0: samer@0: /** Create LineSink reading from given TargetDataLine */ samer@0: public LineSink(SourceDataLine l, AudioFormat f) throws Exception { samer@0: super("lineout"); samer@0: line=l; fmt=f; samer@0: Shell.push(getNode()); samer@0: scale=new VDouble("scale",1.0,0); samer@0: Shell.pop(); samer@0: } samer@0: samer@0: public DataLine getLine() { return line; } samer@0: public boolean isOpen() { return line.isOpen(); } samer@0: public void setBufferSize(int b) { bufsize=b; } samer@0: samer@0: /** samer@0: * Returns the object used to store the scale factor for conversion from samer@0: * doubles/floats to shorts/bytes. This is multiplied by 128 for conversion samer@0: * to 8 bit audio, or 32768 for conversion to 16 bit audio. samer@0: */ samer@0: public VDouble getScale() { return scale; } samer@0: samer@0: public void dispose() { scale.dispose(); super.dispose(); } samer@0: samer@0: /** Open the line using either the current format or the line's default format if samer@0: * none has been set. samer@0: */ samer@0: public void openImpl() throws Exception { samer@0: if (bufsize==0) line.open(fmt); else line.open(fmt,bufsize); samer@0: } samer@0: samer@0: public void closeImpl() throws Exception { line.close(); } samer@0: samer@0: /** Commands are :"set scale". */ samer@0: public void getCommands(Registry r) { samer@0: r.add("set scale").group(); samer@0: super.getCommands(r); samer@0: } samer@0: samer@0: public void execute(String cmd, Environment env) throws Exception { samer@0: if (cmd.equals("set scale")) { env.datum().get(scale); } samer@0: else super.execute(cmd,env); samer@0: } samer@0: samer@0: public Task writer(final double dbuf[], final int off, final int len) { samer@0: return new Writer(2*len) { samer@0: public void write(double dbuf[], int off, int len) throws Exception { samer@0: Util.doubleToShort(dbuf,buf,off,len,scale.value); samer@0: super.write(2*len); samer@0: } samer@0: public void run() throws Exception { samer@0: super.run(); Util.doubleToShort(dbuf,buf,off,len,scale.value); samer@0: } samer@0: }; samer@0: } samer@0: samer@0: public Task writer(final float dbuf[], final int off, final int len) { samer@0: return new Writer(2*len) { samer@0: public void write(float dbuf[], int off, int len) throws Exception { samer@0: Util.floatToShort(dbuf,buf,off,len,(float)scale.value); samer@0: super.write(2*len); samer@0: } samer@0: public void run() throws Exception { samer@0: super.run(); Util.floatToShort(dbuf,buf,off,len,(float)scale.value); samer@0: } samer@0: }; samer@0: } samer@0: samer@0: protected class Writer implements Task { samer@0: byte buf[]; samer@0: int size; samer@0: samer@0: public Writer(int bufsize) { size=bufsize; buf=new byte[size]; } samer@0: samer@0: public void starting() { start(); } samer@0: public void stopping() { stop(); } samer@0: public void dispose() {} samer@0: public void run() throws Exception { samer@0: if (line.write(buf,0,size)<=0) throw new EOFException(); samer@0: changed(); samer@0: } samer@0: samer@0: public void write(int size) throws Exception { samer@0: if (line.write(buf,0,size)<=0) throw new EOFException(); samer@0: changed(); samer@0: } samer@0: } samer@0: samer@0: public static DataLine.Info lineInfo(AudioFormat fmt) { samer@0: return new DataLine.Info( SourceDataLine.class, fmt); samer@0: } samer@0: samer@0: public static DataLine.Info lineInfo(AudioFormat fmt, int bufsize) { samer@0: return new DataLine.Info( SourceDataLine.class, fmt, bufsize); samer@0: } samer@0: } samer@0: