samer@0
|
1 /*
|
samer@0
|
2 * FileSink.java
|
samer@0
|
3 *
|
samer@0
|
4 * Copyright (c) 2000, Samer Abdallah, King's College London.
|
samer@0
|
5 * All rights reserved.
|
samer@0
|
6 *
|
samer@0
|
7 * This software is provided AS iS and WITHOUT ANY WARRANTY;
|
samer@0
|
8 * without even the implied warranty of MERCHANTABILITY or
|
samer@0
|
9 * FITNESS FOR A PARTICULAR PURPOSE.
|
samer@0
|
10 */
|
samer@0
|
11
|
samer@0
|
12 package samer.audio;
|
samer@0
|
13
|
samer@0
|
14 import samer.core.*;
|
samer@0
|
15 import samer.core.types.*;
|
samer@0
|
16 import samer.core.util.*;
|
samer@0
|
17 import samer.tools.*;
|
samer@0
|
18 import javax.sound.sampled.*;
|
samer@0
|
19 import java.io.*;
|
samer@0
|
20
|
samer@0
|
21 import org.tritonus.share.sampled.AudioSystemShadow;
|
samer@0
|
22 import org.tritonus.share.sampled.file.AudioOutputStream;
|
samer@0
|
23
|
samer@0
|
24 /**
|
samer@0
|
25 An AudioSink that writes to a wav file.
|
samer@0
|
26 Viewable name: "wavewriter"<br>
|
samer@0
|
27 Properties read from current environment:
|
samer@0
|
28 <dl>
|
samer@0
|
29 <dt>filesink.current
|
samer@0
|
30 <dd>Current file (String)
|
samer@0
|
31 <dt>filesink.scale
|
samer@0
|
32 <dd>scale factor for converting floats/doubles (Double)
|
samer@0
|
33 </dl>
|
samer@0
|
34 */
|
samer@0
|
35
|
samer@0
|
36 public class FileSink extends Viewable implements AudioSink, Agent
|
samer@0
|
37 {
|
samer@0
|
38 VFile file;
|
samer@0
|
39 AudioOutputStream out=null;
|
samer@0
|
40 AudioFormat format;
|
samer@0
|
41 VDouble scale;
|
samer@0
|
42
|
samer@0
|
43 public FileSink(String filename, AudioFormat fmt) throws Exception {
|
samer@0
|
44 this(fmt); file.setFile(new File(filename));
|
samer@0
|
45 }
|
samer@0
|
46
|
samer@0
|
47 public FileSink(AudioFormat fmt)
|
samer@0
|
48 {
|
samer@0
|
49 super("filessink");
|
samer@0
|
50
|
samer@0
|
51 Shell.push(node);
|
samer@0
|
52 file=new VFile("file","",0);
|
samer@0
|
53 scale=new VDouble("scale",1.0,0);
|
samer@0
|
54 Shell.push("audio");
|
samer@0
|
55 format=fmt;
|
samer@0
|
56 Shell.pop();
|
samer@0
|
57 Shell.pop();
|
samer@0
|
58
|
samer@0
|
59 setAgent(this);
|
samer@0
|
60 Shell.registerViewable(this);
|
samer@0
|
61 }
|
samer@0
|
62
|
samer@0
|
63 public void dispose() {
|
samer@0
|
64 close();
|
samer@0
|
65 Shell.deregisterViewable(this);
|
samer@0
|
66 file.dispose();
|
samer@0
|
67 }
|
samer@0
|
68
|
samer@0
|
69 public VDouble getScale() { return scale; }
|
samer@0
|
70 public void setFormat(AudioFormat f) { format=f; }
|
samer@0
|
71
|
samer@0
|
72 public boolean isOpen() { return out!=null; }
|
samer@0
|
73 public void open() throws Exception { open(file.getFile()); }
|
samer@0
|
74 public synchronized void open(File file) throws Exception
|
samer@0
|
75 {
|
samer@0
|
76 Shell.trace("wave writer opening "+file+" as "+format);
|
samer@0
|
77
|
samer@0
|
78 out=AudioSystemShadow.getAudioOutputStream(
|
samer@0
|
79 AudioFileFormat.Type.WAVE,format,AudioSystem.NOT_SPECIFIED,
|
samer@0
|
80 new BufferedOutputStream(
|
samer@0
|
81 new FileOutputStream(file)));
|
samer@0
|
82 this.file.setFile(file);
|
samer@0
|
83 }
|
samer@0
|
84
|
samer@0
|
85 public synchronized void close() {
|
samer@0
|
86 try { if (out!=null) out.close(); out=null; }
|
samer@0
|
87 catch (IOException ex) { Shell.trace("*** Error closing: "+ex); }
|
samer@0
|
88 }
|
samer@0
|
89
|
samer@0
|
90 public Task writer(final double [] dbuf, final int off, final int len) {
|
samer@0
|
91 return new AnonymousTask() {
|
samer@0
|
92 byte [] bbuf = new byte[2*len];
|
samer@0
|
93
|
samer@0
|
94 public void write(double dbuf[], int off, int len) throws Exception {
|
samer@0
|
95 synchronized (FileSink.this) {
|
samer@0
|
96 Util.doubleToShort(dbuf,bbuf,off,len,scale.value);
|
samer@0
|
97 writeBytes(bbuf, 2*len);
|
samer@0
|
98 }
|
samer@0
|
99 }
|
samer@0
|
100 public void run() throws Exception {
|
samer@0
|
101 synchronized (FileSink.this) {
|
samer@0
|
102 Util.doubleToShort(dbuf,bbuf,off,len,scale.value);
|
samer@0
|
103 writeBytes(bbuf, bbuf.length);
|
samer@0
|
104 }
|
samer@0
|
105 }
|
samer@0
|
106 };
|
samer@0
|
107 }
|
samer@0
|
108
|
samer@0
|
109 public Task writer(final float [] dbuf, final int off, final int len) {
|
samer@0
|
110 return new AnonymousTask() {
|
samer@0
|
111 byte [] bbuf = new byte[2*len];
|
samer@0
|
112
|
samer@0
|
113 public void write(float dbuf[], int off, int len) throws Exception {
|
samer@0
|
114 synchronized (FileSink.this) {
|
samer@0
|
115 Util.floatToShort(dbuf,bbuf,off,len,(float)scale.value);
|
samer@0
|
116 writeBytes(bbuf, 2*len);
|
samer@0
|
117 }
|
samer@0
|
118 }
|
samer@0
|
119 public void run() throws Exception {
|
samer@0
|
120 synchronized (FileSink.this) {
|
samer@0
|
121 Util.floatToShort(dbuf,bbuf,off,len,(float)scale.value);
|
samer@0
|
122 writeBytes(bbuf, bbuf.length);
|
samer@0
|
123 }
|
samer@0
|
124 }
|
samer@0
|
125 };
|
samer@0
|
126 }
|
samer@0
|
127
|
samer@0
|
128 private void writeBytes(byte [] buf,int len) throws Exception {
|
samer@0
|
129 int count = out.write(buf, 0, len);
|
samer@0
|
130 for (int n=count; n<len; n+=count) {
|
samer@0
|
131 count = out.write(buf, n, len - n);
|
samer@0
|
132 if (count<=0) throw new Exception("Write failed");
|
samer@0
|
133 }
|
samer@0
|
134 }
|
samer@0
|
135
|
samer@0
|
136 public void getCommands(Agent.Registry r) { r.add("open").add("close").add("set scale"); }
|
samer@0
|
137 public void execute(String cmd, Environment env) throws Exception {
|
samer@0
|
138 if (cmd.equals("open")) {close(); open(); }
|
samer@0
|
139 else if (cmd.equals("close")) close();
|
samer@0
|
140 else if (cmd.equals("set scale")) { env.datum().get(scale); }
|
samer@0
|
141 }
|
samer@0
|
142
|
samer@0
|
143 // Viewable
|
samer@0
|
144 public Viewer getViewer() {
|
samer@0
|
145 DefaultViewer vwr=new DefaultViewer(this);
|
samer@0
|
146 vwr.add(file);
|
samer@0
|
147 vwr.add(Shell.createButtonsFor(this));
|
samer@0
|
148 return vwr;
|
samer@0
|
149 }
|
samer@0
|
150 }
|