view src/samer/audio/FileSink.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
/*
 *	FileSink.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.core.util.*;
import  samer.tools.*;
import  javax.sound.sampled.*;
import  java.io.*;

import  org.tritonus.share.sampled.AudioSystemShadow;
import  org.tritonus.share.sampled.file.AudioOutputStream;

/**
	An AudioSink that writes to a wav file.
	Viewable name: "wavewriter"<br>
	Properties read from current environment:
	<dl>
	<dt>filesink.current
		<dd>Current file (String)
	<dt>filesink.scale
		<dd>scale factor for converting floats/doubles (Double)
	</dl>
*/

public class FileSink extends Viewable implements AudioSink, Agent
{
	VFile					file;
	AudioOutputStream	out=null;
	AudioFormat			format;
	VDouble				scale;

	public FileSink(String filename, AudioFormat fmt) throws Exception {
		this(fmt); file.setFile(new File(filename)); 
	}

	public FileSink(AudioFormat fmt)
	{
		super("filessink");

		Shell.push(node);
		file=new VFile("file","",0);
		scale=new VDouble("scale",1.0,0);
		Shell.push("audio");
		format=fmt;
		Shell.pop();
		Shell.pop();

		setAgent(this);
		Shell.registerViewable(this);
	}

	public void dispose() {
		close();
		Shell.deregisterViewable(this);
		file.dispose();
	}

	public VDouble getScale() { return scale; }
	public void setFormat(AudioFormat f) { format=f; }

	public boolean isOpen() { return out!=null; }
	public void open() throws Exception { open(file.getFile()); }
	public synchronized  void open(File file) throws Exception
	{
		Shell.trace("wave writer opening "+file+" as "+format);

		out=AudioSystemShadow.getAudioOutputStream(
			AudioFileFormat.Type.WAVE,format,AudioSystem.NOT_SPECIFIED,
				new BufferedOutputStream(
					new FileOutputStream(file)));
		this.file.setFile(file);
	}

	public synchronized void close() {
		try { if (out!=null) out.close(); out=null; }
		catch (IOException ex) { Shell.trace("*** Error closing: "+ex); }
	}

	public Task writer(final double [] dbuf, final int off, final int len) {
		return new AnonymousTask() {
			byte [] bbuf = new byte[2*len];

			public void write(double dbuf[], int off, int len) throws Exception {
				synchronized (FileSink.this) {
					Util.doubleToShort(dbuf,bbuf,off,len,scale.value);
					writeBytes(bbuf, 2*len);
				}
			}
			public void run() throws Exception {
				synchronized (FileSink.this) {
					Util.doubleToShort(dbuf,bbuf,off,len,scale.value);
					writeBytes(bbuf, bbuf.length);
				}
			}
		};
	}

	public Task writer(final float [] dbuf, final int off, final int len) {
		return new AnonymousTask() {
			byte [] bbuf = new byte[2*len];

			public void write(float dbuf[], int off, int len) throws Exception {
				synchronized (FileSink.this) {
					Util.floatToShort(dbuf,bbuf,off,len,(float)scale.value);
					writeBytes(bbuf, 2*len);
				}
			}
			public void run() throws Exception {
				synchronized (FileSink.this) {
					Util.floatToShort(dbuf,bbuf,off,len,(float)scale.value);
					writeBytes(bbuf, bbuf.length);
				}
			}
		};
	}

	private void writeBytes(byte [] buf,int len) throws Exception {
		int count = out.write(buf, 0, len);
		for (int n=count; n<len; n+=count) {
			count = out.write(buf, n, len - n);
			if (count<=0) throw new Exception("Write failed");
		}
	}

	public void getCommands(Agent.Registry r) { r.add("open").add("close").add("set scale"); }
	public void execute(String cmd, Environment env) throws Exception {
		if (cmd.equals("open")) {close(); open(); }
		else if (cmd.equals("close")) close();
		else if (cmd.equals("set scale")) { env.datum().get(scale); }
	}

	// Viewable
	public Viewer getViewer() {
		DefaultViewer vwr=new DefaultViewer(this);
		vwr.add(file);
		vwr.add(Shell.createButtonsFor(this));
		return vwr;
	}
}