view src/samer/audio/LineSink.java @ 8:5e3cbbf173aa tip

Reorganise some more
author samer
date Fri, 05 Apr 2019 22:41:58 +0100
parents bf79fb79ee13
children
line wrap: on
line source
/*
 *	LineSink.java
 *
 *	Copyright (c) 2000, Samer Abdallah, King's College London.
 *	All rights reserved.
 *
 *	This software is provided AS iS and WITHOUT ANY WARRANTY;
 *	without even the implied warranty of MERCHANTABILITY or
 *	FITNESS FOR A PARTICULAR PURPOSE.
 */

package samer.audio;
import  samer.core.*;
import  samer.core.types.*;
import  samer.tools.*;
import  java.io.*;
import  javax.sound.sampled.*;

/**
	An AudioSink that sends samples to a Java Sound SourceDataLine.
	Audio format can be determined in several ways (see below).
	<p> Object is a Viewable, and is called "lineout".
	Reads property "scale" from current environment, but scale
	can be adjusted afterwards.
	@see samer.audio.AudioSink
*/

public class LineSink extends VLine implements AudioSink
{
	private SourceDataLine	line;
	private AudioFormat	   fmt;
	private int             bufsize=0;
	private VDouble			scale;

	/** Create LineSink reading from given TargetDataLine */
	public LineSink(SourceDataLine l, AudioFormat f) throws Exception {
		super("lineout"); 
		line=l; fmt=f;
		Shell.push(getNode());
		scale=new VDouble("scale",1.0,0);
		Shell.pop();
	}

	public DataLine getLine() { return line; }
	public boolean isOpen() { return line.isOpen(); }
	public void setBufferSize(int b) { bufsize=b; }

	/**
	 * Returns the object used to store the scale factor for conversion from
	 * doubles/floats to shorts/bytes. This is multiplied by 128 for conversion
	 * to 8 bit audio, or 32768 for conversion to 16 bit audio.
	*/
	public VDouble getScale() { return scale; }

	public void dispose() { scale.dispose(); super.dispose(); }

	/** Open the line using either the current format or the line's default format if
	*	none has been set.
	*/
	public void openImpl() throws Exception {
		if (bufsize==0) line.open(fmt); else line.open(fmt,bufsize);
	}

	public void closeImpl() throws Exception { line.close(); }

	/** Commands are :"set scale". */
	public void getCommands(Registry r) {
		r.add("set scale").group();
		super.getCommands(r);
	}

	public void execute(String cmd, Environment env) throws Exception {
		if (cmd.equals("set scale")) { env.datum().get(scale); }
		else super.execute(cmd,env);
	}

	public Task writer(final double dbuf[], final int off, final int len) {
		return new Writer(2*len) {
			public void write(double dbuf[], int off, int len) throws Exception {
				Util.doubleToShort(dbuf,buf,off,len,scale.value);
				super.write(2*len);
			}
			public void run() throws Exception {
				super.run();	Util.doubleToShort(dbuf,buf,off,len,scale.value);
			}
		};
	}

	public Task writer(final float dbuf[], final int off, final int len) {
		return new Writer(2*len) {
			public void write(float dbuf[], int off, int len) throws Exception {
				Util.floatToShort(dbuf,buf,off,len,(float)scale.value);
				super.write(2*len);
			}
			public void run() throws Exception {
				super.run();	Util.floatToShort(dbuf,buf,off,len,(float)scale.value);
			}
		};
	}

	protected class Writer implements Task {
		byte buf[];
		int		size;

		public Writer(int bufsize) { size=bufsize; buf=new byte[size]; }

		public void starting() { start(); }
		public void stopping() { stop(); }
		public void dispose() {}
		public void run() throws Exception {
			if (line.write(buf,0,size)<=0) throw new EOFException();
			changed();
		}

		public void write(int size) throws Exception {
			if (line.write(buf,0,size)<=0) throw new EOFException();
			changed();
		}
	}

	public static DataLine.Info lineInfo(AudioFormat fmt) {
		return new DataLine.Info( SourceDataLine.class, fmt); 
	}

	public static DataLine.Info lineInfo(AudioFormat fmt, int bufsize) {
		return new DataLine.Info( SourceDataLine.class, fmt, bufsize); 
	}
}